Author Topic: Test if two lines are collinear (2D)  (Read 3032 times)

0 Members and 1 Guest are viewing this topic.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1451
  • Marco
Test if two lines are collinear (2D)
« on: December 19, 2016, 12:07:15 PM »
Almost certainly is a done deal, but I could not find it, I need to test if two lines are collinear (simple 2D test), I have found theese functions:
Code: [Select]
;; List Collinear-p  -  Lee Mac
;; Returns T if all points in a list are collinear
(defun LM:ListCollinear-p ( lst )
    (or (null (cddr lst))
        (and (LM:Collinear-p (car lst) (cadr lst) (caddr lst))
             (LM:ListCollinear-p (cdr lst))
        )
    )
)
;; 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-4)
                (equal (+ b c) a 1e-4)
                (equal (+ c a) b 1e-4)
            )
        )
        (distance p1 p2) (distance p2 p3) (distance p1 p3)
    )
)
Is there an easier way passing directly the objects without extracting the start and end points?

ahsattarian

  • Newt
  • Posts: 112
Re: Test if two lines are collinear (2D)
« Reply #1 on: September 08, 2022, 04:04:58 AM »
..

It seems that you must have four checks  :

1-   collinear of   po1  -  po2  -  po3

2-   collinear of   po1  -  po2  -  po4

3-   collinear of   po3  -  po4  -  po1

4-   collinear of   po3  -  po4  -  po2

..

ribarm

  • Gator
  • Posts: 3266
  • Marko Ribar, architect
Re: Test if two lines are collinear (2D)
« Reply #2 on: September 08, 2022, 05:52:35 AM »
Actually, IMHO, first 3 checks are all that is needed; 4th is not necessity, but I agree, for security reasons I'd still suggest 4 chks...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

zak26

  • Newt
  • Posts: 33
Re: Test if two lines are collinear (2D)
« Reply #3 on: September 08, 2022, 01:44:19 PM »
I hope this can help you, as always Thanks to Lee for those functions that help us a lot.
Code: [Select]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;   Program  coll          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 20220908 V1.0 Program to verify if two lines or polylines are collinear     ;;;
;;; ;;;
;;; ;;;
;;; Isaac A ;;;
;;; http://www.theswamp.org/index.php?topic=52422.0 ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun c:coll ( / e1 ole p1 p2 p3 tp)
   (vl-load-com)
   (setq ole (getvar 'cmdecho))
   (setvar "cmdecho" 0)
   (vl-cmdf "_.undo" "_begin")

   (setvar "osmode" 37)
   (setq e1 (car (entsel "\nSelect the first line or polyline: "))
tp (cdr (assoc 0 (entget e1)))
   )
   (while (and (/= "LINE" tp) (/= "POLYLINE" tp) (/= "LWPOLYLINE" tp))
      (princ "\n  The object is NOT a line nor polyline")     
      (setq e1 (car (entsel "\nSelect the first line or polyline: "))
            tp (cdr (assoc 0 (entget e1)))
      )
   )
   (setq p1 (vlax-curve-getStartPoint (vlax-ename->vla-object e1)))
   (setq p2 (vlax-curve-getEndPoint (vlax-ename->vla-object e1)))
   (setq p3 (car (cdr (entsel "\nSelect the second line or polyline: "))))
   (if (equal T (LM:Collinear-p p1 p2 p3))
       (princ "\nThe elements are collinear ")
       (alert "Elements are NOT collinear")
   )
   
   (setvar "cmdecho" ole)
   (vl-cmdf "_.undo" "_end")
   (princ)
)

;; 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-4)
                (equal (+ b c) a 1e-4)
                (equal (+ c a) b 1e-4)
            )
        )
        (distance p1 p2) (distance p2 p3) (distance p1 p3)
    )
)

Stefan

  • Bull Frog
  • Posts: 319
  • The most I miss IRL is the Undo button
Re: Test if two lines are collinear (2D)
« Reply #4 on: September 08, 2022, 03:41:00 PM »
Almost certainly is a done deal, but I could not find it, I need to test if two lines are collinear (simple 2D test), I have found theese functions:
Is there an easier way passing directly the objects without extracting the start and end points?

I don't know if it's possible without any of the end points.
Here is a solution with only 2 extracted points.
Code - Auto/Visual Lisp: [Select]
  1. (defun collin (e1 e2)
  2.    '(lambda (p)
  3.       (equal p (vlax-curve-getclosestpointto e2 p T) 1e-8)
  4.     )
  5.     (list
  6.     )
  7.   )
  8. )

Well, there is an even simpler solution. The projection of a point on a line is unique, so you can check the projection of a random point on both lines.
Code - Auto/Visual Lisp: [Select]
  1. (defun collin1 (e1 e2)
  2.   (equal
  3.     (vlax-curve-getclosestpointto e1 '(0.0 0.0 0.0) T)
  4.     (vlax-curve-getclosestpointto e2 '(0.0 0.0 0.0) T)
  5.     1e-8
  6.   )
  7. )

While this might be sufficient, '(0.0 0.0 0.0) is a bad choice because the method fails if the 2 lines intersect at that exact point and (0.0 0.0) is kind of exposed to this error.
I think we can use another random point like EXTMIN or VIEWCTR or (list pi pi 0.0) which are more likely to work but errors are still not excluded.
« Last Edit: September 08, 2022, 07:17:55 PM by Stefan »


VovKa

  • Water Moccasin
  • Posts: 1630
  • Ukraine
Re: Test if two lines are collinear (2D)
« Reply #6 on: September 09, 2022, 03:46:59 PM »
what about vla-IntersectWith?

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Test if two lines are collinear (2D)
« Reply #7 on: September 11, 2022, 02:38:06 AM »
Hi,

My 2 cents (works in 3D):

Code - Auto/Visual Lisp: [Select]
  1. ;; gc:GetVector
  2. ;; Returns the vector from p1 to p2
  3. ;;
  4. ;; Arguments
  5. ;; p1, p2 : 2 points
  6. (defun gc:GetVector (p1 p2) (mapcar '- p2 p1))
  7.  
  8. ;; gc:CrossProduct
  9. ;; Returns the cross product (vector) of two vectors
  10. ;; Arguments
  11. ;; v1, v2 : two vectors
  12. (defun gc:CrossProduct (v1 v2)
  13.   (list (- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
  14.         (- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
  15.         (- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
  16.   )
  17. )
  18.  
  19. ;; gc:ColinearP
  20. ;; Evaluates if all points of the list are colinear
  21. ;;
  22. ;; Arguments
  23. ;; pts : a points list
  24. (defun gc:ColinearP (pts)
  25.   (or
  26.     (null (cddr pts))
  27.     (and
  28.       (equal
  29.         (gc:CrossProduct (gc:GetVector (car pts) (cadr pts)) (gc:GetVector (car pts) (caddr pts)))
  30.         '(0. 0. 0.)
  31.         1e-9
  32.       )
  33.       (gc:ColinearP (cdr pts))
  34.     )
  35.   )
  36. )

Edited: see Marco's relevant comment below
« Last Edit: September 11, 2022, 05:24:02 AM by gile »
Speaking English as a French Frog

ribarm

  • Gator
  • Posts: 3266
  • Marko Ribar, architect
Re: Test if two lines are collinear (2D)
« Reply #8 on: September 11, 2022, 03:08:22 AM »
Pretty fast written, so bluderlish...

Code - Auto/Visual Lisp: [Select]
  1. (gc:CrossProduct (gc:GetVector p1 p2) (gc:GetVector p1 p3))
  2.  

Code - Auto/Visual Lisp: [Select]
  1. (gc:CrossProduct (gc:GetVector (car pts) (cadr pts)) (gc:GetVector (car pts) (caddr pts)))
  2.  
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Test if two lines are collinear (2D)
« Reply #9 on: September 11, 2022, 05:24:48 AM »
Thanks Marco. Code corrected.
Speaking English as a French Frog

Stefan

  • Bull Frog
  • Posts: 319
  • The most I miss IRL is the Undo button
Re: Test if two lines are collinear (2D)
« Reply #10 on: September 11, 2022, 11:29:32 AM »
Hi Gile

If the second line starts where the first one ends, your lisp always return T. So, for every polygonal shape, any 2 consecutive segments are reported as collinear.

Code - Auto/Visual Lisp: [Select]
  1. (gc:ColinearP '((0.0 0.0 0.0) (1.0 1.0 0.0) (1.0 1.0 0.0) (2.0 1.0 0.0)))

One solution is to check the first 2 points against all the rest.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Test if two lines are collinear (2D)
« Reply #11 on: September 11, 2022, 01:24:17 PM »
Good point Stefan, thanks.
If the point list contains duplicated points, this one should work:
Code - Auto/Visual Lisp: [Select]
  1. (defun gc:ColinearP (pts / p0)
  2.   (setq p0 (car pts))
  3.     (function
  4.       (lambda (p1 p2)
  5.         (equal
  6.           (gc:CrossProduct (gc:GetVector p0 p1) (gc:GetVector p0 p2))
  7.           '(0. 0. 0.)
  8.           1e-9
  9.         )
  10.       )
  11.     )
  12.     (cdr pts)
  13.     (cddr pts)
  14.   )
  15. )

Now, regarding Marc'Antonio's request, ans assuming l1 and l2 are the line enames, it could be done like this:
Code - Auto/Visual Lisp: [Select]
  1. (defun ParallelLinesP (l1 l2)
  2.   (equal (gc:CrossProduct
  3.            (getpropertyvalue l1 "Delta")
  4.            (getpropertyvalue l2 "Delta")
  5.          )
  6.          '(0. 0. 0.)
  7.          1e-9
  8.   )
  9. )
  10.  
  11. (defun ColinearP (l1 l2)
  12.   (and (ParallelP l1 l2)
  13.        (equal (gc:CrossProduct
  14.                 (getpropertyvalue l1 "Delta")
  15.                 (gc:GetVector
  16.                   (getpropertyvalue l1 "StartPoint")
  17.                   (getpropertyvalue l2 "StartPoint")
  18.                 )
  19.               )
  20.               '(0. 0. 0.)
  21.               1e-9
  22.        )
  23.   )
  24. )
Speaking English as a French Frog


jamescalabut

  • Mosquito
  • Posts: 1
Re: Test if two lines are collinear (2D)
« Reply #13 on: October 03, 2022, 11:53:04 AM »
Hello,

I find it a bit easier this way.
If one point is on the same line of a segment, the difference between the distances from that point to both ends of the segment is precisely the segment's length.
If that happens for two points, then both points are on that line and describe a segment colinear with the given segment.

Code: [Select]
(defun c:pp()
(setq line1 (entget(car(entsel))))
(setq p11 (cdr(assoc 10 line1)))
(setq p12 (cdr(assoc 11 line1)))

(setq line2 (entget(car(entsel))))
(setq p21 (cdr(assoc 10 line2)))
(setq p22 (cdr(assoc 11 line2)))

(if (= (abs (- (distance p11 p21) (distance p12 p21))) (abs (- (distance p11 p22) (distance p12 p22)))) (princ "\yes") (princ "no"))
)