Hi all,
I need to return the entity name of the largest (longest closed) polyline in a selection set. At this point I have no trouble creating the selection set and even getting the area of the boundingbox, which is not the most acurate way to find the true size, but it's a start. The part that has me stumped is: if I iterate through the selection set, then how can I compare one to the other when I have access to the current entity. I've been staring at examples of lambdas but it seems to me that iterating through the selection set is going about it wrong in the first place.
Below is my current code with a remaining issue. I can return the largest area of the polylines (no good for more than two entities in selection set), but I do not know how to return the entityname:
(IF (> (SETQ SS (SSGET "x" '((0 . "*POLYLINE") (8 . "POOL") (-4 . "<OR") (62 . 5) (62 . 256) (-4 . "OR>")))) 1 ) (PROGN (SETQ a (1- a) ent (CDR (CAR (SSNAME ss a))) en2 (CDR (CAR (SSNAME ss (1- a)))) ar1 (APPLY '* (LIST (LAMBDA (ent) (VLAX-INVOKE-METHOD (VLAX-ENAME->VLA-OBJECT ent) 'getboundingbox 'minpt 'maxpt) (SETQ pt1 (TRANS (VLAX-SAFEARRAY->LIST minpt) 0 ent) pt2 (TRANS (VLAX-SAFEARRAY->LIST maxpt) 0 ent) ) (VL-REMOVE 0.0 (MAPCAR '- pt2 pt1)) ) ) ) ar2 (APPLY '* (LIST (LAMBDA (en2) (VLAX-INVOKE-METHOD (VLAX-ENAME->VLA-OBJECT en2) 'getboundingbox 'minpt 'maxpt) (SETQ pt1 (TRANS (VLAX-SAFEARRAY->LIST minpt) 0 en2) pt2 (TRANS (VLAX-SAFEARRAY->LIST maxpt) 0 en2) ) (VL-REMOVE 0.0 (MAPCAR '- pt2 pt1)) ) ) ) big (MAX ar1 ar2) ) ) )
There is no doubt that this code is rough. I'm trying to hammer out how, then I'll see if I can simplify it.
Thank you for any help/advice.
Solved! Go to Solution.
Solved by Lee_Mac. Go to Solution.
Ok, I've tried building it out in a way that makes sense to me:
(IF (> (SETQ SS (SSGET "x" '((0 . "*POLYLINE") (8 . "POOL") (-4 . "<OR") (62 . 5) (62 . 256) (-4 . "OR>")))) 1) (PROGN (SETQ a (1- a) ent (CDR (CAR (SSNAME ss a))) en2 (CDR (CAR (SSNAME ss (1- a)))) ar1 (CONS ENT (APPLY '* (LIST (LAMBDA (ent) (VLAX-INVOKE-METHOD (VLAX-ENAME->VLA-OBJECT ent) 'getboundingbox 'minpt 'maxpt) (SETQ pt1 (TRANS (VLAX-SAFEARRAY->LIST minpt) 0 ent) pt2 (TRANS (VLAX-SAFEARRAY->LIST maxpt) 0 ent) ) (VL-REMOVE 0.0 (MAPCAR '- pt2 pt1)) ) ) ) ) ar2 (CONS EN2 (APPLY '* (LIST (LAMBDA (en2) (VLAX-INVOKE-METHOD (VLAX-ENAME->VLA-OBJECT en2) 'getboundingbox 'minpt 'maxpt) (SETQ pt1 (TRANS (VLAX-SAFEARRAY->LIST minpt) 0 en2) pt2 (TRANS (VLAX-SAFEARRAY->LIST maxpt) 0 en2) ) (VL-REMOVE 0.0 (MAPCAR '- pt2 pt1)) ) ) ) ) big (MAX (cdr ar1) (cdr ar2)) bigr (if (= big (cdr ar1)) (car ar1) (car ar2)) *poolENT* bigr ) ) )
And, i get this error:
error: bad argument type for compare: <Selection set: 238> 1
I'm not sure what is wrong other than I'm just handling it wrong.
Hi mid-awe,
Consider the following quick example:
(defun c:bigpoly ( / ar1 ar2 ent idx rtn sel ) (if (setq sel (ssget "_X" '( (0 . "*POLYLINE") (8 . "POOL") (-4 . "<OR") (62 . 5) (62 . 256) (-4 . "OR>") (-4 . "&=") (70 . 1) ) ) ) (progn (repeat (setq idx (sslength sel)) (setq ent (ssname sel (setq idx (1- idx)))) (if (< ar1 (setq ar2 (vla-get-area (vlax-ename->vla-object ent)))) (setq ar1 ar2 rtn ent ) ) ) (redraw rtn 3) ) ) (princ) ) (vl-load-com) (princ)
@mid-awe wrote:
Lee,
Thank you. Works great. I still bang my head at some of these "tricks". But, I will be hanging on to (-4 . "&=") (70 . 1)
Does that filter closed polylines? Also, I've not seen the "&=" before. I'm sure that will be very helpful going forward.
Again, Thank you.
You're most welcome mid-awe -
I hope my code was clear to understand, but if not, feel free to ask about anything you are unsure of.
Regarding the relational operator "&=": this is the bitwise masked equals operator, and its use in the ssget filter list in conjunction with the DXF group 70 code is equivalent to:
(= 1 (logand 1 (cdr (assoc 70 <DXF data>))))
I have put together a more complete ssget function reference on my site which includes additional examples.
Lee
Since the original question specifically mentions finding the longest closed Polyline, consider that the greatest area doesn't necessarily indicate the longest perimeter. [A 6x6 square has a smaller perimeter length, but a greater area, than a 10x3 rectangle.] It may be that you should change this in Lee's routine:
(if (< ar1 (setq ar2 (vla-get-area (vlax-ename->vla-object ent))))
(setq ar1 ar2
rtn ent
to something like this, to get the length rather than the area:
(if (< len1 (setq len2 (vlax-curve-getDistAtParam ent (vlax-curve-getEndParam ent))))
(setq len1 len2
rtn ent
@Kent1Cooper wrote:to something like this, to get the length rather than the area:
(if (< len1 (setq len2 (vlax-curve-getDistAtParam ent (vlax-curve-getEndParam ent))))
(setq len1 len2
rtn ent
Or alternatively retrieve the ActiveX Length property:
(vla-get-length (vlax-ename->vla-object ent))
@Lee_Mac wrote:
....Or alternatively retrieve the ActiveX Length property:
(vla-get-length (vlax-ename->vla-object ent))
Yes. My brain defaults to the distance-at-End-Parameter approach because I use it in many routines that may need to find lengths of various entity types. Not all entity types have a Length property [Arcs and Circles don't]. But Polylines do, so in a case that's limited to them like this, that works -- and it's shorter!. [The distance-at-End-Point approach is also unreliable, returning 0 for closed entities. But distance-at-End-Parameter gets it right for any entity type, open or closed.]
@Kent1Cooper wrote:
Since the original question specifically mentions finding the longest closed Polyline, consider that the greatest area doesn't necessarily indicate the longest perimeter. [A 6x6 square has a smaller perimeter length, but a greater area, than a 10x3 rectangle.]
Good point Kent.
Many great things have arisen here. 🙂 Thank you all.
I'm sure Lee was interpreting my example code in which I did my best to find the area of the bounding box (length * width). So, for my needs, the area is perfectly acceptable, although, I have a use for both the area and length.
At this point in the larger program either area or length will do.
Thank you all.