Jump to content

LISP for marks Centroids of closed polylines


Recommended Posts

Guest Fantomas
Posted

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)

  • 6 years later...
Posted (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 by PSAPmapR
To add code tags to post so the script would appear properly.
Posted

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.

Posted

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

Posted

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)
)

Posted

LoL, nicely done. That centroid from region was a slick idea that guy posted the other day. Never would have thought of it myself.

Posted
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! :shock: My old code makes me cringe *shiver*

Posted (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 by VVA
Add elevation ( Z ) See comment ;;;VVA 2015-03-29
Posted

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.

  • 2 weeks later...
Posted

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

Posted

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.]

  • 4 years later...
Posted (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

 

PvrsFlW.png

Edited by Miller87
Posted

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? :unsure:

Posted

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? :unsure:

Modify #9 Try again

  • 3 years later...
Posted

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!

Posted

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.

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...