Added module catenary()

This commit is contained in:
Revar Desmera 2023-11-04 22:08:27 -07:00
parent 22e2fe35c8
commit 0fcca5437e

View file

@ -881,6 +881,8 @@ module arc(n, r, angle, d, cp, points, corner, width, thickness, start, wedge=fa
// n = The number of points to return in the path. Default: 100 // n = The number of points to return in the path. Default: 100
// --- // ---
// angle = If given, specifies the angle that the path will droop by at the endpoints. If given a negative value, returns an arch *above* the Y axis. // angle = If given, specifies the angle that the path will droop by at the endpoints. If given a negative value, returns an arch *above* the Y axis.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). (Module only) Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). (Module only) Default: `0`
// Example(2D): By Droop // Example(2D): By Droop
// stroke(catenary(100, droop=30)); // stroke(catenary(100, droop=30));
// Example(2D): By Angle // Example(2D): By Angle
@ -902,36 +904,48 @@ function catenary(width, droop, n=100, angle) =
angle = angle==undef? undef : abs(angle) angle = angle==undef? undef : abs(angle)
) )
assert(is_finite(width) && width>0, "Bad width= value.") assert(is_finite(width) && width>0, "Bad width= value.")
assert(is_integer(n) && n>0, "Bad n= value. Must be a positive integer.") assert(is_integer(n) && n>0, "Bad n= value. Must be a positive integer.")
assert(is_undef(droop) || is_finite(droop), "Bad droop= value.") assert(is_undef(droop) || is_finite(droop), "Bad droop= value.")
assert(is_undef(angle) || (is_finite(angle) && angle != 0 && abs(angle) < 90), "Bad angle= value.") assert(is_undef(angle) || (is_finite(angle) && angle != 0 && abs(angle) < 90), "Bad angle= value.")
let( let(
lup = is_undef(droop) catlup_fn = is_undef(droop)
? [ ? function(x) let(
for (x=[0:0.01:10]) p1 = [x-0.001, cosh(x-0.001)-1],
let( p2 = [x+0.001, cosh(x+0.001)-1],
p1 = [x-0.001, cosh(x-0.001)-1], delta = p2-p1,
p2 = [x+0.001, cosh(x+0.001)-1], ang = atan2(delta.y, delta.x)
delta = p2-p1, ) ang
ang = atan2(delta.y, delta.x) : function(x) (cosh(x)-1)/x,
) binsearch_fn = function(targ,x=0,inc=4)
[ang, x] inc < 1e-9? lookup(targ,[[catlup_fn(x),x],[catlup_fn(x+inc),x+inc]]) :
] catlup_fn(x+inc) > targ? binsearch_fn(targ,x,inc/2) :
: [ for (x=[0.001:0.1:10]) [(cosh(x)-1)/x, x] ], binsearch_fn(targ,x+inc,inc),
lval = is_undef(droop) scx = is_undef(droop)? binsearch_fn(angle) :
? angle binsearch_fn(droop / (width/2)),
: droop / (width/2), sc = width/2 / scx,
scx = lookup(lval, lup), droop = !is_undef(droop)? droop : (cosh(scx)-1) * sc,
droop = !is_undef(droop)? droop :
(cosh(scx)-1) * width/2 / scx,
path = [ path = [
for (x = lerpn(-scx,scx,n)) for (x = lerpn(-scx,scx,n))
[x, cosh(x)-1] * width/2 / scx - [0,droop] let(
xval = x * sc,
yval = approx(abs(x),scx)? 0 :
(cosh(x)-1) * sc - droop
)
[xval, yval]
], ],
out = sgn>0? path : yflip(p=path) out = sgn>0? path : yflip(p=path)
) out; ) out;
module catenary(width, droop, n=100, angle, anchor=CTR, spin=0) {
path = catenary(width=width, droop=droop, n=n, angle=angle);
attachable(anchor,spin, two_d=true, path=path, extent=true) {
polygon(path);
children();
}
}
// Function: helix() // Function: helix()
// Synopsis: Creates a 2d spiral or 3d helical path. // Synopsis: Creates a 2d spiral or 3d helical path.
// SynTags: Path // SynTags: Path