enthralled Posted January 8, 2019 Posted January 8, 2019 After manually selecting a group of LWpolylines, I need a command to find and select the shortest (closed) LWpolyline from my current selection, I need only one polyline to be selected at a time, even if multiple polylines share the same length. Thanks! Quote
dlanorh Posted January 8, 2019 Posted January 8, 2019 (edited) Try this (defun c:shortest ( / *error* ss p_lst min_l s_lst) (defun *error* ( msg ) (if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")) (princ (strcat "\nOops an Error : " msg " occurred."))) (princ) );_end_*error*_defun (setq c_doc (vla-get-activedocument (vlax-get-acad-object)) ss (ssget '((0 . "LWPOLYLINE") (70 . 1))) );end_setq (if ss (vlax-for obj (vla-get-activeselectionset c_doc) (setq p_lst (cons (list (vlax-get-property obj 'length) obj) p_lst)) );end_for (alert "Nothing Selected") );end_if (cond (p_lst (setq s_lst (vl-sort p_lst (function (lambda (x y) (< (car x) (car y))))) min_l (caar s_lst) p_lst (vl-remove-if-not (function (lambda (x) (= (car x) min_l))) s_lst) s_lst nil );end_setq (mapcar '(lambda (x) (setq s_lst (cons (cadr x) s_lst))) p_lst) (foreach a s_lst (vla-highlight a :vlax-true)) (alert (strcat "There" (if (> (length p_lst) 1) " are " " is ") (itoa (length p_lst)) (if (> (length p_lst) 1) " entities of length : " " entity of length : ") (rtos min_l 2 3))) ) );end_cond );end_defun min_l - contains the shortest distance s_lst - contains all the vla-objects that have a length of min_l The last two lines (foreach a s_lst (vla-highlight a :vlax-true)) (alert (strcat "There" (if (> (length p_lst) 1) " are " " is ") (itoa (length p_lst)) (if (> (length p_lst) 1) " entities of length : " " entity of length : ") (rtos min_l 2 3))) are only included for demonstration purposes and can be removed I've included a selection process as part of the routine. This will only select closed lwpolylines. Edited January 8, 2019 by dlanorh 1 Quote
enthralled Posted January 8, 2019 Author Posted January 8, 2019 On 1/8/2019 at 12:25 PM, dlanorh said: Try this (defun c:shortest ( / *error* ss p_lst min_l s_lst) (defun *error* ( msg ) (if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")) (princ (strcat "\nOops an Error : " msg " occurred."))) (princ) );_end_*error*_defun (setq c_doc (vla-get-activedocument (vlax-get-acad-object)) ss (ssget '((0 . "LWPOLYLINE") (70 . 1))) );end_setq (if ss (vlax-for obj (vla-get-activeselectionset c_doc) (setq p_lst (cons (list (vlax-get-property obj 'length) obj) p_lst)) );end_for (alert "Nothing Selected") );end_if (cond (p_lst (setq s_lst (vl-sort p_lst (function (lambda (x y) (< (car x) (car y))))) min_l (caar s_lst) p_lst (vl-remove-if-not (function (lambda (x) (= (car x) min_l))) s_lst) s_lst nil );end_setq (mapcar '(lambda (x) (setq s_lst (cons (cadr x) s_lst))) p_lst) (foreach a s_lst (vla-highlight a :vlax-true)) (alert (strcat "There" (if (> (length p_lst) 1) " are " " is ") (itoa (length p_lst)) (if (> (length p_lst) 1) " entities of length : " " entity of length : ") (rtos min_l 2 3))) ) );end_cond );end_defun min_l - contains the shortest distance s_lst - contains all the vla-objects that have a length of min_l The last two lines (foreach a s_lst (vla-highlight a :vlax-true)) (alert (strcat "There" (if (> (length p_lst) 1) " are " " is ") (itoa (length p_lst)) (if (> (length p_lst) 1) " entities of length : " " entity of length : ") (rtos min_l 2 3))) are only included for demonstration purposes and can be removed I've included a selection process as part of the routine. This will only select closed lwpolylines. Expand How can I make the shortest (highlighted) polyline into an active selection? Thanks! Quote
ronjonp Posted January 8, 2019 Posted January 8, 2019 (edited) Try something like this: (defun c:foo (/ _a a l s) ;; RJP ยป 2019-01-08 ;; Returns shortest closed polyline (defun _a (e) (vlax-curve-getdistatparam e (vlax-curve-getendparam e))) (cond ((setq s (ssget '((0 . "lwpolyline") (-4 . "&=") (70 . 1)))) (setq l (vl-sort (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) '(lambda (r j) (< (_a r) (_a j))) ) ) (sssetfirst nil (ssadd (car l))) ) ) (princ) ) Edited January 8, 2019 by ronjonp *code changed original logic was flawed 2 Quote
Lee Mac Posted January 8, 2019 Posted January 8, 2019 Here's another method: (defun c:shortestpoly ( / a d e i l s ) (if (setq s (ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1)))) (progn (setq e (ssname s 0) l (vlax-curve-getdistatparam e (vlax-curve-getendparam e)) i 0 ) (while (setq i (1+ i) a (ssname s i)) (if (< (setq d (vlax-curve-getdistatparam a (vlax-curve-getendparam a))) l) (setq l d e a) ) ) (sssetfirst nil (ssadd e)) ) ) (princ) ) This will offer efficiency gains for large sets since the selection is only iterated once (therefore fewer comparisons & length calculations than a sort operation), without the need for conversion to a list (which can be slow when ssnamex is used, since this returns more information than is required). Nothing against Ron's code 1 Quote
ronjonp Posted January 8, 2019 Posted January 8, 2019 OP cross posted .. has many options to choose from. 1 Quote
ronjonp Posted January 8, 2019 Posted January 8, 2019 On 1/8/2019 at 5:37 PM, Lee Mac said: This will offer efficiency gains for large sets since the selection is only iterated once (therefore fewer comparisons & length calculations than a sort operation), without the need for conversion to a list (which can be slow when ssnamex is used, since this returns more information than is required). Expand Totally agree .. sometimes I get a bit crazy trying to keep code short as possible at the expense of speed. Quote
lido Posted January 8, 2019 Posted January 8, 2019 For a shortest pline, it would be interesting to know which is the fastest solution. Bench them all if you have a little time. (defun c:minlpoly (/ lSet) (if (setq lSet (ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1)))) (apply (function min) (mapcar (function (lambda (x)(vla-get-length (vlax-ename->vla-object x))) ) (vl-remove-if (function listp) (mapcar (function cadr) (ssnamex lSet) ) ) ) ) ) ) 1 Quote
Lee Mac Posted January 8, 2019 Posted January 8, 2019 On 1/8/2019 at 9:54 PM, lido said: For a shortest pline, it would be interesting to know which is the fastest solution. Bench them all if you have a little time. Expand Note that your function is not returning the shortest polyline, but rather the shortest length. Quote
lido Posted January 9, 2019 Posted January 9, 2019 Sorry. Try this. (defun c:lighmpoly (/ lEnt lVal) (if (setq sSet (ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1)))) (setq sSet (car (sssetfirst nil (ssadd (nth (vl-position (apply ;; (function max) ;;longest (function min) (mapcar (function (lambda (x / y) (setq y (vla-get-length (vlax-ename->vla-object x)) lVal (cons y lVal) ) y ) ) (setq lEnt (vl-remove-if (function listp) (mapcar (function cadr) (ssnamex sSet) ) ) ) ) ) lVal ) (reverse lEnt) ) ) ) ) ) ) ;; (if lVal (/ (apply (function +) lVal) (length lVal))) ;;average (princ) ) 1 Quote
Roy_043 Posted January 9, 2019 Posted January 9, 2019 @Lido: Your code creates the length list twice... Quote
ronjonp Posted January 9, 2019 Posted January 9, 2019 On 1/8/2019 at 9:54 PM, lido said: Bench them all if you have a little time Expand Here you go. Tested on 1000 polylines. Quote FOO FOO2 SHORTESTPOLY LIGHMPOLY Benchmarking ..........Elapsed milliseconds / relative speed for 128 iteration(s): (SHORTESTPOLY S)......2250 / 12.49 <fastest> (FOO2 S)..............6032 / 4.66 (FOO S)..............19109 / 1.47 (LIGHMPOLY S)........28094 / 1.00 <slowest> Expand FOO2 is a quick mod of my vl-sort ( brought to light a while back by Michael Puckett @ TheSwamp ) (defun foo2 (s / _a a l) (defun _a (e) (vlax-curve-getdistatparam e (vlax-curve-getendparam e))) (cond ((setq l (cdar (vl-sort (mapcar '(lambda (x) (cons (_a x) x)) (vl-remove-if 'listp (mapcar 'cadr (ssnamex s)))) '(lambda (r j) (< (car r) (car j))) ) ) ) (sssetfirst nil (ssadd l)) ) ) (princ) ) 1 Quote
Grrr Posted January 9, 2019 Posted January 9, 2019 (edited) Interesting, how fast would be this: (defun c:polytheshortest ( / SS len tmp r ) (and (ssget "_:L-I" '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1))) (setq SS (vla-get-ActiveSelectionSet (vla-get-ActiveDocument (vlax-get-acad-object)))) (progn (setq tmp (vlax-get (setq r (vla-Item SS 0)) 'Length)) (vlax-for o SS (and (> tmp (setq len (vlax-get o 'Length))) (setq tmp len r o) ); and ); vlax-for (vla-Delete SS) (sssetfirst nil (ssadd (vlax-vla-object->ename r))) ); progn ); and (princ) ); defun Edited January 9, 2019 by Grrr (setq r (vla-Item SS 0)) Quote
ronjonp Posted January 9, 2019 Posted January 9, 2019 (edited) On 1/9/2019 at 7:40 PM, Grrr said: Interesting, how fast would be this: Expand Quote (SHORTESTPOLY S).........2015 / 16.69 <fastest> (FOO2 S).................5719 / 5.88 (FOO S).................21094 / 1.59 (POLYTHESHORTEST S).....23890 / 1.41 (LIGHMPOLY S)...........33625 / 1.00 <slowest> Expand *Must have done something wrong before, but when tested your code bombs on '(vlax-vla-object->ename r)' Edited January 9, 2019 by ronjonp 1 Quote
Grrr Posted January 9, 2019 Posted January 9, 2019 (edited) On 1/9/2019 at 8:23 PM, ronjonp said: *Must have done something wrong before, but when tested your code bombs on '(vlax-vla-object->ename r)' Expand Duh.. modified the code, to initialize r to the first item of the SS. Edited January 9, 2019 by Grrr Quote
ronjonp Posted January 9, 2019 Posted January 9, 2019 On 1/9/2019 at 8:33 PM, Grrr said: Duh.. modified the code, to initialize r to the first item of the SS. Expand Updated Quote <Selection set: 44222> Benchmarking ...........Elapsed milliseconds / relative speed for 256 iteration(s): (SHORTESTPOLY S).........1843 / 23.12 <fastest> (FOO2 S).................5047 / 8.44 (FOO S).................18047 / 2.36 (POLYTHESHORTEST S).....25547 / 1.67 (LIGHMPOLY S)...........42609 / 1.00 <slowest> Expand Quote
Grrr Posted January 9, 2019 Posted January 9, 2019 On 1/9/2019 at 9:30 PM, ronjonp said: Updated Expand Oh wow, activex is freaking slow! .. Thanks for the update! 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.