Obtaining the centre of a closed area

Discussion in 'AutoCAD' started by Marcel Janmaat, Apr 15, 2004.

  1. Has anyone got a good suggestion for me on how to obtain the center of a
    closed area by picking a point within it?
    I was thinking of using bpoly and then use the points of the polyline to
    determine the centre.

    MJ
     
    Marcel Janmaat, Apr 15, 2004
    #1
  2. Marcel Janmaat

    zeha Guest

    Marcel,

    i have seen a function (midpoint) see below
    this give's the midpoint from the bounding box

    but i think thats not where your looking for


    (defun getmidpoint (object / p1 p2)
    (vla-getboundingbox
    object
    'p1
    'p2
    )
    (setq p1 (vlax-safearray->list p1)
    p2 (vlax-safearray->list p2)
    )
    (mapcar
    '*
    '(0.5 0.5 0.5)
    (mapcar '+ p1 p2)
    )
    )
    (defun c:lineMid ()
    (if (setq enam (entsel))
    (command ".line" "none" (getmidpoint (vlax-ename->vla-object(car enam))))
    )
    )
     
    zeha, Apr 15, 2004
    #2
  3. Marcel Janmaat

    TCEBob Guest

    Definition of "center" is variable. There is always a centroid, of
    course, which may or may not lie within the figure. Then, you might
    define it as "that point within the figure which is most distant from
    all points on the figure." Whereupon we have a neat problem in
    differentials, I believe. It would be helpful to know what you need it
    for.

    rs
     
    TCEBob, Apr 15, 2004
    #3
  4. You can only see centroid of a region !

    Danie (A french user !)
     
    OLIVES Daniel, Apr 15, 2004
    #4
  5. Marcel Janmaat

    BillZ Guest

    This will work on simple point lists.

    ;3/13/03
    ;Joe Burke
    ;program to get point inside
    ;pline polygon.
    (defun AveragePts (ptlist)
    (if (null (caddr (car ptlist))) ;test first point for 2D point
    (setq ptlist (mapcar '(lambda (x) (append x '(0.0))) ptlist))
    )
    (mapcar '(lambda (ord)(/ ord (length ptlist) 1.0))
    (list
    (apply '+ (mapcar '(lambda (pt) (car pt)) ptlist))
    (apply '+ (mapcar '(lambda (pt) (cadr pt)) ptlist))
    (apply '+ (mapcar '(lambda (pt) (caddr pt)) ptlist))
    )
    )
    )

    HTH

    Bill
     
    BillZ, Apr 15, 2004
    #5
  6. Marcel Janmaat

    bob.at Guest

    Hello Marcel

    Sory, I cant help you very much but want to tell what we did to solve this problem.
    At my last job we did 3 implementations:

    1.) We first started with bhatch function (i think it is similar to bpoly), taking the points of the resulting hatch. This function did its work in many cases, but sometimes it failed, because it is dependent from screen resolution and from the current view. i.g. it did not recognize narrow gaps between lines; dependent from the actual viewing size. And it is very slow for large data sets for example all land parcels of a township.

    2.) Next step we uses Autodesk Map polygon topologies to solve the problem. This worked better and faster but had also problems with narrow gaps. And in Map 4 there were some memory problems when using Autodesk Map topolgies a couple of numbers - Map crashed with unhadled exceptions. Additionally the user of our programs had to have a Map license and not only an AutoCAD.

    3.) Third step (that was already after I left the company) they made an own "modified delauny algorithm" which starts with the desired lines and calculates closed polygons, regardless of cutting lines or not. This is now working very fine.

    Each of the 3 solutions took a great amount of resources (espacially var. 1 and 3) - some weeks of analysing and programming. And all 3 were realized in arx and c++ and not in Lisp.

    Of course I will not discourage you in doing it. Maybe a simple bhatch is sufficient for your purpose.

    bob.at

    bob.at
     
    bob.at, Apr 15, 2004
    #6
  7. I did some experimenting. If you pick within the area in BPOLY, and then
    turn the resulting Polyline into a Region, you can get its centroid from the
    MASSPROP command, but it looks as though it calculates the centroid only in
    response to the command, and doesn't store it anywhere. The coordinates of
    the centroid don't seem to be on the association list if you do (entget (car
    (entsel))) on the region. (Try that, for the weirdest-looking association
    list you ever saw!) And you can't OSNAP to it. So whether you can access
    that information via AutoLisp or something is beyond me. The only prospect
    I could think of is that MASSPROP lets you put its results into a text file,
    and you might find a way of digging the centroid's coordinates out of that,
    somehow.

    If you pick within the area in BHATCH, then select the hatch pattern, you
    get a grip point at what turns out to be the center of the rectangular
    bounding box of the hatch (which is not the same as the centroid of the
    Region, except in limited symmetrical circumstances). But again, it doesn't
    seem to keep that location stored anywhere. It functions sort of like the
    Insertion point in that, if that location is contained within a Stretch
    crossing-window, the hatch will move for the Stretch command, and you can
    move it by grabbing that grip. But it's NOT the Insertion point -- you
    can't OSNAP to it, for example. It doesn't appear in the Properties, nor
    does it seem to be in the association list. So whether you can access that
    information via AutoLisp or VBA or VLA or whatever is another good question.

    Kent Cooper, AIA
     
    Kent Cooper, AIA, Apr 16, 2004
    #7
  8. Marcel Janmaat

    devitg Guest

    Hi, I do not know how to use it , but there is a VBA function that handle it , maybe it can help .
    Look at the help for CENTROID
    Hope it help

    Sub Example_Centroid()
    ' This example creates a box in model space.
    ' It then returns the Centroid for that box.

    Dim boxObj As Acad3DSolid
    Dim length As Double, width As Double, height As Double
    Dim center(0 To 2) As Double

    ' Define the box
    center(0) = 5#: center(1) = 5#: center(2) = 0
    length = 5#: width = 7: height = 10#

    ' Create the box (3DSolid) object in model space
    Set boxObj = ThisDrawing.ModelSpace.AddBox(center, length, width, height)

    ' Change the viewing direction of the viewport to better see the box
    Dim NewDirection(0 To 2) As Double
    NewDirection(0) = -1: NewDirection(1) = -1: NewDirection(2) = 1
    ThisDrawing.ActiveViewport.direction = NewDirection
    ThisDrawing.ActiveViewport = ThisDrawing.ActiveViewport
    ZoomAll

    ' Return the Centroid for the box
    Dim Centroid As Variant
    Centroid = boxObj.Centroid
    MsgBox "The Centroid for the box is " & Centroid(0) & ", " & Centroid(1), , "Centroid Example"

    End Sub
     
    devitg, Apr 16, 2004
    #8
  9. Marcel Janmaat

    BillZ Guest

    Here's a program I made to get the centroid of a region in R14.

    May need a little tweeking.
    It reads the txt file back into the program from the massprop command and gets the xyz of the centroid.
    Enjoy!

    Bill

    ;04/27/01 BILL ZONDLO program to select region.
    ;and show point at centroid.
    ;--------------;
    (defun c:centroid_pnt (/ alst clst cn2 cnt cntr en en1 ent fl fil lne lt1 xyz) ;program name & variables.
    (initget 1)
    (setq en1 (car (entsel "\nSelect solid or region: < pick > "))
    ent (entget en1)
    )
    (cond ((or (equal (cdr (assoc 0 ent)) "REGION")
    (equal (cdr (assoc 0 ent)) "SOLID")
    (equal (cdr (assoc 0 ent)) "3DSOLID")
    ) ;end or
    (command "_.massprop" en1 "" "Y" "c:/centr.mpr")
    (if (findfile "c:/centr.mpr")
    (progn
    (setq fl (open "c:/centr.mpr" "r"))
    (while (setq fil (read-line fl))
    (if (not (null fil))
    (setq lt1 (append lt1 (list fil))
    )
    ) ;end if
    ) ;end while
    (close fl)
    ) ;end progn
    ) ;end if
    ;---;
    (setq cnt 0 ;extract file info
    cn2 0)
    (repeat (length lt1)
    (setq lne (nth cnt lt1)
    cn2 cnt
    )
    (if (= (substr lne 1 8) "Centroid") ;if centroid line
    (progn
    (repeat 3 ;take 3 lines
    (setq xyz (nth cn2 lt1) ;full line
    clst (append clst (list xyz)) ;append to list.
    cn2 (1+ cn2)
    ) ;end setq
    ) ;end repeat
    ) ;end progn
    ) ;end if
    (setq cnt (1+ cnt))
    ) ;end repeat
    ;---;
    (setq alst (list "X" "Y" "Z")) ;check list
    (foreach n clst
    (setq en n)
    (if (wcmatch en (strcat "*" (car alst) "*")) ;if contains x, y or z
    (progn
    (while (and (> (strlen en) 0)
    (wcmatch en (strcat "*" (car alst) "*"))) ;trim string
    (setq en (substr en 2)) ;
    ) ;end while
    (setq en (substr en 2)
    en (distof en 2)) ;
    ) ;end progn
    (setq en "0.00000" ;in no z, means 0.0
    en (distof en 2))
    ) ;end if
    (setq alst (cdr alst)
    cntr (append cntr (list en))
    )
    ) ;end foreach
    ;---;
    (setvar "pdsize" -3)
    (setvar "pdmode" 34)
    (command "point" cntr)
    ;------------------------;
    ) ;end list
    ) ;end cond
    ;------------------------;
    (princ) ;no nil at end of program.
    ) ;end defun.
     
    BillZ, Apr 16, 2004
    #9
  10. Marcel Janmaat

    devitg Guest

    Hi Billz :
    This lisp works if the objetc had a 3 point centroid , but if the object is a simple area it only have 2 point centroid.
    I will try to modify to get the x y only points.
    See waht is saved when a simple area is saved

    Area: 608108.5780
    Perimeter: 3224.3816
    Bounding box: X: -415.6167 -- 594.6384
    Y: -45.9715 -- 555.9641
    Centroid: X: 89.5109
    Y: 254.9963
    Moments of inertia: X: 57902270268.5057

    So the lisp will give the z point as

    Moments of inertia: X: 57902270268.5057
     
    devitg, Apr 16, 2004
    #10
  11. Marcel Janmaat

    jb Guest

    After you obtain region, you can use function 'dos_massprops' from
    free doslib library - www.mcneel.com
    JB
     
    jb, Apr 16, 2004
    #11
  12. I dont remember the author:

    Option Explicit

    Sub ALE_PointCentroid()
    Dim RObj As AcadEntity
    Dim SSObj As AcadSelectionSet
    Dim Centroid As Variant
    Dim Location(0 To 2) As Double
    Randomize Timer
    Set SSObj = ThisDrawing.SelectionSets.Add(Str(Rnd))
    SSObj.SelectOnScreen
    For Each RObj In SSObj
    If RObj.ObjectName = "AcDbRegion" Then
    Centroid = RObj.Centroid
    Location(0) = Centroid(0)
    Location(1) = Centroid(1)
    Call ThisDrawing.ModelSpace.AddPoint(Location)
    'MsgBox "OK"
    Else: MsgBox "L'oggetto deve essere una regione!"
    End If
    Next RObj
    End Sub


    --
    ________________________________________________

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    O.S. = XP Pro 2002 Ita - Sp.1
    AutoCAD = 2004 Ita - Sp.1a
    ________________________________________________
     
    Marc'Antonio Alessi, Apr 18, 2004
    #12
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.