 Find the nearest parallel line

Recommended Posts Posted (edited) How can I find the nearest line which is parallel with the target entity.

As in the image, I want to find the green line in both case, notice the red line has a smaller distance to my target "abcedfg", but in the second case, the parallel part of the polyline has a longer distance than the green line. In fact,  I need to know the exact amount of the distance to the parallel line to get my lisp start working.

All white ones is for distraction test...

It's been a while since last time I wrote anything in English, please pardon my terrible description if you don't mind. Edited by dirtyacc

Share on other sites are they all lines, or are some of them polylines?

Share on other sites 8 hours ago, dlanorh said:

are they all lines, or are some of them polylines?

some are polyline.

Share on other sites Try this.

Command FNP  (for Find Nearest Parallel)

It draws a few lines and XLines, looks for intersections, then picks the closest parallel line that has overlap. ... then it deletes these lines/Xlines

The part that overlaps is drawn on the nearest line/XLine, and gets selected (sssetfirst)

```

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun drawLine (p1 p2 / exv)
;;(setq exv (trans (list 0 0 1) 1 0 T))
(entmakex (list (cons 0 "LINE")
(cons 10 p1)
(cons 11 p2)
;;(cons 210 exv)
))
)

(defun xLine (pt vec / exv)
(setq exv (trans (list 0 0 1) 1 0 T))
(entmakex (list (cons 0 "XLINE")
(cons 100 "AcDbEntity")
(cons 100 "AcDbXline")
(cons 10 pt)
(cons 11 vec)
(cons 210 exv)
))
)

(defun c:test_xline ( / )

(xLine
(list 128.616 130.629 0.0)
(polar (list 0.0 0.0 0.0) (+ (/ pi 2.0) 2.20327) 1)
)

)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Collinear-p  -  Lee Mac
;; Returns T if p1,p2,p3 are collinear
(defun LM:Collinear-p ( p1 p2 p3 )
(
(lambda ( a b c )
(or
(equal (+ a b) c 1e-8)
(equal (+ b c) a 1e-8)
(equal (+ c a) b 1e-8)
)
)
(distance p1 p2) (distance p2 p3) (distance p1 p3)
)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; get Closest Point To
(defun gct (l1 c1 / p1 )
(setq p1 (vlax-curve-getClosestPointTo
(car l1)
(trans c1 1 0)
(mapcar '-
(trans (getvar "VIEWDIR") 1 0)
(trans '(0 0 0) 1 0)
)
))
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; 2d-coord->pt-lst
;; Converts a 2d coordinates flat list into a 2d point list
;;; (2d-coord->pt-lst '(1.0 2.0 3.0 4.0)) -> ((1.0 2.0) (3.0 4.0))
(defun 2d-coord->pt-lst (lst)
(if lst
(cons (list (car lst) (cadr lst))
(2d-coord->pt-lst (cddr lst))
)
)
)

;; user selects a polyline with nentsel, this function returns ( start and endpoint of ) the selected segment
(defun selected_vertex (pline pp / p1 vertexs i ps pe result)
(setq p1 (gct pline pp))
(setq
i 0
;; get vertices of the polyline
vertexs (2d-coord->pt-lst (vlax-get (vlax-ename->vla-object (car pline)) 'coordinates))
)
(repeat (- (length vertexs) 1)
(if
(LM:Collinear-p
(setq ps (nth i vertexs))
p1
(setq pe (nth (+ i 1) vertexs))
)
(setq result (list ps pe))
)
(setq i (+ i 1))
)
result
)

(defun is_parallel (ang1 ang2 / small_number result)
(setq small_number 0.0001)
;; if angle 2 is 180° more than angle 1, both are parallel as well
(while (>= ang1 pi)
(setq ang1 (- ang1 pi))
)
(while (>= ang2 pi)
(setq ang2 (- ang2 pi))
)
(if (< (abs (- ang1 ang2)) small_number)
(setq result T)
(setq result nil)
)
result
)

(defun same_line (a b c d / small_number)
(setq small_number 0.0001)
(if (and
(< (distance a b) small_number)
(< (distance c d) small_number)
)
T
nil
)
)

;; https://www.theswamp.org/index.php?topic=31737.0
;;  return a list of intersect points or nil
(defun get_interpts (obj1 obj2 / iplist)
(if (not (vl-catch-all-error-p
(setq iplist (vl-catch-all-apply
'vlax-safearray->list
(list
(vlax-variant-value
(vla-intersectwith obj1 obj2 acextendnone)
))))))
iplist
)
)

;; returns the first intersection point, or nil.
;; it disregards other insert points
(defun first_intersect (obj1 obj2 / a)
(setq a (get_interpts (vlax-ename->vla-object obj1) (vlax-ename->vla-object obj2)))
(if a
a ;; (nth 0 a)
nil
)
)

(defun c:fnp ( / src data pp lines i j sp1 ep1 ang1 dst sp2 ep2 ang2 vertexs vtx ss typ temp_xlines tmp_cln tmp_ln tp1 tp2 tp3 tp4 pol1 pol2 pol3 pol4 is1 is2 is3 is4 overlap_data overlap_item dst_ ind)
(setq temp_xlines (list))   ;; must be removed at the end
(setq overlap_data (list))  ;; list of lists: (list (list overlap_point1 overlap_point2 distance) ... )

;; User selected line or polyline
(setq src (nentsel "\nSource line or sub entity of polyline"))
;; it could be a line or a selected part of a polyline.  in any case let's find start and endpoint
(if (= "LINE" (cdr (assoc 0 (entget (car src)))))
(progn
(setq sp1 (cdr (assoc 10 (entget (car src)))))
(setq ep1 (cdr (assoc 11 (entget (car src)))))
)
;; else, it should be a polyline
(progn
(setq vtx (selected_vertex src (cadr src)))
(setq sp1 (nth 0 vtx))
(setq ep1 (nth 1 vtx))
)
)
;; angle
(setq ang1 (angle sp1 ep1))
;; draw a temp line
(setq tmp_cln (drawLine sp1 ep1))

;; now we select all lines and polylines in the dwg
;; and see if the angle is the same
;; of those lines with the same angle we calculate the distance
;; we skip lines without overlap
(setq i 0)
(setq data (list))
(setq ss (ssget "_X" (list (cons 0 "LINE,POLYLINE,LWPOLYLINE" ))))
;;(setq ss (ssget "_X" (list (cons 0 "LINE" ))))
(repeat (sslength ss)
(setq typ (cdr (assoc 0 (entget (ssname ss i)))))

(if (= typ "LINE")
(progn
(setq ang2
(angle
(setq sp2 (cdr (assoc 10 (entget (ssname ss i)))))
(setq ep2 (cdr (assoc 11 (entget (ssname ss i)))))
)
)
(setq data (append data (list (list sp2 ep2 ang2))))
)
;; else, polyline
(progn
(setq dst (ssname ss i))
(setq vertexs (2d-coord->pt-lst (vlax-get (vlax-ename->vla-object dst) 'coordinates)))
(setq j 0)
(repeat (- (length vertexs) 1)

(setq ang2
(angle
(setq sp2 (nth j vertexs))
(setq ep2 (nth (+ j 1) vertexs))
)
)
(setq data (append data (list (list sp2 ep2 ang2))))
(setq j (+ j 1))
)

)
)
(setq i (+ i 1))
)

(setq i 0)
(foreach line data
(if (is_parallel ang1 (nth 2 line))
(progn
;; see if there is overlap.  We draw an XLine perpendicular to both lines at the 4 endpoints.
;; 2 of those XLines should intersect with the other line
;; the distance between these 2 XLines is the parallel overlap

;; skip, if the line = the user selected line
(if (not (same_line sp1 (nth 0 line) ep1 (nth 1 line))) (progn

;; draw a temp line
(setq tmp_ln (drawLine (nth 0 line) (nth 1 line)))

(setq temp_xlines (append temp_xlines (list
(setq tp1 (xLine
sp1
(setq pol1 (polar (list 0.0 0.0 0.0) (+ (/ pi 2.0) ang1) 1))
))
)))
(setq temp_xlines (append temp_xlines (list
(setq tp2 (xLine
ep1
(setq pol2 (polar (list 0.0 0.0 0.0) (+ (/ pi 2.0) ang1) 1) )
))
)))
(setq temp_xlines (append temp_xlines (list
(setq tp3 (xLine
(nth 0 line)
(setq pol3 (polar (list 0.0 0.0 0.0) (+ (/ pi 2.0) (nth 2 line)) 1) )
))
)))
(setq temp_xlines (append temp_xlines (list
(setq tp4 (xLine
(nth 1 line)
(setq pol4 (polar (list 0.0 0.0 0.0) (+ (/ pi 2.0) (nth 2 line)) 1))
))
)))

;;  now look for intersections
(setq is1 (first_intersect tmp_ln tp1))
(setq is2 (first_intersect tmp_ln tp2))
(setq is3 (first_intersect tmp_cln tp3))
(setq is4 (first_intersect tmp_cln tp4))

(setq overlap_item (list))

(if is1 (progn
(setq dst_ (distance is1 sp1))
(setq overlap_item (append overlap_item (list is1)))
))
(if is2 (progn
(setq dst_ (distance is2 ep1))
(setq overlap_item (append overlap_item (list is2)))
))
(if is3 (progn
(setq dst_ (distance is3 (nth 0 line)))
(setq overlap_item (append overlap_item (list (nth 0 line))))
))
(if is4 (progn
(setq dst_ (distance is4 (nth 1 line)))
(setq overlap_item (append overlap_item (list (nth 1 line))))
))

;; only if there are 2 overlap points we have a valid line
(if (= (length overlap_item) 2) (progn
(setq overlap_item (append overlap_item (list dst_)))
;; now add this item to the list of lists
(setq overlap_data (append overlap_data (list overlap_item)))
))
;; delete temp line
(entdel tmp_ln)

))  ;; / not same line ?

)
)
(setq i (+ i 1))
)

(setq
dst_ (nth 2 (nth 0 overlap_data))
ind 0
j 0
)
(foreach i overlap_data
(if (< (nth 2 i) dst_) (progn
(setq
dst_ (nth 2 i)
ind j
)
))
(setq j (+ j 1))
)

(foreach i temp_xlines
(entdel i)
)
(entdel tmp_cln)

(sssetfirst nil
(ssadd (drawLine (nth 0 (nth ind overlap_data)) (nth 1 (nth ind overlap_data))))
)

(princ)
)

```

Share on other sites Posted (edited)

If you have only LINEs and not polylines, in 2D then this should work -

```; Grips the closest parallel line to the picked one
(defun C:test ( / extremum _PickLine GetLinePts )

; Lee Mac
; _\$ (extremum '(lambda ( a b ) (< (caddr a) (caddr b))) '((1.2 5.7 8.3) (9.4 2.6 0.3) (5.7 6.6 7.2))) >> (9.4 2.6 0.3)
(defun extremum ( cmp lst / rtn )
(setq rtn (car lst))
(foreach itm (cdr lst)
(if (apply cmp (list itm rtn)) (setq rtn itm))
)
rtn
)

(setq _PickLine
(lambda ( / e enx r ) (setvar 'errno 0)
(while (/= 52 (getvar 'errno)) (setq e (car (entsel "\nPick a line: " )))
(cond
( (= 7 (getvar 'errno)) (setvar 'errno 0) ) ( (not e) )
( (not (member '(0 . "LINE") (setq enx (entget e)))) (prompt "\nInvalid object.") )
( (setvar 'errno 52) (setq r enx) )
)
)
r
)
)

(setq GetLinePts
(lambda ( e / pts enx r )
(setq pts (apply 'append (mapcar '(lambda (x) (if (member (car x) '(10 11)) (list (cdr x)))) (setq enx (entget e)))))
(setq r
(list
(cdr (assoc 5 enx))
(apply 'mapcar (cons '(lambda (a b) (* (+ a b) 0.5)) pts))
(mapcar 'abs (apply 'mapcar (cons '- pts)))
e
)
)
)
)

( ; Main
(lambda ( / enx SS i L pts pt )
(cond
( (not (setq enx (_PickLine))) )
( (setq SS (ssget "_X" (list '(0 . "LINE") (assoc 410 enx))))
(repeat (setq i (sslength SS))
(setq L (cons (GetLinePts (ssname SS (setq i (1- i)))) L))
); repeat
(and
(setq pts (GetLinePts (cdr (assoc -1 enx))))
(setq L (vl-remove-if '(lambda (x) (or (apply '= (mapcar 'car (list pts x))) (not (equal (caddr pts) (caddr x) 1e-3)))) L))
(sssetfirst nil
(last
(extremum
'(lambda ( a b )
); lambda
L
)
)
)
)
); and
)
); cond
); lambda
)
(princ)
); defun ```

Edited by Grrr

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. ×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.