roy437 Posted December 10, 2019 Posted December 10, 2019 For a 2d / 3d curve, how to calculate 10,000 values (for example) x, y / x, y, z at a given step x, in autolisp. Quote
Lee Mac Posted December 10, 2019 Posted December 10, 2019 Use the vlax-curve-getpointatdist or vlax-curve-getpointatparam function, supplied with your entity name and a given distance or parameter value. Quote
BIGAL Posted December 11, 2019 Posted December 11, 2019 Better to go to the mathematical formula, so provide that. Your request is to vauge and 10,000 points big number. Explain more. Quote
roy437 Posted December 11, 2019 Author Posted December 11, 2019 I have a 3d curve in autocad from x = 108 to x = 12064. I would like to calculate y, z for x = 108, 110, 112, 114,........12064, with dx = 2. Quote
BIGAL Posted December 12, 2019 Posted December 12, 2019 You still need to explain more for any one here to help, at least an image of the curve. Quote
dlanorh Posted December 12, 2019 Posted December 12, 2019 Also, what do you want to do with the calculated values? Quote
lrm Posted December 12, 2019 Posted December 12, 2019 If the curve is an AutoCAD spline then it's a NURBS (non-uniform rational B-spline). If you have not changed the weighing factors of the spline's CVs (they all equal 1) then it can be represented as a B-spline. The attached Excel/VBA macro-enable file includes a B-spline function that I programmed to help me get a better understanding of splines. It will duplicate the curve AutoCAD creates given the same set of CVs. You could use its BSpline function to generate as many points along the spline as you wish. To get 10000 points use an increment of ((number_of_CVs) - degree)/ 10000 for u. The function has three arguments: BSpline(u, degree, CVs) u = the independent parametric variable of the spline degree is of course the degree of the spline. The default value in AutoCAD is 3 CVs is an array of the coordinates of the control vertices (x, or y, or z) How many CVs are in your curve? Lee B-Spline-Calculator-degn.xlsm 1 Quote
BIGAL Posted December 12, 2019 Posted December 12, 2019 Sounds like a curve drawn on a tilted plane and wants the 3d answers on world co-ords. Which is not a true arc but like lrm a spline. Have a look at "The Opera House Sydney" Quote
hanhphuc Posted December 12, 2019 Posted December 12, 2019 The steps dx=2 in 3D or 2D? 19 hours ago, roy437 said: I have a 3d curve in autocad from x = 108 to x = 12064. I would like to calculate y, z for x = 108, 110, 112, 114,........12064, with dx = 2. Quote
roy437 Posted December 12, 2019 Author Posted December 12, 2019 On 12/10/2019 at 8:45 PM, Lee Mac said: Use the vlax-curve-getpointatdist or vlax-curve-getpointatparam function, supplied with your entity name and a given distance or parameter value. Thanks Lee Here's my code, where I used the bisection method. I am waiting for a point of view from you. (defun c:fx( / a b c curve-obj delim dx ent eps fil lc name_file nd p pe ps x x0 xe xs ) ; ; Input data ;--------------------------------------------------- (setq nd 6 ; number of digits decimal eps 0.000001 delim " " ; space, tab or comma dx (getreal "\nIncrement dx : ") name_file (getstring "\nOut file : ") ent (car (entsel)) ; select curve ) ;--------------------------------------------------- (setq fil (open (strcat (getvar "DWGPREFIX") name_file) "w") curve-Obj (vlax-ename->vla-object ent) ps (vlax-curve-getStartPoint curve-Obj) pe (vlax-curve-getEndPoint curve-Obj) lc (vlax-curve-getdistatparam curve-Obj (vlax-curve-getendparam curve-Obj)) a 0.0 b lc xs (car ps) xe (car pe) x0 (+ xs dx) x xe ) (write-line (strcat (rtos xs 2 nd) delim (rtos (cadr ps) 2 nd) delim (rtos (caddr ps) 2 nd)) fil) (while (< x0 xe) ; Bisection method ;----------------------------------------------------- (while (> (abs (- x x0)) eps) (setq c (* 0.5 (+ a b)) p (vlax-curve-getPointAtDist curve-Obj c) x (car p) ) (if (> x x0) (setq b c) (setq a c)) ) ;----------------------------------------------------- (write-line (strcat (rtos x0 2 nd) delim (rtos (cadr p) 2 nd) delim (rtos (caddr p) 2 nd)) fil) (setq x0 (+ x0 dx) a (vlax-curve-getDistAtPoint curve-Obj p) b lc ) ) (write-line (strcat (rtos xe 2 nd) delim (rtos (cadr pe) 2 nd) delim (rtos (caddr pe) 2 nd)) fil) (close fil) (princ) ) Quote
BIGAL Posted December 13, 2019 Posted December 13, 2019 Forget code show us a picture with out that we have no idea what it is your trying to do. Quote
lrm Posted December 14, 2019 Posted December 14, 2019 I now see what you want to do. In short you a searching for the spline's parametric value that corresponds to a specific value of x. Your program appears to work well assuming that the spline is a monotonic function in x. If there are multiple points on the spline for a value of x you will only get one of them. If the spline swings out before the beginning of the spline or beyond it the points on these sections will not be determined (of course this cannot happen for monotonic functions). I suggest you add a counter in the while loop of the bisection code to limit the number of iterations to converge to a solution to avoid the potential of the program hanging. I would also suggest adding a message at the end stating that the program is finished and state the complete path and filename of the output file. Nice code. lrm (a.k.a. Lee M. but not Lee Mac!) Quote
marko_ribar Posted December 14, 2019 Posted December 14, 2019 (edited) I agree with lrm for what he stated, but then again, I don't know what method to suggest you that is fast enough and that covers those issues lrm mentioned... Maybe one that is not so slow but the code should be bigger : 1. You flatten your 3D curve 2. You construct XLINE with point at relative X coordinate 0.0 and with direction (0.0 1.0 0.0) - X coordinate must be smallest one - so suggested method of finding this point is by using (vlax-curve-getclosestpointtoprojection curve '(-1e+99 -1e+99 0.0) '(0.0 1.0 0.0)) 3. You find intersection point of XLINE and flattened curve (there may be more than 1) 4. You construct XLINE from intersection point(s) you found in step 3. with direction (0.0 0.0 1.0) 5. You find intersection point(s) of XLINE from step 4. and your curve in 3D 6. You remove both helper XLINES and repeat from step 2. with point at relative X coordinate incremented for dx You loop 2-6 all until no intersection points found in step 3. Some notes I spot in your posted code (defun c:fx( / ... ) ... ) should actually be (defun c:fx ( / ... ) ... ) - note space char after fx and ( To improve speed of computation, you don't need to use curve-Obj as 'VLA-OBJECT - (vlax-curve-xxx) functions operate as well and faster also with 'ENAME type variables - so no need line (setq curveObj (vlax-ename->vla-object ent)) - just change it to (setq curveObj ent)... How will you flatten 3D curve and to remain its accuracy with real curve is up to you, but you can try command PROJECTGEOMETRY and choose XY plane for projection... At least you'll know you tried it... M.R. Edited December 14, 2019 by marko_ribar Quote
lrm Posted December 15, 2019 Posted December 15, 2019 If you are concerned about the speed of execution one thing you could easily change is to remove the write statements and instead store the results in an array and then do one write to a file at the end of the program. The jumping between lisp execution and file writing is time consuming. It's better to limit how often that is done. It would be interesting to see the average of how many iterations are needed to converge to a solution in the bisection loop for each value of x. Usually a Newton Raphson numerical algorithm will converge faster than the simple bisection method but I don't see how to use it efficiently in this case. Quote
SEANT Posted December 15, 2019 Posted December 15, 2019 As related to Marko’s ‘flatten’ suggestion, the 3d Curve could be linearized. Copy the 3d Curve. Step through every control point and remove the Y and Z components. The resultant spline (probably even 3d Poly) will be a straight curve aligned to the X axis. More importantly, it will have the same parametric span as the original. On that straight curve use vlax-curve-getParamAtDist for a desired X location. Take that parametric value and evaluate the 3d curve via vlax-curve-getPointAtParam to retrieve the Y and Z components. Quote
SEANT Posted December 15, 2019 Posted December 15, 2019 Here is an example of the 3d to 1d curve - upon which my theory can be tested with the VLAX functions. EqualParam.dwg 1 Quote
marko_ribar Posted December 15, 2019 Posted December 15, 2019 I think that SEANT approach may be bingo for monotonic 3d curves, but still I'd rather suggest you using flattening to 2d - this way you are loosing only 1 dimension (remove all z components)... Because of loosing 2 dimensions like SEANT suggested, his method may fail with curves like HELIX or similar... Thanks for attention... M.R. Quote
BIGAL Posted December 15, 2019 Posted December 15, 2019 (edited) My $0.05 not sure about how fast but a pretty simple method and as we want in terms of x axis is if you draw a vertical line crossing the 3dpline you can trim it and get the xyz of endpoint. Using Seant equalparam.dwg need to get last 3 values of controlpoints. I just did plan and moved green line I have not done the x y translation so line end is 0,0. Testing now tried to upload GIF not working. tested on 2000 steps still fast. (defun getend (lstxyz / ) (setq x (- (length lstxyz) 1 )) (setq z (nth x lstxyz)) (setq y (nth (- x 1) lstxyz)) (setq x (nth (- x 2) lstxyz)) (setq xy (list x y)) (setq lst2 (cons (list x y z) lst2)) ) (defun c:test ( ) (setq oldsnap (getvar 'osmode)) (setq lst2 '()) (setvar 'orthomode 1) (setq p3 (getpoint "\nPick start of X line")) (setq p1 (getpoint "\npick point 1 end X line ")) (setq xl1 (car p1)) (setq y1 (cadr p1)) (setq p2 (getpoint p1 "\npick point 2 ")) (setq y2 (cadr p2)) (setvar 'osmode 0) (setq len (distance p1 p3)) (setq diff (/ len 20.0)) (setq obj (vlax-ename->vla-object (car (entsel "\npick object ")))) (repeat (- (fix (/ len diff)) 1) (setq lst (vlax-get Obj 'controlpoints)) (getend lst) (setq xl1 (- xl1 diff)) (setq p1 (list xl1 y1)) (setq p2 (list xl1 y2)) (command "line" p1 p2 "") (command "trim" (entlast) "" xy "") (command "erase" (entlast) "") ) (setq lst2 (cons (list (nth 0 lst)(nth 1 lst)(nth 2 lst)x y z) lst2)) (setvar 'osmode oldsnap) (princ lst2) (princ) ) (c:test) Edited December 15, 2019 by BIGAL Quote
Recommended Posts
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.