Author Topic: Selecting polylines overlapped by shorter polyline  (Read 1479 times)

0 Members and 1 Guest are viewing this topic.

ifncdylan

  • Guest
Selecting polylines overlapped by shorter polyline
« on: March 13, 2018, 08:46:08 PM »
Hey all, I have a bit of a tricky one, I've been looking around the place for some examples of this but I can't seem to get anything together which works how I want.

I've attached some example lines here, there's a red polyline which is the duct and the rest of the polylines which are cables which run through the ducts, north to south. There's also some cables which are running across the duct east to west which I don't want to select. These lines are not always simple straight two vertex polylines and sometimes have extra vertexes, e.g. on the right.

The goal is to select all cables which are 'in' the red ducts - i.e. polylines that are running 'under' another polyline, but only along the length of it, and with some 'fuzz factor' as the lines are not always in the same place (they could be drawn slightly offset) and not always running parallel (sometimes they drawn on a slight angle).

Essentially I want to pick the lines underneath the red line (duct) but only include lines which are running along the length of the red line, not any crossing it in another direction, and include lines that are expanded.

A imagine perhaps a script which picks the middle two vertexes of the red line, and does a small box selection (the 'fuzz factor') on each and compares the two lists to return a list where it only includes the objects that are in both might work, however I'm not very good with curve/vertex functions so I haven't been able to figure out how to get the 'middle' vertexes which could also be the 'start/end' vertexes for a 2-point polyline.

Any pointers to some example functions to do this stuff would be greatly appreciated. :)



ifncdylan

  • Guest
Re: Selecting polylines overlapped by shorter polyline
« Reply #1 on: March 13, 2018, 11:36:01 PM »
Well, here's what I've come up with. It seems to work (on the two-box selection method), however I feel like it could be done more elegantly. It would be good if it didn't require zooming the window around as some drawings have 300k+ lines that need to be processed in this manner so the zoom method does work quite slowly - but hey, it works! :)

