Community
AutoCAD Forum
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Snap to Center of Irregular shape

12 REPLIES 12
Reply
Message 1 of 13
HoshangMustafa
5534 Views, 12 Replies

Snap to Center of Irregular shape

Hi

 

Please find the attached file.

How can I snap to the center of irregular shape?

For the first time, I drew hatch for the shape. When selecting the hatch a node will appear. Is this node is the center of the hatch?

12 REPLIES 12
Message 2 of 13
nrz13
in reply to: HoshangMustafa

I use this LISP to add a point at the center of polygons:

;; Add Center Point to Polygons
(defun subr ()
(setq ctr (+ ctr 1))
(setq x (car vertex))
(setq y (cadr vertex))
(setq allx (+ allx x))
(setq ally (+ ally y))
)
(defun C:CN (/ allx ally ctr tst entity-name data pt x y)
(setq allx 0
ally 0
ctr 0
tst 1
)
(setq entity-name (car (entsel "\nPick an ellipse or polygon: ")))
(SETQ EL (ENTGET ENTITY-NAME))
(while (assoc 10 EL)
(SETQ VERTEX (CDR (assoc 10 EL)))
(SUBR)
(setq EL (cdr (member (assoc 10 EL) EL)))
)
(setq x (/ allx ctr))
(setq y (/ ally ctr))
(setq pt (list x y))
(command "point" pt)
)
;
;/ vertex
(princ)

Just enter CN to start it or make your own alias for it.  I have it in a file that opens whenever the program is loaded.


Work:  AutoCAD 2022.1.3, Windows 10 Pro v22H2 64-bit, Intel Core i7-8700K, 32GB RAM, Samsung 960 Pro SSD, AMD Radeon Pro WX 5100, 3 Dell Monitors (3840x2160)
Home: AutoCAD 2022.1.3, Windows 10 Pro v22H2 64-bit, Intel Core i7-11700, 64GB RAM, Samsung 980 Pro SSD, NVIDIA Quadro P2200, Dell Monitor (3840x2160)
Message 3 of 13
dbroad
in reply to: nrz13

Your method does not seem to return the centroid as indicated by converting the polyline to a region and extracting the centroid from it.  Neither does it follow the algorithm for finding centroid as shown here: http://en.wikipedia.org/wiki/Centroid

 

Here is a method that uses the built-in features for regions:

(vl-load-com)
;;Draw a point at the centroid of a closed polygon
;;Converts the polyline to a region and extracts the centroid
;;D.C.Broad, Jr  2014
;;remove centroid from local var list if access to the point data is needed
;;outside the command.
(defun c:centroid ( / ss o doc oid spc reg centroid)
  (setq doc (vla-get-activedocument (vlax-get-acad-object)))
  (prompt "Select a closed non-self-intersecting polyline.")
  (if
    (and
      (setq ss (ssget '((0 . "lwpolyline"))));selection
      (setq o (vlax-ename->vla-object (ssname ss 0)));object
      (= :vlax-true (vla-get-closed o));closed
      )
    (progn
      (setq oid (vla-get-ownerid o))
      (setq spc (vla-objectidtoobject doc oid));mspace or pspace
      
      (setq reg (vlax-invoke spc 'addregion (list o)));region
      (setq centroid (vlax-get (car reg) 'centroid));centroid
      (vlax-invoke spc 'addpoint (setq centroid (trans (list (car centroid)(cadr centroid) (vla-get-elevation o)) 1 0)));point
      (vla-delete (car reg));cleanup
      
      )
    )
  (princ);quiet exit
  )

 

 This routine may not return a proper point if region is not parallel to ucs.  The trans function may need to be modified to use the ename of the polyline rather than the ucs.

Architect, Registered NC, VA, SC, & GA.
Message 4 of 13
nrz13
in reply to: dbroad

Just to clarify, I just copied this from somewhere at some point.  I don't know enough to be able to calculate or program myself.  I do notice that neither method posted puts the center point where AutoCAD places the center point for a hatch.

I guess I've never noticed the problem before because I'm usually trying to get a center snap point for a square or other uniform polygon or closed polyline.


Work:  AutoCAD 2022.1.3, Windows 10 Pro v22H2 64-bit, Intel Core i7-8700K, 32GB RAM, Samsung 960 Pro SSD, AMD Radeon Pro WX 5100, 3 Dell Monitors (3840x2160)
Home: AutoCAD 2022.1.3, Windows 10 Pro v22H2 64-bit, Intel Core i7-11700, 64GB RAM, Samsung 980 Pro SSD, NVIDIA Quadro P2200, Dell Monitor (3840x2160)
Message 5 of 13
dbroad
in reply to: nrz13

It depends on what the OP wants.  The hatch command seems to have a base point at the center of an object's bounding box. The code to place a point at that point would be as follows:

 

(vl-load-com)
;;Similar to C:BX posted by Cliff Middleton 10/1/2001
;;Draw a point at the center of an object's bounding box.
;;D. C. Broad, Jr. 2014 (defun c:cpbox ( / o llc urc cp) (prompt "Select a polygon: ") (if (setq e (car (entsel))) (progn (setq o (vlax-ename->vla-object e)) (vla-GetBoundingBox o 'llc 'urc) (setq llc (vlax-safearray->list llc)) (setq urc (vlax-safearray->list urc)) (setq cp (mapcar '(lambda (a b) (/ (+ a b) 2.0)) llc urc)) (command "_.point" cp) ) (princ "\nNo object selected") ) (princ) )

 Center might be a misnomer.  Probably should be termed middle of bounding box.

Architect, Registered NC, VA, SC, & GA.
Message 6 of 13


@HoshangMustafa wrote:

Hi

 

Please find the attached file.

How can I snap to the center of irregular shape?

For the first time, I drew hatch for the shape. When selecting the hatch a node will appear. Is this node is the center of the hatch?


I agree that it depends on what you're trying to do, and yes, the grip for a Hatch pattern is the center of its bounding box.  That can be quite different from its centroid or "center of gravity" [e.g. for a right triangle whose legs are orthogonal, it will lie at the midpoint of the hypotenuse, but will be elsewhere if it's rotated non-orthogonally].  Here's another way to get and put a Point at the weighted average of the vertex locations of a Polyline, if that's what you're after [minimally tested]:

 

(defun C:PCP (/ pl pldata vertqua verts vertsum); = Polygon Center Point
  (setq
    pl (car (entsel "\nSelect Polygon to place Point at average of its vertices: "))
    pldata (entget pl)
    vertqua (cdr (assoc 90 pldata))
    verts
      (mapcar 'cdr; XY coordinates only from:
        (vl-remove-if-not '(lambda (x) (= (car x) 10)) pldata); vertex entries only
      ); mapcar & verts
    vertsum '(0 0)
  ); setq
  (foreach pt verts (setq vertsum (mapcar '+ pt vertsum)))
  (command "_.point" (mapcar '/ vertsum (list vertqua vertqua)))
); defun

 

I think [though I'm not positive] that will be the same as the centroid if all the Polyline edges are line segments, but not if there are any arc segments involved, in which case I think you would need to use the Region-and-centroid approach.  It could have controls added to check whether something was actually selected, whether it's the right kind of thing, whether it's closed if that matters, etc.

Kent Cooper, AIA
Message 7 of 13
luis.zzucco
in reply to: dbroad

Hello Doug, I'm trying a variation of your code but returns the following error

 

 

(vl-load-com)

;

; many other commands

;

(setq o (vlax-ename->vla-object (ssname (entlast) 0)))
; error: no function definition: VLAX-ENAME->VLAX-OBJECT 

OR

; error: bad argument type: lselsetp <Entity name: 278228149f0>

;

; other commands to get the centroid

;

 

The code is running thru VLIDE on AUTOCAD 2017.

 

I'm a LISP begginer programmer.

 

Thanks in advance + regards

Luís

 

Message 8 of 13
Kent1Cooper
in reply to: luis.zzucco


@luis.zzucco wrote:

....

(setq o (vlax-ename->vla-object (ssname (entlast) 0)))
; error: no function definition: VLAX-ENAME->VLAX-OBJECT 

OR

; error: bad argument type: lselsetp <Entity name: 278228149f0>

.... 


The (ssname) function gets an entity from a selection set, but you're giving it an entity directly instead.  That's what the second error message means -- it's looking for a selection set, but what it's getting is an entity name.  Try giving just the entity to the other function:

(setq o (vlax-ename->vla-object (entlast)))

 

[That first error message presumably doesn't really contain the X in the second part.  If it does, it's in reaction to something other than the line just above it, in which the function name must be misspelled.]

 

Kent Cooper, AIA
Message 9 of 13

It's easier since Autocad 2016 with the geometric center osnap. No need for lisps anymore 🙂

Message 10 of 13
dbroad
in reply to: luis.zzucco

@luis.zzucco,

@Kent1Cooper should have solved your issue and explained the problems well.  If not, please reply with more information.

 

I agree with @MetalFingerz that it is much easier since 2016 to find the centroid with the GCE snap.

Architect, Registered NC, VA, SC, & GA.
Message 11 of 13
luis.zzucco
in reply to: MetalFingerz

In fact I've tried the use of centroid command, but in some irregular shapes even the centroid isn't inside the polygon. Centroid is the little point at the center of the left figure and is out of the polygon.

problem1.jpg

 

But, I still have those problems I mention before.

 

Kent is probably right the error lies in the command before

(setq o (vlax-ename->vla-object (entlast)))

 

that is a trying to join 6 lines into a new object (but isn't working out)

(command "pedit" join_line "join" ab_line bc_line cd_line de_line ef_line fa_line "" "")

 

This is the code I'm creating in a vbscript macro

_$ (vl-load-com)
_$ (setq os (getvar 'osmode))
_$ (setvar 'osmode 0)
_$ (setvar "filletrad" 0)
_$ (setq a ' (-186.119 298.183 0))
_$ (setq b ' (-186.119 264.383 0))
_$ (command "Line" a b "")
_$ (setq ab_line (entlast))
_$ (setq c ' (-141.919 264.383 0))
_$ (command "Line" b c "")
_$ (setq bc_line (entlast))
_$ (setq d ' (-140.553 268.937 0))
_$ (command "Line" c d "")
_$ (setq cd_line (entlast))
_$ (setq e ' (-178.690 291.013 0))
_$ (command "Line" d e "")
_$ (setq de_line (entlast))
_$ (setq f ' (-181.912 299.737 0))
_$ (command "Line" e f "")
_$ (setq ef_line (entlast))
_$ (command "Line" f a "")
_$ (setq fa_line (entlast))
_$ (command "pedit" join_line "join" ab_line bc_line cd_line de_line ef_line fa_line "" "")
_$ (setq offpt (osnap c "NEA"))
_$ (command "offset" 1.50 ab_line offpt "")
_$ (setq oab_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget oab_line))))
_$ (setq pt2 (cdr (assoc 11 (entget oab_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt1(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (setq offpt (osnap d "NEA"))
_$ (command "offset" 1.50 bc_line offpt "")
_$ (setq obc_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget obc_line))))
_$ (setq pt2 (cdr (assoc 11 (entget obc_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt2(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (setq offpt (osnap e "NEA"))
_$ (command "offset" 4.00 cd_line offpt "")
_$ (setq ocd_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget ocd_line))))
_$ (setq pt2 (cdr (assoc 11 (entget ocd_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt3(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (setq offpt (osnap f "NEA"))
_$ (command "offset" 1.50 de_line offpt "")
_$ (setq ode_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget ode_line))))
_$ (setq pt2 (cdr (assoc 11 (entget ode_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt4(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (setq offpt (osnap a "NEA"))
_$ (command "offset" 1.50 ef_line offpt "")
_$ (setq oef_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget oef_line))))
_$ (setq pt2 (cdr (assoc 11 (entget oef_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt5(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (setq offpt (osnap b "NEA"))
_$ (command "offset" 4.00 fa_line offpt "")
_$ (setq ofa_line (entlast))
_$ (setq pt1 (cdr (assoc 10 (entget ofa_line))))
_$ (setq pt2 (cdr (assoc 11 (entget ofa_line))))
_$ (setq x(/ (- (car pt2) (car pt1)) 2.00))
_$ (setq y(/ (- (cadr pt2) (cadr pt1)) 2.00))
_$ (setq mPt6(list (+ (car pt1)x)(+ (cadr pt1)y)))
_$ (command "._fillet" mPt1 mPt2)
_$ (command "._fillet" mPt2 mPt3)
_$ (command "._fillet" mPt3 mPt4)
_$ (command "._fillet" mPt4 mPt5)
_$ (command "._fillet" mPt5 mPt6)
_$ (command "._fillet" mPt6 mPt1)

 

The shape created is OK but one line of the code (for the offset command) if directing it to the outside of the shape

 

Of course I want to solve this technical LISP problems, but I need to find another solution to solve the main problem that is:

How to get an OSNAP point (automatically) to offset all the lines of the polygon (with different values) always to inside part of the polygon.

 

Ideas?

 

Many thanks,

Luis

 

Message 12 of 13
Kent1Cooper
in reply to: luis.zzucco


@luis.zzucco wrote:

.... the main problem that is:

How to get an OSNAP point (automatically) to offset all the lines of the polygon (with different values) always to inside part of the polygon.

.... 


For an already-assembled Polyline, if you have a known Offset distance, you don't need to find a point with the (vla-offset) function.  Offset it with a positive value, compare the result's Area property to that of the original, and if that's larger, undo that and Offset it with a negative value.  In simplest terms, and [for demonstration purposes] using your 1.5 example built in:

 

(defun C:OPI ; = Offset Polyline Inside
  (/ pl plobj)
  (setq
    pl (car (entsel "\nSelect Polyline to Offset to Inside: "))
    plobj (vlax-ename->vla-object pl)
  ); setq
  (command "_.undo" "_mark")
  (vla-offset plobj 1.5)
  (if (> (vla-get-Area (vlax-ename->vla-object (entlast))) (vla-get-Area plobj))
    (progn
      (command "_.undo" "_back")
      (vla-offset plobj -1.5)
    ); progn
  ); if
); defun

 

It uses Undo Mark/Back rather than something like (entdel (entlast)) because of the possibility that Offsetting an irregularly-shaped Polyline can result in more than one new Polyline.  And it doesn't account for the possibility that the Offset distance will be too large for Offsetting inboard [if it goes that way first with no result, its Area test will fail with the cryptic message "error: Automation Error. Description was not provided."].  And it doesn't just use U, because that undoes the previous regular AutoCAD command, not the (vla-offset).

 

The same can also be used on Circles, Ellipses, or Splines, even unclosed ones -- anything with an Area VLA Property.

 

BUT if you need to Offset the Lines separately, such as at different distances, before connecting them into a Polyline, I don't have any bright ideas about determining in which direction to Offset them.  It's hard to imagine how that could be done, if you don't even have an assembled Polyline yet to make any kind of comparison(s) to, whatever the comparison(s) might be.

Kent Cooper, AIA
Message 13 of 13
luis.zzucco
in reply to: Kent1Cooper

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost