diff --git a/README.md b/README.md index 2a6d3d38..ec675810 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Too many dependencies? Because OpenSCAD doesn't provide namespace management, I - [circle_path](https://openhome.cc/eGossip/OpenSCAD/lib-circle_path.html) - [bezier_curve](https://openhome.cc/eGossip/OpenSCAD/lib-bezier_curve.html) - [bezier_surface](https://openhome.cc/eGossip/OpenSCAD/lib-bezier_surface.html) + - [bezier_smooth](https://openhome.cc/eGossip/OpenSCAD/lib-bezier_smooth.html) - [helix](https://openhome.cc/eGossip/OpenSCAD/lib-helix.html) - [golden_spiral](https://openhome.cc/eGossip/OpenSCAD/lib-golden_spiral.html) - [archimedean_spiral](https://openhome.cc/eGossip/OpenSCAD/lib-archimedean_spiral.html) diff --git a/docs/images/lib-bezier_smooth-1.JPG b/docs/images/lib-bezier_smooth-1.JPG new file mode 100644 index 00000000..c3ec4b48 Binary files /dev/null and b/docs/images/lib-bezier_smooth-1.JPG differ diff --git a/docs/images/lib-bezier_smooth-2.JPG b/docs/images/lib-bezier_smooth-2.JPG new file mode 100644 index 00000000..696bfc01 Binary files /dev/null and b/docs/images/lib-bezier_smooth-2.JPG differ diff --git a/docs/lib-bezier_smooth.md b/docs/lib-bezier_smooth.md new file mode 100644 index 00000000..7db71d13 --- /dev/null +++ b/docs/lib-bezier_smooth.md @@ -0,0 +1,59 @@ +# bezier_smooth + +Given a path, the bezier_smooth function uses bazier curves to smooth all corners. You can use it to create smoothier lines or rounded shapes. + +Dependencies: the `bezier_curve` function. + +## Parameters + +- `path_pts` : A list of points represent the path. +- `round_d` : Used to create the other two control points at the corner. +- `t_step` : The distance between two points of the Bézier path at the corner. It defaults to 0.1. +- `closed` : It defaults to `false`. If you have a closed path, set it to `true`. + +## Examples + + include ; + include ; + include ; + + width = 2; + round_d = 15; + + path_pts = [ + [0, 0, 0], + [40, 60, 10], + [-50, 90, 30], + [-10, -10, 50] + ]; + + hull_polyline3d( + path_pts, width + ); + + smoothed_path_pts = bezier_smooth(path_pts, round_d); + + color("red") translate([30, 0, 0]) hull_polyline3d( + smoothed_path_pts, width + ); + +![bezier_smooth](images/lib-bezier_smooth-1.JPG) + + include ; + include ; + + round_d = 10; + + path_pts = [ + [0, 0], + [40, 0], + [0, 60] + ]; + + polygon(path_pts); + + smoothed_path_pts = bezier_smooth(path_pts, round_d, closed = true); + + translate([50, 0, 0]) polygon(smoothed_path_pts); + +![bezier_smooth](images/lib-bezier_smooth-2.JPG) \ No newline at end of file diff --git a/src/bezier_smooth.scad b/src/bezier_smooth.scad new file mode 100644 index 00000000..95398999 --- /dev/null +++ b/src/bezier_smooth.scad @@ -0,0 +1,81 @@ +/** +* bezier_smooth.scad +* +* Given a path, the bezier_smooth function uses bazier curves to smooth all corners. +* +* @copyright Justin Lin, 2017 +* @license https://opensource.org/licenses/lgpl-3.0.html +* +* @see https://openhome.cc/eGossip/OpenSCAD/lib-bezier_curve.html +* +**/ + +include <__private__/__to3d.scad>; +include <__private__/__to2d.scad>; + +function _ya_za(p1, p2) = + let( + dx = p2[0] - p1[0], + dy = p2[1] - p1[1], + dz = p2[2] - p1[2], + za = atan2(dy, dx), + ya = atan2(dz, sqrt(pow(dx, 2) + pow(dy, 2))) + ) [ya, za]; + +function _corner_ctrl_pts(round_d, p1, p2, p3) = + let( + _ya_za_1 = _ya_za(p1, p2), + _ya_za_2 = _ya_za(p3, p2), + + dz1 = sin(_ya_za_1[0]) * round_d, + dxy1 = cos(_ya_za_1[0]) * round_d, + dy1 = sin(_ya_za_1[1]) * dxy1, + dx1 = cos(_ya_za_1[1]) * dxy1, + + dz2 = sin(_ya_za_2[0]) * round_d, + dxy2 = cos(_ya_za_2[0]) * round_d, + dy2 = sin(_ya_za_2[1]) * dxy2, + dx2 = cos(_ya_za_2[1]) * dxy2 + ) + [ + p2 - [dx1, dy1, dz1], + p2, + p2 - [dx2, dy2, dz2] + ]; + + +function _bezier_corner(t_step, p1, p2, p3) = + bezier_curve(t_step, _corner_ctrl_pts(round_d, p1, p2, p3)); + +function _recursive_bezier_smooth(pts, round_d, t_step, leng, i = 0) = + i <= leng - 3 ? + concat( + _bezier_corner(t_step, pts[i], pts[i + 1], pts[i + 2]), + _recursive_bezier_smooth(pts, round_d, t_step, leng, i + 1) + ) + : []; + +function bezier_smooth(path_pts, round_d, t_step = 0.1, closed = false) = + let( + pts = len(path_pts[0]) == 3 ? path_pts : [for(p = path_pts) __to3d(p)], + leng = len(pts), + middle_pts = _recursive_bezier_smooth(pts, round_d, t_step, leng), + pth_pts = closed ? + concat( + _recursive_bezier_smooth( + [pts[leng - 1], pts[0], pts[1]], + round_d, t_step, 3 + ), + middle_pts, + _recursive_bezier_smooth( + [pts[leng - 2], pts[leng - 1], pts[0]], + round_d, t_step, 3 + ) + ) : + concat( + [pts[0]], + middle_pts, + [pts[leng - 1]] + ) + ) + len(path_pts[0]) == 2 ? [for(p = pth_pts) __to2d(p)] : pth_pts; \ No newline at end of file