zwonko Posted February 28 Posted February 28 Working in bridge engineering so often must to draw cone batters (slope-lines for cone). Tried to make it but something is not ok. The main thing us that batters are not in the equal lenghts. Everything is in attached DWG (and also screen). Code below: (defun c:cone_batter (/ ent1 ent2 pline i pt1 pt2 pt3 dist sset1 ent2 sd slo new_ent new_ent2 elev len1 len2 n_bat point intersection all_entities newpoints) (setq point (getpoint "\n Select cone center point (top): ")) (setq ent1 (car (entsel "\n Select a TOP polyline: "))) (setq ent2 (car (entsel "\n Select a BOTTOM polyline: "))) (setq n_bat (getint "\n How many batter tics: ")) ;(setq elev (vla-get-Elevation (vlax-ename->vla-object ent))) ; read the elevation of the polyline (setq i 0) ; reset i at the start of each iteration (setq len1 (vlax-curve-getdistatparam ent1 (vlax-curve-getendparam ent1))) (princ "\n") (princ len1) (setq len2 (vlax-curve-getdistatparam ent2 (vlax-curve-getendparam ent2))) (princ "\n") (princ len2) (princ "\n") (princ n_bat) (princ "\n") (princ (/ 1 (float n_bat))) (setq all_entities (ssadd)) ; Initialize the list of all entities (setq newpoints nil) ; Initialize the list of intersection points (repeat (+ n_bat 1) (setq pt1 (vlax-curve-getPointAtParam ent1 (* (vlax-curve-getendparam ent1) (* i (/ 1 (float n_bat)))))) ; get the point at each 1/10 of the polyline (princ "\n") (princ pt1) (setq pt2 (vlax-curve-getPointAtParam ent2 (* (vlax-curve-getendparam ent2) (* i (/ 1 (float n_bat)))))) ; get the point at each 1/10 of the polyline (princ "\n") (princ pt2) (entmake (list (cons 0 "LINE") (cons 10 point) (cons 11 pt2) ) ) ;entmake end (princ "\n created center to end line") (ssadd (entlast) all_entities) (setq intersection (vla-IntersectWith (vlax-ename->vla-object ent1) (vlax-ename->vla-object (entlast)) acExtendThisEntity)) (princ "\n intersection found") (setq intersection (vlax-safearray->list (vlax-variant-value intersection))) (princ "\n") (princ intersection) (princ "\n") (entmake (list (cons 0 "LINE") (cons 10 intersection) (cons 11 pt2) ) ) ;entmake end (setq i (+ i 1)) ) ; Delete all entities created in the loop (princ "\n now trying to delete") (sssetfirst nil all_entities) (princ "\n now trying to delete") (if all_entities (command "_.Erase" all_entities "")) (princ "\n after delete") ) cone_batter.dwg Quote
lrm Posted February 28 Posted February 28 (edited) Trimming each segment shows that the arc length for each segment is the same. The second segment is composed of two arcs. Add them together and you get 1106.6 Edited February 28 by lrm Quote
zwonko Posted February 28 Author Posted February 28 Yes, but You took part which is hand made with divide command. Not by lisp, which is in step2 rectangle. Quote
devitg Posted February 28 Posted February 28 19 minutes ago, zwonko said: Yes, but You took part which is hand made with divide command. Not by lisp, which is in step2 rectangle. @zwonko, but it can be divide by LISP too and as any cada operation is made in order , the divide shall place point in consequents handle. (vl-cmdf "divide" ent1 n_bat ) (vl-cmdf "divide" ent2 n_bat ) Then by the polyline bounding box it can get the points by ssget Window Let me try By the way, where are you now?, I'm at Cordoba ARGENTINA Quote
devitg Posted February 28 Posted February 28 @zwonko please try it 1 cone_batter.dwg battline by devitg.LSP 1 Quote
lrm Posted February 28 Posted February 28 (edited) @zwonko The function vlax-curve-getPointAtParam does not increase linearly with respect to distance if the curve does not have a constant radius. SInce your polyline has more than one arc segment and they are of different radii you should not be computng the interval in parametric space. Use vlax-curve-getPointAtDist instead. Edited February 28 by lrm 1 Quote
zwonko Posted February 29 Author Posted February 29 (edited) 11 hours ago, devitg said: please try it Thanks @devitg - it is working. But the question is - if it will work if there will be other points near cone polylines? 12 hours ago, devitg said: By the way, where are you now?, I'm at Cordoba ARGENTINA Poland. 9 hours ago, lrm said: Use vlax-curve-getPointAtDist instead. Will try it - If I will get it, I will share here. Could someone explain the difference between vlax-curve-getPointAtParam and vlax-curve-getPointAtDist . Of course that one works on parameter other one in distance but thouht the results will be same. For example: (lenght_at_end - lenght_at-start ) / 3 and (parameter_at_end - parameter_at-start ) / 3 should give same result point. Edited February 29 by zwonko Quote
zwonko Posted February 29 Author Posted February 29 That will be the code for bridge cone which is working: (defun c:slope-line-cone-bridge (/ ent1 ent2 pline i pt1 pt2 pt3 dist sset1 ent2 sd slo new_ent new_ent2 elev len1 len2 n_bat point intersection all_entities newpoints ticks curlayer) (command "undo" "m") (setq curlayer (getvar "clayer")) (if(not(tblsearch "LAYER" "9 kreskowanie")) (command "-layer" "new" "9 kreskowanie" "Color" 254 "9 kreskowanie" "LTYPE" "Continuous" "9 kreskowanie" "") );end if (setvar "clayer" "9 kreskowanie") (setvar "celtype" "bylayer") (setvar "cecolor" "bylayer") (setq point (getpoint "\n Select cone center point (top): ")) (setq ent1 (car (entsel "\n Select a TOP polyline: "))) (setq ent2 (car (entsel "\n Select a BOTTOM polyline: "))) (setq n_bat (getint "\n How many batter tics - slope lines: ")) (setq i 0) (setq len1 (vlax-curve-getdistatparam ent1 (vlax-curve-getendparam ent1))) ;(princ "\n") ;(princ len1) (setq len2 (vlax-curve-getdistatparam ent2 (vlax-curve-getendparam ent2))) ;(princ "\n") ;(princ len2) ;(princ "\n") ;(princ n_bat) ;(princ "\n") ;(princ (/ 1 (float n_bat))) (setq all_entities (ssadd)) ; Initialize the list of entities (setq ticks (ssadd)) ; Initialize the list of all entities (setq newpoints nil) ; Initialize the list of intersection points (repeat (+ n_bat 1) (setq pt1 (vlax-curve-getPointAtDist ent1 (* len1 (* i (/ 1 (float n_bat)))))) ; get the point at each len of polyline ;(princ "\n") ;(princ pt1) (setq pt2 (vlax-curve-getPointAtDist ent2 (* len2 (* i (/ 1 (float n_bat)))))) ; get the point at each len of polyline ;(princ "\n") ;(princ pt2) (entmake (list (cons 0 "LINE") (cons 10 point) (cons 11 pt2) ) ) ;entmake end ;(princ "\n created center to end line") (ssadd (entlast) all_entities) (setq intersection (vla-IntersectWith (vlax-ename->vla-object ent1) (vlax-ename->vla-object (entlast)) acExtendThisEntity)) ;(princ "\n intersection found") (setq intersection (vlax-safearray->list (vlax-variant-value intersection))) ;(princ "\n") ;(princ intersection) ;(princ "\n") (if (equal (/ i 2.0) (fix (/ i 2.0)) 0.001) ;check for every second (progn (setq pt2 (polar intersection (angle intersection pt2) (/ (distance intersection pt2) 2))) ;(princ "\n new point py2") ;(princ pt2) );end progn );end if (entmake (list (cons 0 "LINE") (cons 10 intersection) (cons 11 pt2) ) ) ;entmake end (ssadd (entlast) ticks) (setq i (+ i 1)) ) ; Delete all entities created in the loop ; (princ "\n now trying to delete") (sssetfirst nil all_entities) ; (princ "\n now trying to delete") (if all_entities (command "_.Erase" all_entities "")) ; (princ "\n after delete") (COMMAND "-Group" "create" "*" "" ticks "") ;;create group (setvar "clayer" curlayer) );end_defun Thanks everybody for help 1 Quote
lrm Posted February 29 Posted February 29 Quote Could someone explain the difference between vlax-curve-getPointAtParam and vlax-curve-getPointAtDist . Of course that one works on parameter other one in distance but thouht the results will be same. For example: (lenght_at_end - lenght_at-start ) / 3 and (parameter_at_end - parameter_at-start ) / 3 should give same result point. Curves have an independent parameter, let's call it u. For a polyline consisting of one arc the range for u is 0 to 1. If the polyline has two arcs the range for u would be 0 to 2. If u were between 0 and 1 then the point is on the first arc segment. If u is between 1 and 2 then the point is on the second arc segment. Note that the distance along the arc from say, u = 1.1 to 1.2 would be the same as from 1.2 to 1.3 but not equal to the distance from 2.1 to 2.2 since the second arc may have a different radius and subtended angle. vlax-curve-getPointAtParam is used to work with the paramter (u) while vlax-curve-getPointAtDist is used to work with the distace measured along th curve. Note, for Bezier and B-Splines (AutoCAD splines) the maximum parameter variable is an integer. For NURBS the maximum value could be a real number (that's why they are called "non-uniform"). 1 Quote
zwonko Posted February 29 Author Posted February 29 @Irm, thanks for explanation. Could You also give some examplewhere to use vlax-curve-getPointAtParam ? Quote
CyberAngel Posted February 29 Posted February 29 40 minutes ago, lrm said: Curves have an independent parameter, let's call it u. For a polyline consisting of one arc the range for u is 0 to 1. If the polyline has two arcs the range for u would be 0 to 2. If u were between 0 and 1 then the point is on the first arc segment. If u is between 1 and 2 then the point is on the second arc segment. Note that the distance along the arc from say, u = 1.1 to 1.2 would be the same as from 1.2 to 1.3 but not equal to the distance from 2.1 to 2.2 since the second arc may have a different radius and subtended angle. vlax-curve-getPointAtParam is used to work with the paramter (u) while vlax-curve-getPointAtDist is used to work with the distace measured along th curve. If I understand your explanation, getPointAtParam calculates a percentage of the arc distance, while getPointAtDist calculates the actual arc distance. The parameter may or may not change from one segment to the next, depending on length. Both functions then return the point on the curve at that distance, or nil if there's an error (such as a distance outside the arc). So in this case Quote (lenght_at_end - lenght_at-start ) / 3 and (parameter_at_end - parameter_at-start ) / 3 should give same result point. for a curve of length 4.2, the first expression gives (4.2-0)/3 = 1.4, while the second gives (1-0)/3 = 0.333 (1/3). It's like comparing apples and oranges. In the latter case you would skip the calculation and use parameter = 0.333, which returns the same point as length = 1.4. Quote
lrm Posted February 29 Posted February 29 (edited) Quote @zwonko @lrmthanks for explanation. Could You also give some examplewhere to use vlax-curve-getPointAtParam ? The calculation of the length along a polyline is very straightforward. For arc sections the distance along the arc is simply the radius of the arc times the angle subtended by the arc (in radians). Straight line sections, of course, are simply: Distance from point 1 to point 2 = square root ((x2-x1)^2 + (y2-y1)^2 +(z2-z1)^2) Things become a little more tricky with splines. The general spline in AutoCAD is known as a NURBS or non-uniform rational B-spline. NURBS, and its simpler special case forms named B-splines and Bezier splines are parametric functions. For parametric equations an independent variable,, the parameter (u), is used to specify a point on the curve. Give the equation for a spline a value for the parameter u and you'll get back the X,Y,Z coordinates of a point on the spline. This calculation is done quickly and efficiently. However, the calculation of distance along a spline is more complex. It requires mathematics known as numerical integration. Numerical calculations use a trial-and-error like approach to solving a problem. Repeated calculations are made and evaluated to determine the distance along the spline. In making these calculations the parameter u is repeatedly adjusted until the distance along the curve is within some acceptable tolerance. Bottom line? Locating a point on a spline with a parameter is much more efficient than locating a point on a spline given a distance. For example, the calculation for determining the intersection of two splines would manipulate values of u for the two splines on a trial and error basis until a value for each u yielded the same point in space within an acceptable tolerance. In this example, the distance along the curve is not needed. Quote @CyberAngel If I understand your explanation, getPointAtParam calculates a percentage of the arc distance, while getPointAtDist calculates the actual arc distance. Yes, you can think of the "param" in getPointAtParamas for each segment as a percentage but be careful that for spline the parameter value cannot be directly converted to a distance along the spline since the parameter typically would not vary equally with distance. A nice attribute of parametric splines is that for evenly distributed values of the parameter you will get more points in areas of sharp curvature and in areas of flatter curvature. A simple demonstration of this feature can be shown with a polyline-spline and the splineegs command. In the image below the red line was copied and then using pedit-spline turned iinto a spline. The default value for splinesegs his 8. To draw the spline AutoCAD uses values of 0.0, 0.125, 0.25, 0.375, …, 1.0 for u to determine the chords to draw to represent the spline. Looking closely at the white curve you will see that it's composed of eight straight sections note how they are shorter where the curvature is smaller. If splinesegs is changed to 4, and the spline is decurved and then then splined again the result is as follows. Four chords are used to represent the spline and it looks very crude. If splinesegs is changed to 4, and the spline is decurved and then then splined again the result is as follows. Four chords are used to represent the spline and it looks very crude. On a completely separate but related note, last year I posted this 3ds Max Tutorial on using numerical methods to animate the boom of a trolley conected to an overhead cable. Even if you are not a 3ds Max user or familiar with Max scripts I think you can see how the function interpcurve3d at 6:23 in the video is used to find a point on a curve using a parameter can be helpful in solving such a problem. Edited February 29 by lrm 1 Quote
BIGAL Posted March 1 Posted March 1 (edited) A may be method, is (Entsel pick arc1, (entsel pick arc2. Then explode both plines this means they are now arcs, then use ssget pt1, ssget pt2 to get the arcs, the points are (cadr of entsel, work out the points along the arc based on number of batter lines, do for both arcs, then do a UNDO, the plines will be restored but you have all the points still. A Undo does not undo Lisp values. No need for complicated getPointAtParamas. Simply tested up to work out points, but no code. Should do complicated shape like image by LRM. If worth looking into more ask. Just further comment I use a tadpole block and just scale to fit between top and bottom. Just pick 2 plines. Edited March 1 by BIGAL Quote
devitg Posted March 1 Posted March 1 On 2/29/2024 at 4:47 AM, zwonko said: Thanks @devitg - it is working. But the question is - if it will work if there will be other points near cone polylines? No problem, as the point made by DIVIDE, are set to its own and unique layer , (vl-cmdf "_Layer" "M" "point1" "") (vl-cmdf "divide" ent1 n_bat) and then the ssget filter points at such layer (vl-cmdf "ZOOM" "o" ent1 "") (setq point@ent1-ss (ssget "w" p1 p2 '((0 . "point") (8 . "POINT1"))) ) ;_ end of setq So it will ssget POINTS at such layer Of course it could be do a check, if the layer do no exist. 1 Quote
Tsuky Posted March 3 Posted March 3 @zwonko Try this if you might be interested. CONE_BATTER.lsp 1 Quote
devitg Posted March 26 Posted March 26 On 2/29/2024 at 9:29 PM, BIGAL said: Just further comment I use a tadpole block and just scale to fit between top and bottom. Just pick 2 plines. @shahAbdul It seem to be a BLOCK inserted by a not known lisp. Maybe @BIGAL could help Quote
marko_ribar Posted March 26 Posted March 26 Maybe this link can help you somehow : https://www.cadtutor.net/forum/files/file/28-edgenet-newest-lsp-routines-by-mrzip/ Regards, M.R. 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.