Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

to get intersection between a line and a 3dface

47 REPLIES 47
Reply
Message 1 of 48
devitg
6550 Views, 47 Replies

to get intersection between a line and a 3dface

In this dwg it is clear that the line intersect with the 3dface . Both the line and the 3dface have as method INTERSECTWITH So I use VLA-INTERSECTWITH and get this error message ; error: ActiveX Server returned an error: El índice no es válido Or index not valid Why do it happens so?? Thanks in advance
47 REPLIES 47
Message 2 of 48
Anonymous
in reply to: devitg

this returns -1, which means the safearray is empty, hence the error

(setq obj1 (vlax-ename->vla-object (car (entsel "\nPick first object: ")))
      obj2 (vlax-ename->vla-object (car (entsel "\nPick object to Intersect: ")))
      )
  (vlax-safearray-get-u-bound
    (vlax-variant-value (vla-intersectwith obj1 obj2 acExtendNone)) 1)

 

I wish I could explain why it is empty.

 

You can find the intersection point using the Cal command with the expression ILP(end,end,end,end,end)

pick 2 endpoints of the line and 3 endpoints of the plane

 

Message 3 of 48
devitg
in reply to: Anonymous

I will test with the at least 2 possible 3 points planes from a 4 points 3dface, or just the 3 points , case the 3dface has 3 poiints Thanks for the tip.
Message 4 of 48
Anonymous
in reply to: devitg

I don't think the expression ILP will accept anything but 5 points (I may be wrong)

 

just goofing around...

 

 

(setq ln (entget (car (entsel "\nPick line: ")))
      fc (entget (car (entsel "\nPick face: ")))
      p1 (cdr (assoc 10 ln))
      p2 (cdr (assoc 11 ln))
      p3 (cdr (assoc 10 fc))
      p4 (cdr (assoc 11 fc))
      p5 (cdr (assoc 12 fc))
      )
(cal "ILP(p1,p2,p3,p4,p5)")

 

 

 

Message 5 of 48
_gile
in reply to: Anonymous

Hi,

 

ILP will return the intersection point between the line and the plane defined by three points, but won't evaluate if the intersection point is inside the triangle.

 

Here're some vector calculus routine which can be used for this task.

 

 

;; DotProduct (gile)
;; Returns the dot product (scalar product) of two vectors
;;
;; Arguments: two vectors

(defun DotProduct (v1 v2) (apply '+ (mapcar '* v1 v2)))

;; CrossProduct (gile)
;; Returns the cross product of two vectors
;;
;; Arguments: two vectors