Thanks to all the people I nabbed some code knowledge from.. and as always.. thank you to Lee Mac, whose utility functions basically form the foundations of everything I do. :)

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun C:test ( / s i e v osm)
  3.  
  4.     (defun *error* ( msg )
  5.         (if osm (setvar 'osmode osm))
  6.                 (if (not (member msg '("Function cancelled" "quit / exit abort")))
  7.                 (princ (strcat "\nError: " msg))
  8.                 )
  9.         (princ)
  10.   )
  11.  
  12.   ;current view/snap settings
  13.   (setq osm (getvar "osmode"))
  14.   (setvar "osmode" 0)
  15.  
  16.   (cond
  17.         ((and (setq s (ssget '((0 . "LWPOLYLINE"))))
  18.          (setq view (LM:ViewportExtents)))
  19.         (if (setq v (LM:ss->vla s))
  20.                 (foreach o v
  21.                         (if (setq u (DB:SelectLinesUnder o))
  22.                                 (if (setq l (LM:ss->vla u))
  23.                                         (foreach d l
  24.                                                 (vla-put-color d acGreen)
  25.                                         )
  26.                                 )
  27.                         )
  28.                 )
  29.           )
  30.         ; restore view
  31.     )
  32.    (T
  33.     (princ)
  34.     )
  35.    )
  36.  
  37.    (setvar "osmode" osm)
  38. )
  39.    
  40. ; Input:        [ent]           - Polyline entity
  41. ; Return:       [ss]            - selection set of objects
  42.  
  43. (defun DB:SelectLinesUnder ( ent / fuzz verts mid p1 p2 b1 b2 l1 l2 ss1 ss2 ss3 d1 osm)
  44.  
  45.   (defun *error* ( msg )
  46.         (if osm (setvar 'osmode osm))
  47.                 (if (not (member msg '("Function cancelled" "quit / exit abort")))
  48.                 (princ (strcat "\nError: " msg))
  49.                 )
  50.         (princ)
  51.   )
  52.  
  53.   (setq osm (getvar "osmode"))
  54.   (setvar "osmode" 0)
  55.  
  56.   (if (= 'VLA-OBJECT (type ent)) (setq ent (vlax-vla-object->ename ent)))
  57.   (setq fuzz 0.3)
  58.  
  59.   ;; zoom to the object so selections work
  60.  
  61.   (zoom-to ent)
  62.   (setq verts (DB:lwvertices (entget ent)))
  63.  
  64.   ; get the middle vertices (lines with 2/3 verts returns first/last position
  65.   (cond
  66.     ((>= 3 (length verts))
  67.         (setq p1 (nth 0 verts)
  68.               p2 (last verts)
  69.               )
  70.      )
  71.     ((< 3 (length verts))
  72.         (setq mid (/ (1- (length verts)) 2)
  73.               p1 (nth mid verts)
  74.               p2 (nth (1+ mid) verts))
  75.      )
  76.   )
  77.  
  78.  
  79.  
  80.   ;create selection boxes at each point
  81.   (setq b1 (GE_GetBoxAroundPt p1 fuzz fuzz 0))
  82.   (setq b2 (GE_GetBoxAroundPt p2 fuzz fuzz 0))
  83.   (setq ss1 (ssget "_F" b1 '((0 . "*LINE"))))
  84.   (setq ss2 (ssget "_F" b2 '((0 . "*LINE"))))
  85.  
  86.   ; remove the original line from the sets
  87.   (ssdel ent ss1)
  88.   (ssdel ent ss2)
  89.  
  90.   ; compare lists for duplicates
  91.   (setq l1 (LM:ss->vla ss1))
  92.   (setq l2 (LM:ss->vla ss2))
  93.   (setq d1 (DB:ListDupes l1 l2))
  94.  
  95.   ; build return sset from duplicates
  96.   (setq ss3 (ssadd))
  97.   (foreach obj d1
  98.     (ssadd (vlax-vla-object->ename obj) ss3)
  99.   )
  100.   ;restore snap and zoom
  101.   (setvar 'osmode osm)
  102.  
  103.   ;return value
  104.   (if (and ss3 (> (sslength ss3) 0)) ss3 nil)
  105.  
  106.   )
  107.  
  108.  
  109. (defun DB:ListDupes ( l1 l2 )
  110.   (vl-remove-if-not '(lambda ( x ) (member x l2)) l1)
  111. )      
  112.  
  113. ;; Returns a list of vertex points in a LWPolyline (simplified version of LM:lwvertices by Lee Mac)
  114. (defun DB:lwvertices ( e )
  115.     (if (setq e (member (assoc 10 e) e))
  116.         (cons
  117.                 (cdr (assoc 10 e))
  118.             (DB:lwvertices (cdr e))
  119.         )
  120.     )
  121. )
  122.  
  123. ;; create box around point (http://www.4d-technologies.com/techcenter/)
  124. (defun GE_GetBoxAroundPt( pt dX dY Rot / p1 p2 p3 p4 halfX halfY _Rot )
  125.  
  126.         halfX (* 0.5 dX)
  127.         halfY (* 0.5 dY)
  128.         _Rot  (/ (* Rot pi) 180.0)
  129.         p1    (polar pt (+ _Rot pi) halfX)
  130.         p1    (polar p1 (+ _Rot (* 0.5 pi)) halfY)
  131.         p2    (polar p1 _Rot dX)
  132.         p3    (polar p2 (- _Rot (* 0.5 pi)) dY)
  133.         p4    (polar p3 (+ _Rot pi) dX)
  134. )
  135. (list p1 p2 p3 p4)
  136. )
  137.  
  138. (defun zoom-to (obj / lowleft upright)
  139.   (if (eq (type obj) 'ENAME) (setq obj (vlax-ename->vla-object obj)))
  140.   (vla-getboundingbox obj 'lowleft 'upright)
  141.   (vlax-invoke-method (vlax-get-acad-object) 'zoomwindow lowleft upright)
  142. )
  143.  
  144. ;; Viewport Extents  -  Lee Mac
  145. ;; Returns two WCS points describing the lower-left and
  146. ;; upper-right corners of the active viewport.
  147.  
  148. (defun LM:ViewportExtents ( / c h v )
  149.     (setq c (trans (getvar 'viewctr) 1 0)
  150.           h (/ (getvar 'viewsize) 2.0)
  151.           v (list (* h (apply '/ (getvar 'screensize))) h)
  152.     )
  153.     (list (mapcar '- c v) (mapcar '+ c v))
  154. )
  155.  

ronjonp

  • Needs a day job
  • Posts: 7529
Re: Selecting polylines overlapped by shorter polyline
« Reply #2 on: March 14, 2018, 02:59:13 PM »
Here's another way to do it. May give you some ideas. :)

Code - Auto/Visual Lisp: [Select]
  1. (defun c:foo (/ _colinear _ss2l _foo _pts f pts2 r s1 s2 tmp)
  2.   ;; RJP - 03.14.2018
  3.   (defun _ss2l (s) (cond ((= 'pickset (type s)) (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))))))
  4.   (defun _pts (e) (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= 10 (car x))) (entget e))))
  5.   (defun _foo (e / p)
  6.     (mapcar
  7.       '(lambda (a b) (cons (mapcar '(lambda (c) (/ c 2.)) (mapcar '+ a b)) (rem (angle a b) pi)))
  8.       (setq p (_pts e))
  9.       (cdr p)
  10.     )
  11.   )
  12.   (defun _colinear (p1 p2 p3 f) (equal (+ (distance p1 p2) (distance p2 p3)) (distance p1 p3) f))
  13.   ;; Fuzz value for equality check
  14.   (setq f 1e-2)
  15.   (if
  16.     (and (setq s1 (_ss2l (ssget '((0 . "lwpolyline") (62 . 1)))))
  17.          (setq s2 (_ss2l (ssget "_A" '((0 . "lwpolyline") (-4 . "<NOT") (62 . 1) (-4 . "NOT>")))))
  18.          (setq r (ssadd))
  19.     )
  20.      (foreach pt (apply 'append (mapcar '_foo s1))
  21.        (setq tmp s2)
  22.        (foreach pl s2
  23.          (setq pts2 (_pts pl))
  24.          (cond ((vl-some '(lambda (a b)
  25.                             (and (_colinear a (car pt) b f) (equal (cdr pt) (rem (angle a b) pi) f))
  26.                           )
  27.                          pts2
  28.                          (cdr pts2)
  29.                 )
  30.                 (setq tmp (vl-remove pl tmp))
  31.                 (ssadd pl r)
  32.                )
  33.          )
  34.        )
  35.        (setq s2 tmp)
  36.      )
  37.   )
  38.   (sssetfirst nil r)
  39.   (princ)
  40. )
« Last Edit: March 15, 2018, 10:30:00 AM by ronjonp »

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

ifncdylan

  • Guest
Re: Selecting polylines overlapped by shorter polyline
« Reply #3 on: March 15, 2018, 07:34:43 PM »
Thanks ronjonp! Looks like a much better way to go about the selection method.

I'll try it out and see if I can understand how it's working - but I don't like my chances of that!  :2funny: