mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-15 08:59:40 +00:00
Merge branch 'anachronist_dev' of https://github.com/amatulic/BOSL2 into anachronist_dev
This commit is contained in:
commit
f564a0f060
1 changed files with 0 additions and 77 deletions
77
paths.scad
77
paths.scad
|
@ -1246,82 +1246,5 @@ function _assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) =
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/// Internal function: _bend_path_corner()
|
|
||||||
/// Usage:
|
|
||||||
/// _bend_path_corner(three_point_path, [sharpness], [cutlimit], [splinesteps], [midpoint]);
|
|
||||||
/// Description:
|
|
||||||
/// Used by squircle() in shapes2d.scad and curvy_path() in rounding.scad
|
|
||||||
/// Given a path with three points [p1, p2, p3] (2D or 3D), return a subdivided path that curves around from p1 to p3, with the sharpness parameter determining how close to a perfect circle (sharpness=0) or the p2 corner (sharpness=1) the path is from the shortest leg, with the amount of corner lopped off limited by cutlimit. The longer leg is stretched appropriately.
|
|
||||||
/// The error in using a cubic bezier curve to approximate a circular arc is about 0.00026 for a unit circle, with zero error at the endpoint and the corner bisector.
|
|
||||||
/// Arguments:
|
|
||||||
/// p = List of 3 points [p1, p2, p3]. The points may be 2D or 3D.
|
|
||||||
/// sharpness = curve is circular (sharpness=0) or sharp to the corner (sharpness=1) or anywhere in between
|
|
||||||
/// cutlimit = optionally constrain the curved path to be no farther than this from the corner
|
|
||||||
/// splinesteps = number of steps to use for each half of the corner
|
|
||||||
function _bend_path_corner(p, sharpness=0.5, cutlimit=999999, splinesteps=10, midpoint=[true,true]) =
|
|
||||||
sharpness==1 || cutlimit==0 ? [p[1]]
|
|
||||||
: let(
|
|
||||||
p2 = p[1],
|
|
||||||
p1 = midpoint[0] ? 0.5*(p[0]+p2) : p[0],
|
|
||||||
p3 = midpoint[1] ? 0.5*(p2+p[2]) : p[2],
|
|
||||||
a0 = 0.5*vector_angle(p1, p2, p3),
|
|
||||||
d1 = norm(p1-p2),
|
|
||||||
d3 = norm(p3-p2),
|
|
||||||
tana = tan(a0),
|
|
||||||
rmin = min(d1, d3) * tana,
|
|
||||||
rmax = max(d1, d3) * tana,
|
|
||||||
// A "perfect" unit circle quadrant constructed from cubic bezier points [1,0], [1,d], [d,1], [0,1], with d=0.55228474983 has exact radius=1 at 0°, 45°, and 90°, with a maximum radius (at 22.5° and 67.5°) of 1.00026163152; nearly a perfect circle arc.
|
|
||||||
fleg = let(a2=a0*a0)
|
|
||||||
// model of "perfect" circle leg lengths for a bezier unit circle arc depending on arc angle a0; the model error is ~1e-5
|
|
||||||
-4.4015E-08 * a2*a0 // tiny term, but reduces error by an order of magnitude
|
|
||||||
+0.0000113366 * a2
|
|
||||||
-0.00680018 * a0
|
|
||||||
+0.552244,
|
|
||||||
leglenmin = rmin * fleg,
|
|
||||||
leglenmax = rmax * fleg,
|
|
||||||
cp = circle_2tangents(rmin, p1, p2, p3)[0], // circle center
|
|
||||||
middir = unit(cp-p2), // unit vector from corner pointing to circle center
|
|
||||||
bzmid = cp - rmin*middir, // location of bezier point joining both halves of curve
|
|
||||||
maxcut = norm(bzmid-p2), // maximum possible distance from corner to curve
|
|
||||||
sharp = max(sharpness, 1-min(1, cutlimit/maxcut)),
|
|
||||||
|
|
||||||
bzdist = maxcut * (1-sharp), // distance from corner to tip of curve
|
|
||||||
cornerlegmin = min(leglenmin, bzdist*tana),
|
|
||||||
cornerlegmax = min(leglenmax, bzdist*tana),
|
|
||||||
p21unit = unit(p1-p2),
|
|
||||||
p23unit = unit(p3-p2),
|
|
||||||
midto12unit = unit(p21unit-p23unit),
|
|
||||||
// bezier points around the corner p1,p2,p3 (p2 is the vertex):
|
|
||||||
// bz0 is p1
|
|
||||||
// bz1 is on same leg as p1
|
|
||||||
// bz2 is on line perpendicular to bisector for first half of curve
|
|
||||||
// bz3 is bezier start/end point on the corner bisector
|
|
||||||
// bz4 is on line perpendicular to bisector for second half of curve
|
|
||||||
// bz5 is on same leg as p3
|
|
||||||
// bz6 is p3
|
|
||||||
bz3 = p2 + middir * bzdist, // center control point
|
|
||||||
bz2 = bz3 + midto12unit*(d1<d3 ? cornerlegmin : cornerlegmax),
|
|
||||||
bz1 = p1 - (d1<=d3 ? leglenmin :
|
|
||||||
leglenmax)*p21unit,
|
|
||||||
//norm(0.333*(bz2-p1)))*p21unit,
|
|
||||||
bz4 = bz3 - midto12unit*(d3<d1 ? cornerlegmin : cornerlegmax),
|
|
||||||
bz5 = p3 - (d3<=d1 ? leglenmin :
|
|
||||||
leglenmax)*p23unit,
|
|
||||||
//norm(0.333*(bz4-p3)))*p23unit,
|
|
||||||
bez1 = [p1, bz1, bz2, bz3],
|
|
||||||
bez2 = [bz3, bz4, bz5, p3],
|
|
||||||
ustep = 1/splinesteps
|
|
||||||
) [
|
|
||||||
for(u=[0:ustep:0.9999]) _bzpoint(bez1, u),
|
|
||||||
for(u=[0:ustep:0.9999]) _bzpoint(bez2, u)
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Internal function to avoid pulling in all of beziers.scad for _bend_path_corner() above
|
|
||||||
/// Get the t coordinate of a cubic Bezier curve given 4 control points in cp
|
|
||||||
function _bzpoint(cp, t) = let(n=len(cp[0])-1, t2=t*t, tm=1-t, tm2=tm*tm) [
|
|
||||||
for(i=[0:n])
|
|
||||||
cp[0][i]*tm2*tm + 3*cp[1][i]*t*tm2 + 3*cp[2][i]*t2 * (1-t) + cp[3][i]*t2*t
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
Loading…
Reference in a new issue