Guest Fantomas Posted December 4, 2004 Posted December 4, 2004 To find Centroid of the closed polyline it is necessary to transform it in Region. This program finds Centroids the several closed polylines and marks their points. (defun c:polycen (/ polySet polyList Model newPl obArr newReg newPt) (princ "\n*** Select closed polylines *** ") (if (setq polySet(ssget '((0 . "LWPOLYLINE")))) (progn (setq polyList(mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr(ssnamex polySet)))) Model(vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))) ); end setq (foreach p polyList (if(= :vlax-true(vla-get-Closed p)) (progn (setq newPl(vla-copy p) obArr(vlax-make-safearray vlax-vbObject '(0 . 0)) ); end setq (vlax-safearray-put-element obArr 0 newPl) (setq newReg(car(vlax-safearray->list (vlax-variant-value (vla-AddRegion Model obArr)))) newPt(vlax-3d-point (append (vlax-safearray->list (vlax-variant-value (vla-get-Centroid newReg)))(list 0.0))) ); end setq (vla-AddPoint Model newPt) (vla-delete newPl)(vla-delete newReg) ); end progn ); end if ); end foreach ); end progn (princ "\n*** Notning closed polylines selected! *** ") ); end if (princ) ); end of c:polycen (vl-load-com) Quote
PSAPmapR Posted March 4, 2011 Posted March 4, 2011 (edited) This is pretty much the solution I was looking for. I simply needed to generate a simple (ie visual or aesthetic) centroid or "point" at the relative centroid of closed polylines or regions that represent building foot prints. Once the points are created and I have imported the drawing into my GIS, I could then assign 9-1-1 numbers to these points. As the above post, when I found it here on CADTutor, had been corrupted with HTML ASCII codes for various characters, I cleaned it up a bit, and am posting the corrected syntax here. Thanks for the help. (defun c:polycen (/ polySet polyList Model newPl obArr newReg newPt) (princ "\n*** Select closed polylines *** ") (if (setq polySet(ssget '((0 . "LWPOLYLINE")))) (progn (setq polyList(mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr(ssnamex polySet)))) Model(vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))) ); end setq (foreach p polyList (if(= :vlax-true(vla-get-Closed p)) (progn (setq newPl(vla-copy p) obArr(vlax-make-safearray vlax-vbObject '(0 . 0)) ); end setq (vlax-safearray-put-element obArr 0 newPl) (setq newReg(car(vlax-safearray->list (vlax-variant-value (vla-AddRegion Model obArr)))) newPt(vlax-3d-point (append (vlax-safearray->list (vlax-variant-value (vla-get-Centroid newReg)))(list 0.0))) ); end setq (vla-AddPoint Model newPt) (vla-delete newPl)(vla-delete newReg) ); end progn ); end if ); end foreach ); end progn (princ "\n*** Nothing closed polylines selected! *** ") ); end if (princ) ); end of c:polycen (vl-load-com) Edited March 4, 2011 by PSAPmapR To add code tags to post so the script would appear properly. Quote
BIGAL Posted March 4, 2011 Posted March 4, 2011 Rather than making it a region you could go to first principles and just pull all the ployline vertices out and calculate the centroid for pline closed or not. The centroid is a simple formula but I would look on net for it, can't remember it. Quote
BIGAL Posted March 4, 2011 Posted March 4, 2011 Found this code which explains a bit better the use of x,y points could be made into vba or lisp Attribute VB_Name = "Module1" 'Author: Rodrigo Alves Pons 'email: rodpons@ig.com.br 'webpage: www.geocities.com/rodrigo_alves_pons/ 'Version: 2007-01-05 'functions to calculate the area and centroid of a polygon, 'according to the algorithm defined at: 'http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/ Option Explicit Type tPoint X As Double Y As Double End Type Function PolygonArea(N As Integer, Points() As tPoint) As Double Dim i As Integer, j As Integer Dim area As Double area = 0 For i = 0 To N - 1 j = (i + 1) Mod N area = area + Points(i).X * Points(j).Y - Points(j).X * Points(i).Y Next i PolygonArea = area / 2 End Function Function PolygonCentroid(N As Integer, Points() As tPoint, area As Double) As tPoint Dim i As Integer, j As Integer Dim C As tPoint Dim P As Double C.X = 0 C.Y = 0 For i = 0 To N - 1 j = (i + 1) Mod N P = Points(i).X * Points(j).Y - Points(j).X * Points(i).Y C.X = C.X + (Points(i).X + Points(j).X) * P C.Y = C.Y + (Points(i).Y + Points(j).Y) * P Next i C.X = C.X / (6 * area) C.Y = C.Y / (6 * area) PolygonCentroid = C End Function Quote
Lee Mac Posted March 5, 2011 Posted March 5, 2011 Another way to code the PolyCen program: (defun c:pc ( / acdoc acspc acsel reg ) (vl-load-com) ;; © Lee Mac 2011 (setq acdoc (vla-get-ActiveDocument (vlax-get-acad-object)) acspc (vlax-get-property acdoc (if (= 1 (getvar 'CVPORT)) 'Paperspace 'Modelspace)) ) (if (ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1))) (progn (vlax-for obj (setq acsel (vla-get-ActiveSelectionSet acdoc)) (vlax-invoke acspc 'addpoint (trans (vlax-get (setq reg (car (vlax-invoke acspc 'addregion (list obj)))) 'Centroid) 1 0) ) (vla-delete reg) ) (vla-delete acsel) ) ) (princ) ) Quote
alanjt Posted March 5, 2011 Posted March 5, 2011 LoL, nicely done. That centroid from region was a slick idea that guy posted the other day. Never would have thought of it myself. Quote
Lee Mac Posted March 5, 2011 Posted March 5, 2011 LoL, nicely done. That centroid from region was a slick idea that guy posted the other day. Never would have thought of it myself. I haven't used it in almost two years! My old code makes me cringe *shiver* Quote
alanjt Posted March 5, 2011 Posted March 5, 2011 I haven't used it in almost two years! My old code makes me cringe *shiver*Well, touch you.:wink: Quote
VVA Posted March 6, 2011 Posted March 6, 2011 (edited) Without the need for the region. Only geometry. Use Evgeniy Elpanov function (defun c:pc ( / acdoc acspc acsel pl bl ) (vl-load-com) (setq acdoc (vla-get-ActiveDocument (vlax-get-acad-object)) acspc (vlax-get-property acdoc (if (= 1 (getvar 'CVPORT)) 'Paperspace 'Modelspace)) ) (if (ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1))) (progn (vlax-for obj (setq acsel (vla-get-ActiveSelectionSet acdoc)) (vlax-invoke acspc 'addpoint (trans (progn (setq pl nil bl nil) (foreach a (reverse (entget (vlax-vla-object->ename obj))) (cond ((= (car a) 10) (setq pl (cons (cdr a) pl))) ((= (car a) 42) (setq bl (cons (cdr a) bl))) ); _ cond ); _ foreach ;;;(eea-centroid-solid-lw pl bl) [color="red"] (reverse(cons (vla-get-elevation obj)(reverse (eea-centroid-solid-lw pl bl))));;;VVA MOD 2015-03-29[/color] ) 1 0) ) ) (vla-delete acsel) ) ) (princ) ) (defun eea-centroid-solid-lw (pl bl / A1) ;| *********************************************************************** by ElpanovEvgeniy Library function, Centroids (center of masses) of region, inside [polilinii], which has arched segments. pl - list of the apexes of [polilinii] (code 10) bl - list of tangents fourth of angle of the arched segments of [polilinii] (code 42) Date of the creation 2000 - 2005 Last editorial staff 08.06.2009 URL http://elpanov.com/index.php?id=46 ********************************************************************* Library of function. Centroid (the of center of of weights) of region, inside of a of polyline, having of arc of segments pl - list of point bl - list of bulge Date of of creation 2000 - 2005 years. Last of edit 08.06.2009 ********************************************************************** (setq e (car (entsel "\n Select LWPOLYLINE ")) pl nil bl nil ) ;_ setq (foreach a (reverse (entget e)) (cond ((= (car a) 10) (setq pl (cons (cdr a) pl))) ((= (car a) 42) (setq bl (cons (cdr a) bl))) ) ;_ cond ) ;_ foreach (eea-centroid-solid-lw pl bl) ***************************************************************** (defun c:test (/ e bl pl) (setq e (car (entsel "\n Select LWPOLYLINE "))) (foreach a (reverse (entget e)) (cond ((= (car a) 10) (setq pl (cons (cdr a) pl))) ((= (car a) 42) (setq bl (cons (cdr a) bl))) ) ;_ cond ) ;_ foreach (entmakex (list '(0 . "point") '(62 . 1) (cons 10 (eea-centroid-solid-lw pl bl)) (assoc 210 (entget e)) ) ;_ list ) ;_ entmakex ) ;_ defun ******************************************************************* |; (setq a1 0) (mapcar (function /) (apply (function mapcar) (cons (function +) (mapcar (function (lambda (p1 p2 b / A BB C I S) (setq i (/ (- (* (car p1) (cadr p2)) (* (car p2) (cadr p1))) 2) a1 (+ i a1) i (/ i 3) ) ;_ setq (if (zerop b) (mapcar (function (lambda (a b) (* (+ a b) i))) p1 p2) (progn (setq c (distance p1 p2) bb (* b b) a (/ (* c c (- (* (atan b) (1+ bb) (1+ bb)) (* b (- 1 bb)))) (* 8 bb)) a1 (+ a a1) s (/ (- (* b c c) (* 3 a (- 1 bb))) (* 12 a b)) ) ;_ setq (mapcar (function (lambda (a b c d) (+ (* (+ a b) i) (* d (+ (/ (+ a b) 2) c))))) p1 p2 (list (* (- (cadr p2) (cadr p1)) s) (* (- (car p2) (car p1)) -1 s)) (list a a) ) ;_ mapcar ) ;_ progn ) ;_ if ) ;_ lambda ) ;_ function (cons (last pl) pl) pl (cons (last bl) bl) ) ;_ mapcar ) ;_ cons ) ;_ apply (list a1 a1) ) ;_ mapcar ) ;_ defun Edited March 29, 2015 by VVA Add elevation ( Z ) See comment ;;;VVA 2015-03-29 Quote
gile Posted March 6, 2011 Posted March 6, 2011 Hi, You can find here the PT-CEN command which make a point (nodal) on a lwpolyline centroid (even containing arcs). It uses a geometrical way (as the upper one posted by VVA) and runs about 3 times faster than the Region route. Quote
kirby Posted March 18, 2011 Posted March 18, 2011 Hi This is slightly off topic... Has anyone find a satisfactory way of generating a 'soft centroid', which is a point inside a closed polygon when the actual centroid is located outside of the polygon boundary (say the polygon looks like a letter 'L' or 'O'). This could be used for map annotation (say inserting a block with polygon attributes at the soft centroid; I would use this for inserting a block with subcatchment properties within a polygon representing a drainage subcatchment boundary when building a hydrologic model of a drainage area). I've though about a few ways of doing this, but havn't tried to code it yet. Methods could include: 1. Randomly selecting two vertices, drawing a line segment between them, and checking that the midpoint of the line segment lies within the polygon. 2. Partitioning/decomposing the polygon into smaller pieces (possibly by ear cutting - see link), then checking if the centroid of a sub-polygons lies within the polygon. The most satisfactory 'soft centroid' would be the one closest to the actual centroid. Ear cutting description http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/cutting_ears.html Comments or suggestions would be welcome. Regards, Kirby Quote
amarcon Posted March 21, 2011 Posted March 21, 2011 A challenge for the classic coders here. My dilemma is that I need to find the centroid of polylines which often have holes. (ie Concrete panel outline with windows and doors.) An approach I thought of, but I am not a very good coder, is to do a 'dummy hatch' to get the area and then find the centroid of it. This could be done with one click! ie click in internal space. [Currently I have custom commands to do this. I select the outer pline and then the pline openings; this creates first region and subtracts the openings and then determines centroid from resultant region.] Quote
Miller87 Posted March 26, 2015 Posted March 26, 2015 (edited) I have some trouble with your script: The script which you write works perfectly in 2D plane, when the polyline belongs to default XY plane with Z = 0; I need a modified version of the lisp that inserts centroid point in 3D space and even when the LWpolyline has a Z coordinate not equal ZERO. Is that possible to do this? Some tips? Thanks for your attention Edited March 26, 2015 by Miller87 Quote
Miller87 Posted March 26, 2015 Posted March 26, 2015 Nobody has an idea? I'm stuck with my project. Maybe if it's possible to read the Z from the selection LWpolyline (with entget?), and insert the coordinate in the point? Quote
VVA Posted March 29, 2015 Posted March 29, 2015 I need a modified version of the lisp that inserts centroid point in 3D space and even when the LWpolyline has a Z coordinate not equal ZERO. Is that possible to do this? Maybe if it's possible to read the Z from the selection LWpolyline (with entget?), and insert the coordinate in the point? Modify #9 Try again Quote
Ante Posted December 11, 2018 Posted December 11, 2018 Hi all! Can anyone please tell me how to correctly use this script. I have my drawing, and than I type in command "script" after that I select the script whic I have copyed to notepad and than svae it as scr file. After the script is loaded program asks for something, but I don't know what it is. It basicalay writes the last line of code - "(vl-load-com). "I'm using script post by Guest Fantomas, and I'm using AutoCad 2019. I could realy use some help, so if anyone can tell me what to do after this step I would be grateful! Quote
Jef! Posted December 12, 2018 Posted December 12, 2018 Ante, This file is not a script, it is a lisp file. You need to save it with .lsp extension. To make a single use, you can then drag and drop the .lsp file in your cad session and launch the command defined with the name after the defun part, which is polycen. Since the thread start by that lisp function and it has been reworked, I would use the last one posted by vva. Cheers. Quote
danglar Posted December 13, 2018 Posted December 13, 2018 ..probably this attempt can be helpful (see attached lisp) Draw Centroid Point and Mass Properties - DCM.lsp Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.