discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

3D Cardinal Spline

D
dinther
Fri, Mar 12, 2021 1:45 AM

I needed a 3D cardinal spline for a ship hull generator. I could not find the
kind I wanted so I wrote one. Also a good exercise in functional coding. I
thought to share it. Feedback welcome of course.

//  Cardinal Spine adapted from
https://github.com/dominictarr/cardinal-spline-3d
//  for openscad
//
//  By: Paul van Dinther
//
//  usage:
//
//  pts = cardinal_spline([[5,0],[3,-4],[0,-5],[-3,-4],[-5,0]], tension =
0.5, numOfSeg=15, close=false);
//  polygon(pts);
//
//  or 3D
//
//  pts = cardinal_spline([[5,0,0],[3,4,2],[0,5,5],[-3,4,2],[-5,0,0]],
tension = 0.5, numOfSeg=15, close=true);
//  for (i = [0:1:len(pts)-1]) translate(pts[i]) sphere(r=0.25);
//

function cardinal_spline(points= undef, tension = 0.5, numOfSeg=15, close =
false) =
let(
count = len(points),
pts = close? concat([points[count-1]],points, [points[0]]) :
concat([points[0]], points,[points[count-1]]),
echo(pts),
cachePtr = 4,
cache = concat([1,0,0,0], [for (i = [1:1:numOfSeg-1]) let(
st = i/numOfSeg,
st2 = st * st,
st3 = st2 * st,
st23 = st3 * 2,
st32 = st2 * 3,
cg = [st23 - st32 + 1, st32 - st23, st3 - 2 * st2 + st,st3-st2])
each cg],[0,1, for (i=[0:1:((numOfSeg + 2)4)-(numOfSeg4)-4]) 0 ])
) concat(parse(pts=pts, cache=cache, count=count, tension=tension,
numOfSeg=numOfSeg), close? parse(pts=[points[count-2],points[count-1],
points[0], points[1]],cache=cache, count=2, tension=tension,
numOfSeg=numOfSeg) : [points[count-1]]);

function parse(pts=undef, cache=undef, count=undef , tension=0.5,
numOfSeg=15) =
[for( i = [ 1 : 1 : count-1]) let(
pt1x = pts[i][0],
pt1y = pts[i][1],
pt1z = pts[i][2]==undef? 0 : pts[i][2],
pt2x = pts[i+1][0],
pt2y = pts[i+1][1],
pt2z = pts[i+1][2]==undef? 0 : pts[i+1][2],
t1x = (pt2x - pts[i-1][0]) * tension,
t1y = (pt2y - pts[i-1][1]) * tension,
t1z = (pt2z - (pts[i-1][2]==undef? 0 : pts[i-1][2])) * tension,
echo(pts[i-1][2]),
t2x = (pts[i+2][0] - pt1x) * tension,
t2y = (pts[i+2][1] - pt1y) * tension,
t2z = ((pts[i+2][2]==undef? 0 : pts[i+2][2]) - pt1z) * tension,
data = [for(t=[0:1:numOfSeg-1]) let(
c1 = cache[t4 + 0],
c2 = cache[t
4 + 1],
c3 = cache[t4 + 2],
c4 = cache[t
4 + 3],
x = c1 * pt1x + c2 * pt2x + c3 * t1x + c4 * t2x,
y = c1 * pt1y + c2 * pt2y + c3 * t1y + c4 * t2y,
z = c1 * pt1z + c2 * pt2z + c3 * t1z + c4 * t2z,
d = pts[i][2]==undef? [x, y] : [x, y, z]
) d]) each data];

--
Sent from: http://forum.openscad.org/

I needed a 3D cardinal spline for a ship hull generator. I could not find the kind I wanted so I wrote one. Also a good exercise in functional coding. I thought to share it. Feedback welcome of course. // Cardinal Spine adapted from https://github.com/dominictarr/cardinal-spline-3d // for openscad // // By: Paul van Dinther // // usage: // // pts = cardinal_spline([[5,0],[3,-4],[0,-5],[-3,-4],[-5,0]], tension = 0.5, numOfSeg=15, close=false); // polygon(pts); // // or 3D // // pts = cardinal_spline([[5,0,0],[3,4,2],[0,5,5],[-3,4,2],[-5,0,0]], tension = 0.5, numOfSeg=15, close=true); // for (i = [0:1:len(pts)-1]) translate(pts[i]) sphere(r=0.25); // function cardinal_spline(points= undef, tension = 0.5, numOfSeg=15, close = false) = let( count = len(points), pts = close? concat([points[count-1]],points, [points[0]]) : concat([points[0]], points,[points[count-1]]), echo(pts), cachePtr = 4, cache = concat([1,0,0,0], [for (i = [1:1:numOfSeg-1]) let( st = i/numOfSeg, st2 = st * st, st3 = st2 * st, st23 = st3 * 2, st32 = st2 * 3, cg = [st23 - st32 + 1, st32 - st23, st3 - 2 * st2 + st,st3-st2]) each cg],[0,1, for (i=[0:1:((numOfSeg + 2)*4)-(numOfSeg*4)-4]) 0 ]) ) concat(parse(pts=pts, cache=cache, count=count, tension=tension, numOfSeg=numOfSeg), close? parse(pts=[points[count-2],points[count-1], points[0], points[1]],cache=cache, count=2, tension=tension, numOfSeg=numOfSeg) : [points[count-1]]); function parse(pts=undef, cache=undef, count=undef , tension=0.5, numOfSeg=15) = [for( i = [ 1 : 1 : count-1]) let( pt1x = pts[i][0], pt1y = pts[i][1], pt1z = pts[i][2]==undef? 0 : pts[i][2], pt2x = pts[i+1][0], pt2y = pts[i+1][1], pt2z = pts[i+1][2]==undef? 0 : pts[i+1][2], t1x = (pt2x - pts[i-1][0]) * tension, t1y = (pt2y - pts[i-1][1]) * tension, t1z = (pt2z - (pts[i-1][2]==undef? 0 : pts[i-1][2])) * tension, echo(pts[i-1][2]), t2x = (pts[i+2][0] - pt1x) * tension, t2y = (pts[i+2][1] - pt1y) * tension, t2z = ((pts[i+2][2]==undef? 0 : pts[i+2][2]) - pt1z) * tension, data = [for(t=[0:1:numOfSeg-1]) let( c1 = cache[t*4 + 0], c2 = cache[t*4 + 1], c3 = cache[t*4 + 2], c4 = cache[t*4 + 3], x = c1 * pt1x + c2 * pt2x + c3 * t1x + c4 * t2x, y = c1 * pt1y + c2 * pt2y + c3 * t1y + c4 * t2y, z = c1 * pt1z + c2 * pt2z + c3 * t1z + c4 * t2z, d = pts[i][2]==undef? [x, y] : [x, y, z] ) d]) each data]; -- Sent from: http://forum.openscad.org/