Message 1 of 10
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Given a point P1, how can I find all points on a 3D curve with the same Z coordinate as P1?
Solved! Go to Solution.
Given a point P1, how can I find all points on a 3D curve with the same Z coordinate as P1?
Solved! Go to Solution.
To achieve as attachment!
Maybe through a combination of PLANESURF (at that level) and IMPRINT?
Vladimir Michl, www.arkance-systems.cz - www.cadforum.cz
How to achieve such a combination?
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
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.
@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.
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.
; 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)
)
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
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