I wrote the attached vlisp program to give me a better feel for the curvature of a spline. It determines the instantaneous radius of curvature at a 100 points along a spline. In addition to numerical values the program will draw lines showing either lines from a point on the spline to the center of curvature for that point (e.g., short lines are small radii, flat sections long lines), or curvature (short lines indication near flat curvature). The latter option requires a scale factor to aid visualization.
I ran the program on your spline wth the following results.
![leeminardi_0-1722982238748.png leeminardi_0-1722982238748.png](https://forums.autodesk.com/t5/image/serverpage/image-id/1395013iF6DD288CC7BBF8FC/image-size/medium?v=v2&px=400)
Note that the area circled in red is fairly flat and the spline area circled in green has the smallest radii.
YOu may want to use the numerical values to determine an approximate radius to use.
(defun C:SplineCurvatue (/ path inc n osm par der1 der2 curva p perp normv p2 sf
curveType ans)
; = Degree Of Curvature - Lines
; Creates curvature lines or radius-of-curvature lines
; normal to a spline.
; LRM 8/18/2022 edited to place curvature vectors outside
(setq
path (car (entsel))
inc (/ (vlax-curve-getEndParam path) 100)
n 0
osm (getvar 'osmode)
)
(setvar 'osmode 0)
(setvar "cmdecho" 0)
(initget "y n")
(setq ans (getkword "Do you want radius-of-curvature instead of curvature? [y/n] <n>: "))
(if (= ans "y")
(setq curveType 1)
(setq curveType 2
sf (getdist "Enter scale factor.")
)
)
(repeat 100
(setq par (* inc n))
(setq der1 (vlax-curve-getfirstDeriv path par)
der2 (vlax-curve-getSecondDeriv path par)
)
; calculate curvature at point par
(setq d (distance '(0 0 0) (cross der1 der2)))
(if (> (abs d) 1.0e-15)
(progn
(setq curva (/ (expt (distance '(0 0 0) der1) 3) d))
(if (= curveType 2)
(setq curva (* -1. (* sf (/ 1. curva))))
)
(princ "\n") (princ n)
(princ " curvature = ") (princ curva)
(setq p (vlax-curve-getPointAtParam path par)
perp (unitv (cross der1 (cross der2 der1)))
normv (mapcar '* perp (list curva curva curva))
p2 (mapcar '+ p normv)
)
(command "_.line" p p2 "")
) ; end progn
)
(setq n (1+ n))
)
(setvar 'osmode osm)
(setvar "cmdecho" 1)
(princ)
)
;;; Compute the cross product of 2 vectors a and b
(defun cross (a b / crs)
(setq crs (list
(- (* (nth 1 a) (nth 2 b))
(* (nth 1 b) (nth 2 a))
)
(- (* (nth 0 b) (nth 2 a))
(* (nth 0 a) (nth 2 b))
)
(- (* (nth 0 a) (nth 1 b))
(* (nth 0 b) (nth 1 a))
)
) ;end list
) ;end setq c
) ;end cross
(defun unitV ( v / d)
(setq d (distance '(0 0 0) v)
d (mapcar '/ v (list d d d))))
On a related note, I have found that I would prefer to use loft rather than sweep for 2D shapes swept along a spline. Loft can provide better local control of twist. The following program is a work-in-progress and not ready for prime time but you may find it helpful.
Begin by defining a block with the profile (a polyline) you would like to sweep. Working in world coordinates make sure that the Z axis is perpendicular to the plane of th polyline.
Use the program to position multiple copies of the block along the spline. You can modify the twist of individual sections by setting the UVS to OBject. Then use the standard 2D rotate command to adjust the twist for that section. When you have the sections twisted as desirered explode all the section and use the loft command.
Here's the results I got bor a modified section of your railing. I had to simplify the top of the section to get results.
![leeminardi_1-1722982990915.png leeminardi_1-1722982990915.png](https://forums.autodesk.com/t5/image/serverpage/image-id/1395017i83A1B9BAC4F6D094/image-size/medium?v=v2&px=400)
(defun C:test (/ nsec blockname twist tottwist path inc n osm par der1
der2 p p1 p2 vy vz vx p3)
; draft version
; Adds blocks along a spline. The user specifies the number of blocks and
; the total amount of twist over the length of the spline. The Z axis of the block
; is tangent to the spline.
; LRM 5/1/2023 revised 6/4/2024
(command "ucs" "w")
(setvar 'osmode 0)
(setq nsec (getint "\nEnter number of sections: "))
(setq nsec (- nsec 1))
(setq blockname (getstring "\nEnter block name: "))
(setq twist (getreal "\nEnter start twist angle: "))
(setq tottwist (getreal "\nENter total twist start to end: "))
(setq
path (car (entsel))
inc (/ (vlax-curve-getEndParam path) nsec)
n 0
osm (getvar 'osmode)
)
(setvar "cmdecho" 0)
(repeat (+ nsec 1)
(setq par (* inc n))
(setq der1 (vlax-curve-getfirstDeriv path par)
der2 (vlax-curve-getSecondDeriv path par)
p (vlax-curve-getPointAtParam path par)
)
(setq p1 (mapcar '+ p (unitv (cross der1 der2))))
(setq p2 (mapcar '+ p (unitv der1)))
(setq vy (unitv (mapcar '- p1 p)))
(setq vz (unitv (mapcar '- p2 p)))
(setq vx (unitv (cross vy vz)))
(setq p3 (mapcar '- p vx))
(command "_point" "_non" p)
(command "_point" "_non" p2)
(command "_point" "_non" p3)
(command "-insert" blockname '(0 0 0) 1 1 0)
(command "_align" "last" "" '(0 0 0) p '(1 0 0) p1 '(0 0 -1) p2 "n")
(if (> (abs twist) 0.00001)
(command "rotate3d" "last" "" "2" p p2 twist)
)
(setq twist (- twist (/ tottwist nsec)))
(setq n (1+ n))
) ; end repeat
(setvar 'osmode osm)
(setvar "cmdecho" 1)
(princ)
)
;;; Compute the cross product of 2 vectors a and b
(defun cross (a b / crs)
(setq crs (list
(- (* (nth 1 a) (nth 2 b))
(* (nth 1 b) (nth 2 a))
)
(- (* (nth 0 b) (nth 2 a))
(* (nth 0 a) (nth 2 b))
)
(- (* (nth 0 a) (nth 1 b))
(* (nth 0 b) (nth 1 a))
)
) ;end list
) ;end setq c
) ;end cross
(defun unitV (v / d)
(setq d (distance '(0 0 0) v)
d (mapcar '/ v (list d d d))
)
)
lee.minardi