Find all points with the same Z coordinate on a 3D curve based on a specified point?

Find all points with the same Z coordinate on a 3D curve based on a specified point?

myloveflyer
Contributor Contributor
790 Views
9 Replies
Message 1 of 10

Find all points with the same Z coordinate on a 3D curve based on a specified point?

myloveflyer
Contributor
Contributor

Given a point P1, how can I find all points on a 3D curve with the same Z coordinate as P1?

0 Likes
Accepted solutions (3)
791 Views
9 Replies
Replies (9)
Message 2 of 10

myloveflyer
Contributor
Contributor

To achieve as attachment!

0 Likes
Message 3 of 10

vladimir_michl
Advisor
Advisor

Maybe through a combination of PLANESURF (at that level) and IMPRINT?

 

Vladimir Michl, www.arkance-systems.cz - www.cadforum.cz

 

0 Likes
Message 4 of 10

myloveflyer
Contributor
Contributor

How to achieve such a combination?

0 Likes
Message 5 of 10

john.uhden
Mentor
Mentor
Accepted solution

@myloveflyer 

Might you have a thing going with @leeminardi?  Nevermind.

This is not your entire solution, but a way to get there...

(defun @2d (p)(mapcar '+ p '(0 0)))
;; Given 2 3D points (say one at each end of a line or straight segment)
;; and a target Z value (elev. or level),
;; Find the point on the segment with an elev. of Z,
;;  or nil if Z is out of segment range:
(defun @findZ (p1 p2 Z / d dydx dzdx z1 z2 x y p)
  (setq d (distance (@2d p1)(@2d p2))
        dydx (/ (- (cadr p2)(cadr p1)) d)
        z1 (last p1) z2 (last p2)
        dzdx (/ (- Z2 Z1) d)
  )
  (if (or (<= z1 Z z2)(<= z2 Z z1))
    (setq dx (/ (- Z z1) dzdx)
          x (car (polar p1 (angle p1 p2) dx))
          y (+ (cadr p1)(* dx dydx))
          p (list x y Z)
    )
  )
)

You will have to work your way, segment by segment, finding if a Z value falls within the range of that segment.

If non-nil you could cons them to a list of all points found.

John F. Uhden

0 Likes
Message 6 of 10

Kent1Cooper
Consultant
Consultant

Copy the curve(s) in question at zero displacement [in place].  Maybe put the copy/copies on a different Layer and turn off the Layer of the original(s).  Go into a UCS that looks edgewise, e.g. with UCS ZAxis 0,0,0 1,0,0, and into PLAN view in that UCS.  Draw a horizontal LINE at the desired elevation [which will now be the Y coordinate value of the Line's ends], whether from the Point in question via NODe Object-Snap or just by typing in points with that Y value, or draw it at Y=0 and MOVE it in the Y direction.  You can TRIM the curve to that Line [or its extension in Edge-Extend mode], even if it does not actually intersect the curve in 3D, and use [presumably Osnap to] the resulting endpoint(s) for the location(s) where that curve crosses that elevation.  UCS Previous, restore Layer settings, etc.

Kent Cooper, AIA
0 Likes
Message 7 of 10

Kent1Cooper
Consultant
Consultant

@john.uhden wrote:

....

You will have to work your way, segment by segment, finding if a Z value falls within the range of that segment.

....


That's fine for something like a 3D Polyline, but they really meant the word "curve" in the Topic heading -- the sample drawing shows Splines, for which that approach would not work....  A tilted 2D or LWPolyline that contains any arc segment(s) will have the same problem.

Kent Cooper, AIA
0 Likes
Message 8 of 10

leeminardi
Mentor
Mentor
Accepted solution

Try the following,  It searches 100 segments (can be changed) of the spline  to see if the z coordinate is above and below the point for that segment.  If so, it uses the bisection method to determine the value of the spline parameter that yields the correct elevation within a given tolerance (0.01 default).  It then searches the remaining segments that may have the specified z value.   The program will find multiple solutions if they exist.

I decided to use parametric space rather than Euclidean space in the spline search as you will get finer detail in areas with small radius of curvature.  The program requires some tuning for splines with very erratic behavior where there may be more than one solution within the search segment.  If needed, the code could be enhanced to consider the spline degree and number of control vertices to set better values for the tolerance and segment size.    

leeminardi_0-1650914364029.png

 

 

;  finds the points on a spline that have the same z coordinate as a
;  specified point.
;  lrm  4/25/2022
;  Set tolerance for solution as needed. Default is 0.01
;  Set "nsegs" number of search segments as needed. Default is 100
; 
(defun c:test (/ pt z ent obj end1 end2 dt ta tb dt za zb zm tm)
  (setq tol   0.01
      nsegs   100
      pt    (getpoint "\nSpecify point with desired elevation.")
      Z	    (caddr pt)
      ent   (entsel "\nSelect spline")
      obj   (vlax-ename->vla-object (car ent))
      end1  (vlax-curve-getStartParam obj)
      end2  (vlax-curve-getEndParam obj)
      dt    (/ (- end2 end1) nsegs)
      ta    0 ; spline independent parameters
      tb    dt
)
(setq snp (getvar "osmode")
      setvar "osmode"   0
)
  (while (< tb end2)
    (Setq za (caddr (vlax-curve-getPointAtParam obj ta))
	  zb (caddr (vlax-curve-getPointAtParam obj tb))
	  tm (/ (+ ta tb) 2.0)
	  zm (caddr (vlax-curve-getPointAtParam obj tm))
    )
    (if	(> (* (- Z za) (- Z zb)) 0.0)	; find intervale with z change
      (progn
	(setq ta tb
	      tb (+ tb dt)
	      tt tb
	)
      )
      (progn
	(while (> (abs (- zm z)) tol)	; search interval
	  (if (> (* (- Z za) (- Z zm)) 0.0)
	    (progn
	      (setq ta tm
		    za zm
	      )
	    )
	    (progn
	      (setq tb tm
		    zb zm
	      )
	    )
	  )
	  (setq	tm (/ (+ ta tb) 2.0)
		zm (caddr (vlax-curve-getPointAtParam obj tm))
	  )
	)				; end search interval
	(setq ta tt
	      tb (+ tt dt)
	)
	(setq pm (vlax-curve-getPointAtParam obj tm))
	(command "_point" pm "")
      )
    )
  )
  (setvar "osmode" snp)
  (princ)
)

 

lee.minardi
Message 9 of 10

john.uhden
Mentor
Mentor
Accepted solution

@Kent1Cooper 

My apologies.

Speaking in terms of AutoLisp, lines, arcs, polylines, etc. are all curves.

Mine was stupidly verbose anyway.

Much shorter:

(defun @findZ2 (p1 p2 Z / z1 z2 p)
  (setq z1 (float (last p1)) z2 (float (last p2)))
  (if (or (<= z1 Z z2)(<= z2 Z z1))
    (setq ratio (/ (- Z z1)(- z2 z1))
          p (mapcar '* (list ratio ratio ratio)(mapcar '+ p1 p2))
    )
  )
)

John F. Uhden

0 Likes
Message 10 of 10

john.uhden
Mentor
Mentor

@leeminardi 

You are a frigging wizard!

I oughta take you as my navigator 'cause you'll analyze the wind direction ahead before it shifts.

Gotta get a boat bigger than a Sunfish.  How about an MC Scow?  Google it.  You'll land at Melges Brothers Boat Works in Zenda, Wisc.  I'd love to win the lottery and get my daughter an E Scow to race.  Talk about flying...

John F. Uhden

0 Likes