(defun CrossProduct (v1 v2)
  (list	(- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
	(- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
	(- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
  )
)

;; Normalize (gile)
;; Returns the single unit vector of a vector
;;
;; Argument: a vecteur

(defun Normalize (v)
  ((lambda (l)
     (if (/= 0 l)
       (mapcar (function (lambda (x) (/ x l))) v)
     )
   )
    (distance '(0 0 0) v)
  )
)

;; Normal3points (gile)
;; Returns the normal vector of the plane defined by 3 points
;;
;; Arguments: three points

(defun Normal3points (p0 p1 p2)
  (Normalize (CrossProduct (mapcar '- p1 p0) (mapcar '- p2 p0)))
)

;; IntersectLinePlane (gile)
;; Returns the intersection point between an unbounded line and a plane
;;
;; Arguments
;; p1 p2: two points defining the line
;; org: a point on the plane
;; nor: the plane normal vector

(defun ilp (p1 p2 org nor / scl)
  (if (and
	(/= 0 (setq scl (DotProduct nor (mapcar '- p2 p1))))
	(setq scl (/ (DotProduct nor (mapcar '- p1 org)) scl))
      )
    (mapcar (function (lambda (x1 x2) (+ (* scl (- x1 x2)) x1)))
	    p1
	    p2
    )
  )
)

;; IsInTriangle (gile)
;; Evaluates if a point is in side (or on) a triangle
;;
;;Arguments
;; pt: the point to evaluate
;; p1 p2 p3: three points defining the triangle

(defun IsInTriangle (pt p1 p2 p3)
  ((lambda (n1 n2 n3)
     (or
       (and (equal n1 n2 1e-9) (equal n2 n3 1e-9))
       (null n1)
       (null n2)
       (null n3)
     )
   )
    (Normal3points pt p1 p2)
    (Normal3points pt p2 p3)
    (Normal3points pt p3 p1)
  )
)

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 48
devitg
in reply to: _gile

for this data (setq p1 '( 0 0 100 )) (setq p2 '(0 0 200)) (setq p3 '( 100 100 0)) (setq p4 '( 50 100 0)) (setq p5 '( 200 100 0)) (Setq ach (c:cal "ilp(p1,p2,p3,p4,p5)")); ILP return NIL (0 0 100) (0 0 200) (100 100 0) (50 100 0) (200 100 0) nil But for this other data (setq p1 '( 0 0 100 )) (setq p2 '(0 0 200)) (setq p3 '( -100 100 0)) (setq p4 '( 50 -100 0)) (setq p5 '( 200 100 0)) (Setq ach (c:cal "ilp(p1,p2,p3,p4,p5)")); ILP return (0.0 0.0 0.0) But at any case the LINE "true" intersects the plane , so the ILP can not be used. Iwill try GILE's way
Message 7 of 48
_gile
in reply to: devitg

devtig,

The points (100 100 0) (50 100 0) (200 100 0) *doesn't* define a plane because they're colinear. That's why ILP returns nil.

 

Here's another LISP function which require 5 points.

 

 

;; IntersectLine3PtsPlane
;; Returns the intersection point between a line defined by p1 p2
;; and a plane defined by p3 p4 p5
;;
;; Arguments
;; p1 p2 : two points defining the line
;; p3 p4 p5 : three points defining the plane

(defun IntersectLine3PtsPlane (p1 p2 p3 p4 p5 / x1 y1 z1 x2 y2	z2 x3 y3 z3 x4 y4 z4 x5
		y5 z5 xn yn zn sc pt)
  (mapcar 'set
	  '(x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4 x5 y5 z5)
	  (append p1 p2 p3 p4 p5)
  )
  (setq	xn (- (* (- y4 y3) (- z5 z3)) (* (- y5 y3) (- z4 z3)))
	yn (- (* (- z4 z3) (- x5 x3)) (* (- z5 z3) (- x4 x3)))
	zn (- (* (- x4 x3) (- y5 y3)) (* (- x5 x3) (- y4 y3)))
  )
  (if (not
	(zerop
	  (setq
	    sc (+ (* xn (- x2 x1)) (* yn (- y2 y1)) (* zn (- z2 z1)))
	  )
	)
      )
    (setq sc (/	(+ (* xn (- x1 x3)) (* yn (- y1 y3)) (* zn (- z1 z3)))
		sc
	     )
	  pt (list
	       (+ (* sc (- x1 x2)) x1)
	       (+ (* sc (- y1 y2)) y1)
	       (+ (* sc (- z1 z2)) z1)
	     )
    )
  )
)

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 48
devitg
in reply to: _gile

Hi gile , please note that my original post subject was , and still is to get intersection between a line and a 3dface When I put the points p1 to p5 , was to state the line's and 3dface's points , i made a mistake not to notice thy where in a row Yours "IntersectLine3PtsPlane" only return nil if both z's lines are equal , and also if both Z's are 0 and the plane have it's 3 z=0 , so the line is parallel to the plane. For any other case , when Z's are unequal it will give a point , disregard it do "inside" or not the triangle defined by the p3 p4 p5 points. Both the ILP from c:cal and yours "IntersectLine3PtsPlane" work the same way. I still need to know if the line do really pass trough the 3dface.
Message 9 of 48
Kent1Cooper
in reply to: devitg

Another way to evaluate things, which could make certain parts a lot easier, is from the point of view of the Plane as the definer of a User Coordinate SystemTo determine whether and where a [virtual] Line defined by two points [p1, p2] intersects a [virtual] Plane defined by three points [pA, pB, pC], you can do this:

 

(command "_.ucs" "_new" "_3point" pA pB pC)

 

[or by the UCS Object option if the User is to select a 3DFace].  Then:

 
(setq
  p1p (trans p1 0 1) ; Line's endpoints relative to Plane coordinates
  p2p (trans p2 0 1)
  p1pZ (caddr p1p) ; their Z coordinates relative to the Plane
  p2pZ (caddr p2p)
)

 

Then you can easily determine, first of all, whether the Line is completely off the Plane:
 

(and ; Z coordinates on the same side of, and neither on, the Plane
  (= (minusp p1pZ) (minusp p2pZ))
  (not (zerop p1pZ))
  (not (zerop p2pZ))
); end and

 

If that's the case, there's no need to go further.  If not, you can find the intersection of the Line and the Plane [or its extension], in the Plane's coordinates, this way:

 

(mapcar '+
  p1p
  (mapcar
    '(lambda (c)
      (* c (/ p1pZ (+ p1pZ (- p2pZ))))
    ); end lambda
    (mapcar '- p2p p1p); 'delta' of Line
  ); end mapcar/lambda
); end mapcar +
 

Then you can check whether that falls inside the triangle, in various ways depending on whether on the edge should count.  Those checks should also be made simpler by the fact that pA is 0,0,0 in the Plane's coordinates.  A few comparative angles and/or distances should tell the story.

 

But if you're getting the Plane from a selected 3DFace, might it have 4 sides?  That wouldn't affect any of the above except that it could complicate the calculation of whether the intersection point is inside the 3DFace.  [Oh, and 4-sided 3DFaces don't necessarily need to be planar, so that introduces another possible complication.]

Kent Cooper, AIA
Message 10 of 48
_gile
in reply to: devitg

Hi,

 

Both ILP and IntersectLinePlane should return nil while or:

- p1 and p1 are equal (no line defined)

- p3, p4 and p5 are colinear (no plane defined)

- the line and the plane ar parallel (or coplanar)

 

Try the 'IntersLineTriangle' which deals with any case (i expect...)

 

 

;; DotProduct (gile)
;; Returns the dot product (scalar product) of two vectors
;;
;; Arguments: two vectors

(defun DotProduct (v1 v2) (apply '+ (mapcar '* v1 v2)))

;; CrossProduct (gile)
;; Returns the cross product of two vectors
;;
;; Arguments: two vectors

(defun CrossProduct (v1 v2)
  (list	(- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
	(- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
	(- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
  )
)

;; Normalize (gile)
;; Returns the single unit vector of a vector
;;
;; Argument: a vecteur

(defun Normalize (v)
  ((lambda (l)
     (if (/= 0 l)
       (mapcar (function (lambda (x) (/ x l))) v)
     )
   )
    (distance '(0 0 0) v)
  )
)

;; Normal3points (gile)
;; Returns the normal vector of the plane defined by 3 points
;;
;; Arguments: three points

(defun Normal3points (p0 p1 p2)
  (Normalize
    (CrossProduct (mapcar '- p1 p0) (mapcar '- p2 p0))
  )
)

;; IntersectLinePlane (gile)
;; Returns the intersection point between an unbounded line and a plane
;;
;; Arguments
;; p1 p2: two points defining the line
;; org: a point on the plane
;; nor: the plane normal vector

(defun IntersectLinePlane (p1 p2 org nor / scl)
  (if (and
	(/= 0 (setq scl (DotProduct nor (mapcar '- p2 p1))))
	(setq scl (/ (DotProduct nor (mapcar '- p1 org)) scl))
      )
    (mapcar (function (lambda (x1 x2) (+ (* scl (- x1 x2)) x1)))
	    p1
	    p2
    )
  )
)

;; IsOnSegemnt
;; Evaluates if a point lies on a segemnt
;;
;; Arguments
;; pt: the point to evaluate
;; p1 p2: the points defining the segment

(defun IsOnSegment (pt p1 p2)
  (or (equal pt p1 1e-9)
      (equal pt p2 1e-9)
      (equal (Normalize (mapcar '- pt p1))
	     (Normalize (mapcar '- p2 pt))
	     1e-9
      )
  )
)

;; IntersLineTriangle
;; Returns the intersection point between line and a triangle (or nil)
;; Displays a message
;;
;; Arguments
;; p1 p2: two points defining an unbounded line
;; p3 p4 p5 three points defining a triangle

(defun IntersLineTriangle (p1 p2 p3 p4 p5 / n0 n1 n2 n3 dir p lst)
  (setq n0 (Normal3points p3 p4 p5))
  (if n0
    (if	(setq pt (IntersectLinePlane p1 p2 p3 n0))
      (progn
	(setq n1 (Normal3points pt p3 p4)
	      n2 (Normal3points pt p4 p5)
	      n3 (Normal3points pt p5 p3)
	)
	(if (and (equal n1 n2 1e-9) (equal n2 n3 1e-9))
	  (princ "\nThe line intersect inside the triangle at: ")
	  (if (or (null n1) (null n2) (null n3))
	    (princ "\nThe line intersect a triangle edge at: ")
	    (princ
	      "\nThe line intersect the plane outside the triangle at: "
	    )
	  )
	)
      )
      (if
	(and
	  (equal (caddr (trans p1 0 n0)) (caddr (trans p3 0 n0)) 1e-9)
	  (equal (caddr (trans p1 0 n0)) (caddr (trans p3 0 n0)) 1e-9)
	)
	 (progn
	   (princ "\nThe line and the triangle plane are coplanar,")
	   (setq dir (Normalize (mapcar '- p2 p1)))
	   (if (setq p (inters p1 p2 p3 p4 nil))
	     (setq lst (cons p lst))
	     (if
	       (or
		 (equal	(mapcar '- p3 p1)
			(mapcar '(lambda (x) (* x (distance p1 p3))) dir)
			1e-9
		 )
		 (equal	(mapcar '- p1 p3)
			(mapcar '(lambda (x) (* x (distance p1 p3))) dir)
			1e-9
		 )
	       )
		(progn
		  (princ "\nand the line is colinear to p3 p4 ")
		  (setq pt (list p3 p4))
		)
	     )
	   )
	   (if (setq p (inters p1 p2 p4 p5 nil))
	     (setq lst (cons p lst))
	     (if
	       (or
		 (equal	(mapcar '- p4 p1)
			(mapcar '(lambda (x) (* x (distance p1 p4))) dir)
			1e-9
		 )
		 (equal	(mapcar '- p1 p4)
			(mapcar '(lambda (x) (* x (distance p1 p4))) dir)
			1e-9
		 )
	       )
		(progn
		  (princ "\nand the line is colinear to p4 p5 ")
		  (setq pt (list p4 p5))
		)
	     )
	   )
	   (if (setq p (inters p1 p2 p5 p3 nil))
	     (setq lst (cons p lst))
	     (if
	       (or
		 (equal	(mapcar '- p5 p1)
			(mapcar '(lambda (x) (* x (distance p1 p5))) dir)
			1e-9
		 )
		 (equal	(mapcar '- p1 p5)
			(mapcar '(lambda (x) (* x (distance p1 p5))) dir)
			1e-9
		 )
	       )
		(progn
		  (princ "\nand the line is colinear to p1 p5 ")
		  (setq pt (list p1 p5))
		)
	     )
	   )
	   (if lst
	     (progn
	       (princ "\nand the line intersect the triangle at: ")
	       (setq pt	(if (cadr lst)
			  lst
			  (car lst)
			)
	       )
	     )
	   )
	   (if (null pt)
	     (princ "\nand do not intersect the triangle.")
	   )
	 )
	 (princ
	   "\nThe line and the triangle plane are parallel, no intersection"
	 )
      )
    )
    (progn
      (princ
	"\np3 p4 p5 are colinear, they define a line, not a plane"
      )
      (if (or (setq pt (inters p1 p2 p3 p4 nil))
	      (setq pt (inters p1 p2 p4 p5 nil))
	      (setq pt (inters p1 p2 p5 p3 nil))
	  )
	(if (or	(IsOnSegment pt p3 p4)
		(IsOnSegment pt p3 p4)
		(IsOnSegment pt p3 p4)
	    )
	  (princ
	    "\nThe line intersect an edge of the 'flat triangle' at: "
	  )
	  (princ
	    "\nThe line intersect the p3 p4 p5 line outside the 'flat triangle' at: "
	  )
	)
      )
    )
  )
  pt
)

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 48
Kent1Cooper
in reply to: devitg

devitg wrote:

 

In this dwg it is clear that the line intersect with the 3dface . Both the line and the 3dface have as method INTERSECTWITH So I use VLA-INTERSECTWITH and get this error message ; error: ActiveX Server returned an error: El índice no es válido Or index not valid Why do it happens so??....

 

Your drawing is too new for me to open, but could it be that the Line penetrates through the 3DFace but does not intersect one of its edges?  In that case, I don't get the message you describe, but I get a nil return, so the IntersectWith method won't find that kind of "intersection" -- it needs the Line and an edge of the 3DFace to touch.

Kent Cooper, AIA
Message 12 of 48
devitg
in reply to: _gile

Hi Gile, thanks for yours effort. I will try it. Gabriel
Message 13 of 48
devitg
in reply to: Kent1Cooper

Hi Kent , that is the case when the line penetrates through the 3dface or not , Gile give me a good wayy to check it. What acad do you handle?
Message 14 of 48
Kent1Cooper
in reply to: devitg


@devitg wrote:
Hi Kent , that is the case when the line penetrates through the 3dface or not , Gile give me a good wayy to check it. What acad do you handle?

I'm stuck back in the 2004 version, but I don't think there's any need for you to repost the drawing.

 

Here's a routine using the align-the-UCS approach, complete with command name, error handling, object-selection controls, etc.  Load it up, type LIF [for Line Intersect Face], and select a Line and a 3DFace.

 

It could easily be adjusted to change the feedback it gives, for example to say where outside the 3DFace the Line crosses its plane, or whether a Line that's co-planar with the 3DFace is wholly or partly inside it [not really necessary, since if they're co-planar, you can easily see how they relate], or other things you might want.

 

It does not localize its 'intw' variable [for INTersection point in World coordinates], so you can use that in something else if you want.

Kent Cooper, AIA
Message 15 of 48
devitg
in reply to: Kent1Cooper

Hi Kent, thanks for it I will check it later.
Message 16 of 48
Anonymous
in reply to: Kent1Cooper

Hi Kent ! help me! how to get intersection between a 2D-Plolyline ( with elevation) and a 3Dface

Message 17 of 48
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

Hi Kent ! help me! how to get intersection between a 2D-Plolyline ( with elevation) and a 3Dface


It would probably involve the same sort of routine, setting the UCS to match the 3Dface, and checking Polyline vertices for whether their translated Z coordinates are positive or negative.  If two adjacent vertices have opposite Z signs, then the segment between them crosses the plane of the 3Dface, and its intersection with it could be similarly calculated.

 

Might such a 2D Polyline intersect the 3Dface more than once?  Might a 3Dface ever have 4 sides, and not be planar?

Kent Cooper, AIA
Message 18 of 48
Anonymous
in reply to: Kent1Cooper

2D Polyline intersect the 3Dface more than once.

I'm interested in: 3dfface perpendicular to the Oxy

Message 19 of 48
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

2D Polyline intersect the 3Dface more than once.

I'm interested in: 3dfface perpendicular to the Oxy


A little more information would be helpful.

 

I don't know what "the Oxy" means, but maybe that doesn't matter.

 

Would the User select a Polyline and a 3Dface, and the routine say whether that Polyline crosses that 3Dface perpendicularly?

 

Would the User select a Polyline, and the routine find the 3Dface, possibly from among several, that it crosses perpendicularly?

 

Would the User select a 3Dface, and the routine find the Polyline, possibly from among several, that crosses it perpendicularly?

 

Or something else?

Kent Cooper, AIA
Message 20 of 48
Anonymous
in reply to: _gile

Well, i test the Gile's option and i have to do some corrections to obtain the intersection but there are cases where don't give me the intersection and returns nil, if the point is at the edge of the 3dface, i debugged and the pt gets the intersection correct but at the line: (if (or (null n1) (null n2) (null n3))
(princ "\nThe line intersect a triangle edge at: "), n1 , n2  and n3 are no null but the intersection is on the edge of the 3dFace...and returns nil

Why? 

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost