hristev Posted September 1, 2017 Posted September 1, 2017 Hi guys I am looking for a routine which helps to select AutoCAD points near line whitin user defined certain distance. I've tried to write it by myself but I am completely newbie in AutoLISP. Anyway I will share my toughts about it. As I said the user defines the distance from the line, so probably the routine should use the start and end point of the line and add/substract this distance so you get 4 pairs of coordinates and then use these coordinates to define the selection window.I hope it make sense. It will be much apreciated if you give me some hints, thank you in advance. Quote
hanhphuc Posted September 1, 2017 Posted September 1, 2017 (edited) my $0.02 [url="http://www.lee-mac.com/ssget.html"]ssget[/url] [color="blue"]getpoint entget polar[/color] (defun c:test ( / d en ob ls xy o1 o2) (defun xy (l) (if ([color="red"]cadr[/color] l) (cons (list (car l)(cadr l))(xy (cddr l))))) (and (setq d (getdist "\nDistance from line..")) (setq en(car(entsel "\nSelect polyline "))) (wcmatch (cdr (assoc 0 (entget en))) "LWPOLYLINE") (setq ob '("o1" "o2") ls (mapcar ''((a b) (xy (vlax-get (set (read a) (car (vlax-invoke (vlax-ename->vla-object en) 'Offset b))) 'coordinates ) ) ) ob (list d (- d)) ) ) (mapcar ''((x)(vla-delete (eval(read x)))) ob) (sssetfirst nil (ssget "_WP" (append (car ls)(reverse (cadr ls))) '((0 . "POINT")))) ); and ) Edited September 2, 2017 by hanhphuc xy function - cddr to cdar Quote
hristev Posted September 1, 2017 Author Posted September 1, 2017 Thank you very much of both of you! @Tharwat that is exactly what I need. But I haven't been clear enough with my explanation though - the points Z values are not 0. So can you make it to ignore the Z values of the points and take in acount only X Y values and still select them. I appreciate your help Quote
hristev Posted September 1, 2017 Author Posted September 1, 2017 Thank you very much of both of you! @Tharwat that is exactly what I need. But I haven't been clear enough with my explanation though - the points Z values are not 0. So can you make it to ignore the Z values of the points and take in acount only X Y values and still select them. I appreciate your help Quote
Tharwat Posted September 1, 2017 Posted September 1, 2017 Hi, Try this program and be sure to have the selected line / polyline completely visible in the screen. (defun c:Test ( / dis sel obj l r str end top dwn int sad ssc ent pnt) ;; Tharwat - Date: 01.Sep.2017 ;; (if (and (setq dis (getdist "\nSpecify distance between line and points : ")) (princ "\nSelect Line/Polyline :") (setq sel (ssget "_+.:S:E" '((0 . "LINE,LWPOLYLINE")))) (setq obj (ssname sel 0)) ) (progn (vla-GetBoundingBox (vlax-ename->vla-object obj) 'l 'r) (setq str (vlax-safearray->list r) end (vlax-safearray->list l) top (mapcar '(lambda (c d) (+ d c)) (list dis dis 0.) str) dwn (mapcar '(lambda (c d) (- d c)) (list dis dis 0.) end) int -1 sad (ssadd) ) (if (setq ssc (ssget "_C" top dwn '((0 . "POINT")))) (while (setq ent (ssname ssc (setq int (1+ int)))) (setq pnt (cdr (assoc 10 (entget ent)))) (if (<= (distance (vlax-curve-getclosestpointto obj pnt) pnt) dis) (ssadd ent sad)) ) ) ) ) (sssetfirst nil sad) (princ) ) (vl-load-com) Quote
hristev Posted September 1, 2017 Author Posted September 1, 2017 Thank you very much of both of you! @Tharwat that is exactly what I need. But I haven't been clear enough with my explanation though - the points Z values are not 0. So can you make it to ignore the Z values of the points and take in acount only X Y values and still select them. I appreciate your help Quote
hanhphuc Posted September 1, 2017 Posted September 1, 2017 Hi,Try this program and be sure to have the selected line / polyline completely visible in the screen. (defun c:Test ( / dis sel obj l r str end top dwn int [color="red"]sad[/color] ssc ent pnt) ;; Tharwat - Date: 01.Sep.2017 ;; why sad? i'm happy you still active here, fast & nice code anyway Quote
Tharwat Posted September 1, 2017 Posted September 1, 2017 (defun xy (l) (if [color="blue"](cddr l) [/color] (cons (list (car l)(cadr l))(xy (cddr l))))) Hi, I think there is no need to check for the second list of coordinates since this would come up with the last coordinates missing. why sad? It is just a bad habit of using this name of variable with that function and nothing else. i'm happy you still active here, fast & nice code anyway Thank you, its too kind of you to say that. Quote
hanhphuc Posted September 2, 2017 Posted September 2, 2017 Hi, I think there is no need to check for the second list of coordinates since this would come up with the last coordinates missing. Thank you Tharwat you are correct, It was rough written but my ignorant for x,y parity as always good catch Quote
Tharwat Posted September 2, 2017 Posted September 2, 2017 Thank you Tharwat you are correct,It was rough written but my ignorant for x,y parity as always good catch No problem. (if l ... is enough. Have a nice weekend. Quote
Lee Mac Posted September 2, 2017 Posted September 2, 2017 Here's another way to solve it, without reliance on object visibility: ([color=BLUE]defun[/color] c:ptnearline ( [color=BLUE]/[/color] dis ent enx idx llp lst pnt pte sel tmp urp ) ([color=BLUE]initget[/color] 4) ([color=BLUE]if[/color] ([color=BLUE]and[/color] ([color=BLUE]setq[/color] dis ([color=BLUE]getdist[/color] [color=MAROON]"\nSpecify proximity: "[/color])) ([color=BLUE]progn[/color] ([color=BLUE]while[/color] ([color=BLUE]not[/color] ([color=BLUE]progn[/color] ([color=BLUE]setvar[/color] 'errno 0) ([color=BLUE]setq[/color] ent ([color=BLUE]car[/color] ([color=BLUE]entsel[/color] [color=MAROON]"\nSelect line or polyline: "[/color]))) ([color=BLUE]cond[/color] ( ([color=BLUE]=[/color] 7 ([color=BLUE]getvar[/color] 'errno)) ([color=BLUE]prompt[/color] [color=MAROON]"\nMissed, try again."[/color]) ) ( ([color=BLUE]null[/color] ent)) ( ([color=BLUE]=[/color] [color=MAROON]"LINE"[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 0 ([color=BLUE]setq[/color] enx ([color=BLUE]entget[/color] ent))))) ([color=BLUE]setq[/color] llp ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 10 enx)) urp ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 11 enx)) tmp ([color=BLUE]mapcar[/color] '[color=BLUE]max[/color] llp urp) llp ([color=BLUE]mapcar[/color] '[color=BLUE]min[/color] llp urp) urp tmp ) ) ( ([color=BLUE]=[/color] [color=MAROON]"LWPOLYLINE"[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 0 enx))) ([color=BLUE]setq[/color] lst ([color=BLUE]mapcar[/color] '[color=BLUE]cdr[/color] ([color=BLUE]vl-remove-if-not[/color] '([color=BLUE]lambda[/color] ( x ) ([color=BLUE]=[/color] 10 ([color=BLUE]car[/color] x))) enx)) llp ([color=BLUE]apply[/color] '[color=BLUE]mapcar[/color] ([color=BLUE]cons[/color] '[color=BLUE]min[/color] lst)) urp ([color=BLUE]apply[/color] '[color=BLUE]mapcar[/color] ([color=BLUE]cons[/color] '[color=BLUE]max[/color] lst)) ) ) ( ([color=BLUE]prompt[/color] [color=MAROON]"\nPlease select a line or polyline."[/color])) ) ) ) ) ent ) ([color=BLUE]setq[/color] sel ([color=BLUE]ssget[/color] [color=MAROON]"_X"[/color] ([color=BLUE]list[/color] '(000 . [color=MAROON]"POINT"[/color]) '(-04 . [color=MAROON]">=,>="[/color]) ([color=BLUE]cons[/color] 10 ([color=BLUE]mapcar[/color] '[color=BLUE]-[/color] llp ([color=BLUE]list[/color] dis dis))) '(-04 . [color=MAROON]"<=,<="[/color]) ([color=BLUE]cons[/color] 10 ([color=BLUE]mapcar[/color] '[color=BLUE]+[/color] urp ([color=BLUE]list[/color] dis dis))) ([color=BLUE]if[/color] ([color=BLUE]=[/color] 1 ([color=BLUE]getvar[/color] 'cvport)) ([color=BLUE]cons[/color] 410 ([color=BLUE]getvar[/color] 'ctab)) '(410 . [color=MAROON]"Model"[/color]) ) ) ) ) ) ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] idx ([color=BLUE]sslength[/color] sel)) ([color=BLUE]setq[/color] pte ([color=BLUE]ssname[/color] sel ([color=BLUE]setq[/color] idx ([color=BLUE]1-[/color] idx))) pnt ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 10 ([color=BLUE]entget[/color] pte))) ) ([color=BLUE]if[/color] ([color=BLUE]<[/color] dis ([color=BLUE]distance[/color] pnt ([color=BLUE]vlax-curve-getclosestpointto[/color] ent pnt))) ([color=BLUE]ssdel[/color] pte sel) ) ) ) ([color=BLUE]sssetfirst[/color] [color=BLUE]nil[/color] sel) ([color=BLUE]princ[/color]) ) ([color=BLUE]vl-load-com[/color]) ([color=BLUE]princ[/color]) Quote
hristev Posted September 2, 2017 Author Posted September 2, 2017 @hanhphuc, @Tharwat and @Lee Mac, you guys are true legends. As I tried the routines of all of you I realized my explanation was not fully correct. I missed the part that my points' Z value is not 0 and the routine needs to take in account only X and Y. Obviously the routine of @hanhphuc work in that scenario and the other two don't but I am grateful to all tree of you that you spend time on this. Cheers Quote
guigonse Posted September 2, 2017 Posted September 2, 2017 ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] idx ([color=BLUE]sslength[/color] sel)) ([color=BLUE]setq[/color] pte ([color=BLUE]ssname[/color] sel ([color=BLUE]setq[/color] idx ([color=BLUE]1-[/color] idx))) pnt ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 10 ([color=BLUE]entget[/color] pte))) ) ([color=BLUE]if[/color] ([color=BLUE]<[/color] dis ([color=BLUE]distance[/color] pnt ([color=BLUE]vlax-curve-getclosestpointto[/color] ent pnt))) ([color=BLUE]ssdel[/color] pte sel) ) ) [\QUOTE] IMO you could forget about pre-selecting POINTS and make Lee Mac's distance check for ALL POINT entities, isn't it? Quote
guigonse Posted September 2, 2017 Posted September 2, 2017 Arghh!! Missed copy/pasting part of the code... Apologies... Quote
guigonse Posted September 2, 2017 Posted September 2, 2017 ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] idx([color=BLUE]sslength[/color][color=red][b][color=red] [b](setq sel[/b][/color] (ssget "X" '((0 . "POINT"))))[/b][/color])) ([color=BLUE]setq[/color] pte ([color=BLUE]ssname[/color] sel ([color=BLUE]setq[/color] idx ([color=BLUE]1-[/color] idx))) pnt ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 10 ([color=BLUE]entget[/color] pte))) ) ([color=BLUE]if[/color] ([color=BLUE]<[/color] dis ([color=BLUE]distance[/color] pnt ([color=BLUE]vlax-curve-getclosestpointto[/color] ent pnt))) ([color=BLUE]ssdel[/color] pte sel) ) ) That's the part of the code i was referring, with small changes in red... By the way, there's an option for editing my own messages? This will shorten threads, I think... Quote
Lee Mac Posted September 2, 2017 Posted September 2, 2017 IMO you could forget about pre-selecting POINTS and make Lee Mac's distance check for ALL POINT entities, isn't it? This is hugely inefficient for large point sets. Using an ssget filter to vastly reduce the initial point set based on coordinate values greatly reduces the number of relatively inefficient calls to vlax-curve-getclosestpointto & distance. Code concision does not necessary equal efficiency. Quote
guigonse Posted September 2, 2017 Posted September 2, 2017 This is hugely inefficient for large point sets. Using an ssget filter to vastly reduce the initial point set based on coordinate values greatly reduces the number of relatively inefficient calls to vlax-curve-getclosestpointto & distance. Code concision does not necessary equal efficiency. You're right, probably... But if the whole points group in the rectangle which diagonal is the selection line, then you will end selecting the major part of them despite your coding effort! What about a "Windows Polygon selection? Would be easy to generate it with (polar ..) generated points from the reference segment, and the selection would be the answer itself... And frankly speaking, forgetting 3d scanned cloud points, do you really think there would be a loose of performance perception on processing part or the whole of points in the major part of drawings? ;; p1 = start point of reference segment ;; p2 = end point of reference segment ;; dist = distance of selection (setq a (angle p1 p2) ss (ssget "_CW" (list (polar p1 a dist) (polar p1 a (- dist)) (polar p2 a dist) (polar p2 a (- dist)) ) '((0 . "POINT")) ) ) I'm just checking strategies... Quote
Lee Mac Posted September 2, 2017 Posted September 2, 2017 This is hugely inefficient for large point sets. Using an ssget filter to vastly reduce the initial point set based on coordinate values greatly reduces the number of relatively inefficient calls to vlax-curve-getclosestpointto & distance. Code concision does not necessary equal efficiency. As a quick demonstration of this difference in efficiency, the following are timings for point sets of varying size: 100,000 Random Points Prefiltered point set: 0.312 seconds Processing all points: 1.154 seconds 500,000 Random Points Prefiltered point set: 0.749 seconds Processing all points: 5.756 seconds 1,000,000 Random Points Prefiltered point set: 1.232 seconds Processing all points: 10.389 seconds Quote
guigonse Posted September 3, 2017 Posted September 3, 2017 You have wrote both routines and a third to generate random points and evaluated them!! You are my hero!! Questions: how do you make "solid" time measurements with Lisp? And with Visual Lisp? Referring to the problem, being efficiency a key point, wouldn't be better to optimize (ssget ..) to make the exact selection with a "Window Poligon" option? Something like ;; p1 = straight segment origin ;; p2 = straight segment end ;; d = max distance to straight segment (setq a (+ (angle p1 p2) (/ pi 2)) ss (ssget "_CW" (list (polar p1 a d) (polar p1 a (- d)) (polar p2 a d) (polar p2 a (- d)) ) '((0 . "POINT")) ) ) This way, selection is the solution, isn't it? But only with straight segments, of course... Quote
Roy_043 Posted September 3, 2017 Posted September 3, 2017 @guigonse: In principle you are right, although your window points are not in the correct order. But please note this: Your code assumes a 2D drawing. The window selection has to be on-screen. Lee has already referred to this. The end and start point of the line are expressed in the WCS whereas the "CW" points are expressed in the current UCS. 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.