mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
Merge pull request #752 from adrianVmariano/master
debug function rename, etc
This commit is contained in:
commit
676f13cb48
5 changed files with 279 additions and 403 deletions
120
attachments.scad
120
attachments.scad
|
@ -528,65 +528,6 @@ module tags(tags)
|
|||
}
|
||||
|
||||
|
||||
// Module: recolor()
|
||||
// Usage:
|
||||
// recolor(c) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), hide(), show(), diff(), intersect()
|
||||
// Description:
|
||||
// Sets the color for children that can use the $color special variable. For a more step-by-step
|
||||
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// c = Color name or RGBA vector.
|
||||
// Example:
|
||||
// recolor("red") cyl(l=20, d=10);
|
||||
module recolor(c)
|
||||
{
|
||||
$color = c;
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: hide()
|
||||
// Usage:
|
||||
// hide(tags) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), recolor(), show(), diff(), intersect()
|
||||
// Description:
|
||||
// Hides all children with the given tags. Overrides any previous `hide()` or `show()` calls.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Example:
|
||||
// hide("A") cube(50, anchor=CENTER, $tags="Main") {
|
||||
// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A");
|
||||
// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B");
|
||||
// }
|
||||
module hide(tags="")
|
||||
{
|
||||
$tags_hidden = tags==""? [] : str_split(tags, " ");
|
||||
$tags_shown = [];
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: show()
|
||||
// Usage:
|
||||
// show(tags) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), recolor(), hide(), diff(), intersect()
|
||||
// Description:
|
||||
// Shows only children with the given tags. Overrides any previous `hide()` or `show()` calls.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Example:
|
||||
// show("A B") cube(50, anchor=CENTER, $tags="Main") {
|
||||
// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A");
|
||||
// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B");
|
||||
// }
|
||||
module show(tags="")
|
||||
{
|
||||
$tags_shown = tags==""? [] : str_split(tags, " ");
|
||||
$tags_hidden = [];
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: diff()
|
||||
|
@ -755,6 +696,67 @@ module hulling(a)
|
|||
}
|
||||
|
||||
|
||||
// Module: recolor()
|
||||
// Usage:
|
||||
// recolor(c) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), hide(), show(), diff(), intersect()
|
||||
// Description:
|
||||
// Sets the color for children that can use the $color special variable. For a more step-by-step
|
||||
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// c = Color name or RGBA vector.
|
||||
// Example:
|
||||
// recolor("red") cyl(l=20, d=10);
|
||||
module recolor(c)
|
||||
{
|
||||
$color = c;
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: hide()
|
||||
// Usage:
|
||||
// hide(tags) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), recolor(), show(), diff(), intersect()
|
||||
// Description:
|
||||
// Hides all children with the given tags. Overrides any previous `hide()` or `show()` calls.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Example:
|
||||
// hide("A") cube(50, anchor=CENTER, $tags="Main") {
|
||||
// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A");
|
||||
// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B");
|
||||
// }
|
||||
module hide(tags="")
|
||||
{
|
||||
$tags_hidden = tags==""? [] : str_split(tags, " ");
|
||||
$tags_shown = [];
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: show()
|
||||
// Usage:
|
||||
// show(tags) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: tags(), recolor(), hide(), diff(), intersect()
|
||||
// Description:
|
||||
// Shows only children with the given tags. Overrides any previous `hide()` or `show()` calls.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Example: Display the attachments but not the parent
|
||||
// show("A B") cube(50, anchor=CENTER, $tags="Main") {
|
||||
// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A");
|
||||
// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B");
|
||||
// }
|
||||
module show(tags="")
|
||||
{
|
||||
$tags_shown = tags==""? [] : str_split(tags, " ");
|
||||
$tags_hidden = [];
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Section: Attachable Masks
|
||||
|
||||
|
|
538
beziers.scad
538
beziers.scad
|
@ -20,7 +20,7 @@
|
|||
// Degree = The degree of the polynomial used to make the bezier curve. A bezier curve of degree N will have N+1 control points. Most beziers are cubic (degree 3). The higher the degree, the more the curve can wiggle.
|
||||
// Bezier Parameter = A parameter, usually `u` below, that ranges from 0 to 1 to trace out the bezier curve. When `u=0` you get the first control point and when `u=1` you get the last control point. Intermediate points are traced out *non-uniformly*.
|
||||
// Bezier Path = A list of bezier control points corresponding to a series of Bezier curves that connect together, end to end. Because they connect, the endpoints are shared between control points and are not repeated, so a degree 3 bezier path representing two bezier curves will have seven entries to represent two sets of four control points. **NOTE:** A "bezier path" is *NOT* a standard path
|
||||
// Bezier Patch = A two-dimensional arrangement of Bezier control points that generate a bounded curved Bezier surface. A rectangular patch is a (N+1) by (M+1) grid of control points, which define surface with four edges (in the non-degenerate case). A triangular patch is a triangular arrangement of control points and it generates a Bezier surface with 3 edges.
|
||||
// Bezier Patch = A two-dimensional arrangement of Bezier control points that generate a bounded curved Bezier surface. A Bezier patch is a (N+1) by (M+1) grid of control points, which defines surface with four edges (in the non-degenerate case).
|
||||
// Bezier Surface = A surface defined by a list of one or more bezier patches.
|
||||
// Spline Steps = The number of straight-line segments used to approximate a Bezier curve. The more spline steps, the better the approximation to the curve, but the slower it will be to generate. This plays a role analogous to `$fn` for circles. Usually defaults to 16.
|
||||
|
||||
|
@ -40,28 +40,28 @@
|
|||
// is best when `u` is a long list and the bezier degree is 10 or less. The degree of the bezier
|
||||
// curve is `len(bezier)-1`.
|
||||
// Arguments:
|
||||
// bezier = The list of endpoints and control points for this bezier segment.
|
||||
// bezier = The list of endpoints and control points for this bezier curve.
|
||||
// u = Parameter values for evaluating the curve, given as a single value, a list or a range.
|
||||
// Example(2D): Quadratic (Degree 2) Bezier.
|
||||
// bez = [[0,0], [30,30], [80,0]];
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// translate(bezier_points(bez, 0.3)) color("red") sphere(1);
|
||||
// Example(2D): Cubic (Degree 3) Bezier
|
||||
// bez = [[0,0], [5,35], [60,-25], [80,0]];
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// translate(bezier_points(bez, 0.4)) color("red") sphere(1);
|
||||
// Example(2D): Degree 4 Bezier.
|
||||
// bez = [[0,0], [5,15], [40,20], [60,-15], [80,0]];
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// translate(bezier_points(bez, 0.8)) color("red") sphere(1);
|
||||
// Example(2D): Giving a List of `u`
|
||||
// bez = [[0,0], [5,35], [60,-25], [80,0]];
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// pts = bezier_points(bez, [0, 0.2, 0.3, 0.7, 0.8, 1]);
|
||||
// rainbow(pts) move($item) sphere(1.5, $fn=12);
|
||||
// Example(2D): Giving a Range of `u`
|
||||
// bez = [[0,0], [5,35], [60,-25], [80,0]];
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// pts = bezier_points(bez, [0:0.2:1]);
|
||||
// rainbow(pts) move($item) sphere(1.5, $fn=12);
|
||||
|
||||
|
@ -177,35 +177,36 @@ function _bezier_matrix(N) =
|
|||
|
||||
// Function: bezier_curve()
|
||||
// Usage:
|
||||
// path = bezier_curve(bezier, n, [endpoint]);
|
||||
// path = bezier_curve(bezier, [splinesteps], [endpoint]);
|
||||
// Topics: Bezier Curves
|
||||
// See Also: bezier_curvature(), bezier_tangent(), bezier_derivative(), bezier_points()
|
||||
// Description:
|
||||
// Takes a list of bezier control points and generates n points along the bezier curve they define.
|
||||
// Takes a list of bezier control points and generates splinesteps segments (splinesteps+1 points)
|
||||
// along the bezier curve they define.
|
||||
// Points start at the first control point and are sampled uniformly along the bezier parameter.
|
||||
// The endpoints of the output will be *exactly* equal to the first and last bezier control points
|
||||
// when endpoint is true. If endpoint is false the sampling stops one step before the final point
|
||||
// of the bezier curve, but you still get n, more tightly spaced, points.
|
||||
// of the bezier curve, but you still get the same number of (more tightly spaced) points.
|
||||
// The distance between the points will *not* be equidistant.
|
||||
// The degree of the bezier curve is one less than the number of points in `curve`.
|
||||
// Arguments:
|
||||
// bezier = The list of control points that define the Bezier curve.
|
||||
// n = The number of points to generate along the bezier curve.
|
||||
// splinesteps = The number of segments to create on the bezier curve. Default: 16
|
||||
// endpoint = if false then exclude the endpoint. Default: True
|
||||
// Example(2D): Quadratic (Degree 2) Bezier.
|
||||
// bez = [[0,0], [30,30], [80,0]];
|
||||
// move_copies(bezier_curve(bez, 8)) sphere(r=1.5, $fn=12);
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// Example(2D): Cubic (Degree 3) Bezier
|
||||
// bez = [[0,0], [5,35], [60,-25], [80,0]];
|
||||
// move_copies(bezier_curve(bez, 8)) sphere(r=1.5, $fn=12);
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// Example(2D): Degree 4 Bezier.
|
||||
// bez = [[0,0], [5,15], [40,20], [60,-15], [80,0]];
|
||||
// move_copies(bezier_curve(bez, 8)) sphere(r=1.5, $fn=12);
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
function bezier_curve(bezier,n,endpoint=true) =
|
||||
bezier_points(bezier, lerpn(0,1,n,endpoint));
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
function bezier_curve(bezier,splinesteps=16,endpoint=true) =
|
||||
bezier_points(bezier, lerpn(0,1,splinesteps+1,endpoint));
|
||||
|
||||
|
||||
// Function: bezier_derivative()
|
||||
|
@ -288,9 +289,9 @@ function bezier_curvature(bezier, u) =
|
|||
// Topics: Bezier Curves
|
||||
// See Also: bezier_points()
|
||||
// Description:
|
||||
// Finds the closest part of the given bezier segment to point `pt`.
|
||||
// Finds the closest part of the given bezier curve to point `pt`.
|
||||
// The degree of the curve, N, is one less than the number of points in `curve`.
|
||||
// Returns `u` for the shortest position on the bezier segment to the given point `pt`.
|
||||
// Returns `u` for the closest position on the bezier curve to the given point `pt`.
|
||||
// Arguments:
|
||||
// bezier = The list of control points that define the Bezier curve.
|
||||
// pt = The point to find the closest curve point to.
|
||||
|
@ -299,7 +300,7 @@ function bezier_curvature(bezier, u) =
|
|||
// pt = [40,15];
|
||||
// bez = [[0,0], [20,40], [60,-25], [80,0]];
|
||||
// u = bezier_closest_point(bez, pt);
|
||||
// trace_bezier(bez, N=len(bez)-1);
|
||||
// debug_bezier(bez, N=len(bez)-1);
|
||||
// color("red") translate(pt) sphere(r=1);
|
||||
// color("blue") translate(bezier_points(bez,u)) sphere(r=1);
|
||||
function bezier_closest_point(bezier, pt, max_err=0.01, u=0, end_u=1) =
|
||||
|
@ -395,28 +396,31 @@ function bezier_line_intersection(bezier, line) =
|
|||
// Section: Bezier Path Functions
|
||||
// To contruct more complicated curves you can connect a sequence of Bezier curves end to end.
|
||||
// A Bezier path is a flattened list of control points that, along with the degree, represents such a sequence of bezier curves where all of the curves have the same degree.
|
||||
// A Bezier path looks like a regular path, since it is just a list of points, but it is not a regular path. Use {{bezpath_curve()} to convert a Bezier path to a regular path.
|
||||
// A Bezier path looks like a regular path, since it is just a list of points, but it is not a regular path. Use {{bezpath_curve()}} to convert a Bezier path to a regular path.
|
||||
// We interpret a degree N Bezier path as groups of N+1 control points that
|
||||
// share endpoints, so they overlap by one point. So if you have an order 3 bezier path `[p0,p1,p2,p3,p4,p5,p6]` then the first
|
||||
// Bezier curve control point set is `[p0,p1,p2,p3]` and the second one is `[p3,p4,p5,p6]`. The endpoint, `p3`, is shared between the control point sets.
|
||||
// The Bezier degree, which must be known to interpret the Bezier path, defaults to 3.
|
||||
|
||||
|
||||
// Function: bezpath_points()
|
||||
// Usage:
|
||||
// pt = bezpath_points(bezpath, seg, u, [N]);
|
||||
// ptlist = bezpath_points(bezpath, seg, LIST, [N]);
|
||||
// path = bezpath_path_points(bezpath, seg, RANGE, [N]);
|
||||
// pt = bezpath_points(bezpath, curveind, u, [N]);
|
||||
// ptlist = bezpath_points(bezpath, curveind, LIST, [N]);
|
||||
// path = bezpath_points(bezpath, curveind, RANGE, [N]);
|
||||
// Topics: Bezier Paths
|
||||
// See Also: bezier_points(), bezier_curve()
|
||||
// Description:
|
||||
// Returns the coordinates of Bezier path path segment `seg` at parameter `u`.
|
||||
// Extracts from the Bezier path `bezpath` the control points for the Bezier curve whose index is `curveind` and
|
||||
// computes the point or points on the corresponding Bezier curve specified by `u`. If `curveind` is zero you
|
||||
// get the first curve. The number of curves is `(len(bezpath)-1)/N` so the maximum index is that number minus one.
|
||||
// Arguments:
|
||||
// path = A Bezier path path to approximate.
|
||||
// seg = Segment number along the path. Each segment is N points long.
|
||||
// bezpath = A Bezier path path to approximate.
|
||||
// curveind = Curve number along the path.
|
||||
// u = Parameter values for evaluating the curve, given as a single value, a list or a range.
|
||||
// N = The degree of the Bezier path curves. Cubic Bezier paths have N=3. Default: 3
|
||||
function bezpath_points(bezpath, seg, u, N=3) =
|
||||
bezier_points(select(bezpath,seg*N,(seg+1)*N), u);
|
||||
// N = The degree of the Bezier path curves. Default: 3
|
||||
function bezpath_points(bezpath, curveind, u, N=3) =
|
||||
bezier_points(select(bezpath,curveind*N,(curveind+1)*N), u);
|
||||
|
||||
|
||||
// Function: bezpath_curve()
|
||||
|
@ -428,7 +432,7 @@ function bezpath_points(bezpath, seg, u, N=3) =
|
|||
// Takes a bezier path and converts it into a path of points.
|
||||
// Arguments:
|
||||
// bezpath = A bezier path to approximate.
|
||||
// splinesteps = Number of straight lines to split each bezier segment into. default=16
|
||||
// splinesteps = Number of straight lines to split each bezier curve into. default=16
|
||||
// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3
|
||||
// endpoint = If true, include the very last point of the bezier path. Default: true
|
||||
// Example(2D):
|
||||
|
@ -438,7 +442,7 @@ function bezpath_points(bezpath, seg, u, N=3) =
|
|||
// [60,25], [70,0], [80,-25],
|
||||
// [80,-50], [50,-50]
|
||||
// ];
|
||||
// trace_bezier(bez, N=3, width=2);
|
||||
// debug_bezier(bez, N=3, width=2);
|
||||
function bezpath_curve(bezpath, splinesteps=16, N=3, endpoint=true) =
|
||||
assert(is_path(bezpath))
|
||||
assert(is_int(N))
|
||||
|
@ -473,7 +477,7 @@ function bezpath_curve(bezpath, splinesteps=16, N=3, endpoint=true) =
|
|||
// [100,25], [140,25], [160,0]];
|
||||
// pos = bezpath_closest_point(bez, pt);
|
||||
// xy = bezpath_points(bez,pos[0],pos[1]);
|
||||
// trace_bezier(bez, N=3);
|
||||
// debug_bezier(bez, N=3);
|
||||
// color("red") translate(pt) sphere(r=1);
|
||||
// color("blue") translate(xy) sphere(r=1);
|
||||
function bezpath_closest_point(bezpath, pt, N=3, max_err=0.01, seg=0, min_seg=undef, min_u=undef, min_dist=undef) =
|
||||
|
@ -626,12 +630,12 @@ function path_to_bezpath(path, closed, tangents, uniform=false, size, relsize) =
|
|||
// bez = [[50,30], [40,10], [10,50], [0,30],
|
||||
// [-10, 10], [-30,10], [-50,20]];
|
||||
// closed = bezpath_close_to_axis(bez);
|
||||
// trace_bezier(closed);
|
||||
// debug_bezier(closed);
|
||||
// Example(2D):
|
||||
// bez = [[30,50], [10,40], [50,10], [30,0],
|
||||
// [10, -10], [10,-30], [20,-50]];
|
||||
// closed = bezpath_close_to_axis(bez, axis="Y");
|
||||
// trace_bezier(closed);
|
||||
// debug_bezier(closed);
|
||||
function bezpath_close_to_axis(bezpath, axis="X", N=3) =
|
||||
assert(is_path(bezpath,2), "bezpath_close_to_axis() can only work on 2D bezier paths.")
|
||||
assert(is_int(N))
|
||||
|
@ -668,11 +672,11 @@ function bezpath_close_to_axis(bezpath, axis="X", N=3) =
|
|||
// Example(2D):
|
||||
// bez = [[50,30], [40,10], [10,50], [0,30], [-10, 10], [-30,10], [-50,20]];
|
||||
// closed = bezpath_offset([0,-5], bez);
|
||||
// trace_bezier(closed);
|
||||
// debug_bezier(closed);
|
||||
// Example(2D):
|
||||
// bez = [[30,50], [10,40], [50,10], [30,0], [10, -10], [10,-30], [20,-50]];
|
||||
// closed = bezpath_offset([-5,0], bez);
|
||||
// trace_bezier(closed);
|
||||
// debug_bezier(closed);
|
||||
function bezpath_offset(offset, bezier, N=3) =
|
||||
assert(is_vector(offset,2))
|
||||
assert(is_path(bezier,2), "bezpath_offset() can only work on 2D bezier paths.")
|
||||
|
@ -712,7 +716,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([ 20,-25], 135, 90, 10, 15),
|
||||
// bez_end ([ 50, 0], -90,20),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
// Example(2D): 2D Bezier Path by Vector
|
||||
// bezpath = flatten([
|
||||
// bez_begin([-50,0],[0,-20]),
|
||||
|
@ -720,7 +724,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([ 20,-25], [-10,10], [0,15]),
|
||||
// bez_end ([ 50,0],[0, 20]),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
// Example(2D): 2D Bezier Path by Vector and Distance
|
||||
// bezpath = flatten([
|
||||
// bez_begin([-30,0],FWD, 30),
|
||||
|
@ -728,7 +732,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([ 20,-25], 135, 90, 10, 15),
|
||||
// bez_end ([ 30,0],BACK,30),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
// Example(3D,FlatSpin,VPD=200): 3D Bezier Path by Angle
|
||||
// bezpath = flatten([
|
||||
// bez_begin([-30,0,0],90,20,p=135),
|
||||
|
@ -736,7 +740,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([20,-25,0], 135, 90, 15, 10, p1=135, p2=45),
|
||||
// bez_end ([ 30,0,0],-90,20,p=45),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
// Example(3D,FlatSpin,VPD=225): 3D Bezier Path by Vector
|
||||
// bezpath = flatten([
|
||||
// bez_begin([-30,0,0],[0,-20, 20]),
|
||||
|
@ -744,7 +748,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([20,-25,0],[0,10,-10],[0,15,15]),
|
||||
// bez_end ([ 30,0,0],[0,-20,-20]),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
// Example(3D,FlatSpin,VPD=225): 3D Bezier Path by Vector and Distance
|
||||
// bezpath = flatten([
|
||||
// bez_begin([-30,0,0],FWD, 20),
|
||||
|
@ -752,7 +756,7 @@ function bezpath_offset(offset, bezier, N=3) =
|
|||
// bez_joint([20,-25,0],LEFT,DOWN,r1=20,r2=15),
|
||||
// bez_end ([ 30,0,0],DOWN,20),
|
||||
// ]);
|
||||
// trace_bezier(bezpath);
|
||||
// debug_bezier(bezpath);
|
||||
function bez_begin(pt,a,r,p) =
|
||||
assert(is_finite(r) || is_vector(a))
|
||||
assert(len(pt)==3 || is_undef(p))
|
||||
|
@ -857,19 +861,70 @@ function bez_end(pt,a,r,p) =
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Section: Bezier Surfaces
|
||||
|
||||
|
||||
// Function: is_bezier_patch()
|
||||
// Usage:
|
||||
// bool = is_bezier_patch(x);
|
||||
// Topics: Bezier Patches, Type Checking
|
||||
// Description:
|
||||
// Returns true if the given item is a bezier patch.
|
||||
// Arguments:
|
||||
// x = The value to check the type of.
|
||||
function is_bezier_patch(x) =
|
||||
is_list(x) && is_list(x[0]) && is_vector(x[0][0]) && len(x[0]) == len(x[len(x)-1]);
|
||||
|
||||
|
||||
// Function: bezier_patch_flat()
|
||||
// Usage:
|
||||
// patch = bezier_patch_flat(size, [N=], [spin=], [orient=], [trans=]);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_patch_points()
|
||||
// Description:
|
||||
// Returns a flat rectangular bezier patch of degree `N`, centered on the XY plane.
|
||||
// Arguments:
|
||||
// size = 2D XY size of the patch.
|
||||
// ---
|
||||
// N = Degree of the patch to generate. Since this is flat, a degree of 1 should usually be sufficient.
|
||||
// orient = The orientation to rotate the edge patch into. Given as an [X,Y,Z] rotation angle list.
|
||||
// trans = Amount to translate patch, after rotating to `orient`.
|
||||
// Example(3D):
|
||||
// patch = bezier_patch_flat(size=[100,100], N=3);
|
||||
// debug_bezier_patches([patch], size=1, showcps=true);
|
||||
function bezier_patch_flat(size=[100,100], N=4, spin=0, orient=UP, trans=[0,0,0]) =
|
||||
let(
|
||||
patch = [
|
||||
for (x=[0:1:N]) [
|
||||
for (y=[0:1:N])
|
||||
v_mul(point3d(size), [x/N-0.5, 0.5-y/N, 0])
|
||||
]
|
||||
],
|
||||
m = move(trans) * rot(a=spin, from=UP, to=orient)
|
||||
) [for (row=patch) apply(m, row)];
|
||||
|
||||
|
||||
|
||||
// Function: bezier_patch_reverse()
|
||||
// Usage:
|
||||
// rpatch = bezier_patch_reverse(patch);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat()
|
||||
// Description:
|
||||
// Reverses the patch, so that the faces generated from it are flipped back to front.
|
||||
// Arguments:
|
||||
// patch = The patch to reverse.
|
||||
function bezier_patch_reverse(patch) =
|
||||
[for (row=patch) reverse(row)];
|
||||
|
||||
|
||||
// Function: bezier_patch_points()
|
||||
// Usage:
|
||||
// pt = bezier_patch_points(patch, u, v);
|
||||
// ptgrid = bezier_patch_points(patch, LIST, LIST);
|
||||
// ptgrid = bezier_patch_points(patch, RANGE, RANGE);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_points(), bezier_curve(), bezpath_curve(), bezier_triangle_point()
|
||||
// See Also: bezier_points(), bezier_curve(), bezpath_curve()
|
||||
// Description:
|
||||
// Given a square 2-dimensional array of (N+1) by (N+1) points size, that represents a Bezier Patch
|
||||
// of degree N, returns a point on that surface, at positions `u`, and `v`. A cubic bezier patch
|
||||
|
@ -886,7 +941,7 @@ function bez_end(pt,a,r,p) =
|
|||
// [[-50,-16, 20], [-16,-16, 40], [ 16,-16, 40], [50,-16, 20]],
|
||||
// [[-50,-50, 0], [-16,-50, 20], [ 16,-50, 20], [50,-50, 0]]
|
||||
// ];
|
||||
// trace_bezier_patches(patches=[patch], size=1, showcps=true);
|
||||
// debug_bezier_patches(patches=[patch], size=1, showcps=true);
|
||||
// pt = bezier_patch_points(patch, 0.6, 0.75);
|
||||
// translate(pt) color("magenta") sphere(d=3, $fn=12);
|
||||
// Example(3D): Getting Multiple Points at Once
|
||||
|
@ -896,7 +951,7 @@ function bez_end(pt,a,r,p) =
|
|||
// [[-50,-16, 20], [-16,-16, 40], [ 16,-16, 40], [50,-16, 20]],
|
||||
// [[-50,-50, 0], [-16,-50, 20], [ 16,-50, 20], [50,-50, 0]]
|
||||
// ];
|
||||
// trace_bezier_patches(patches=[patch], size=1, showcps=true);
|
||||
// debug_bezier_patches(patches=[patch], size=1, showcps=true);
|
||||
// pts = bezier_patch_points(patch, [0:0.2:1], [0:0.2:1]);
|
||||
// for (row=pts) move_copies(row) color("magenta") sphere(d=3, $fn=12);
|
||||
function bezier_patch_points(patch, u, v) =
|
||||
|
@ -909,94 +964,30 @@ function bezier_patch_points(patch, u, v) =
|
|||
[for (i = idx(vbezes[0])) bezier_points(column(vbezes,i), is_num(v)? [v] : v)];
|
||||
|
||||
|
||||
// Function: bezier_triangle_point()
|
||||
// Usage:
|
||||
// pt = bezier_triangle_point(tri, u, v);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_points(), bezier_curve(), bezpath_curve(), bezier_patch_points()
|
||||
// Description:
|
||||
// Given a triangular 2-dimensional array of N+1 by (for the first row) N+1 points,
|
||||
// that represents a Bezier triangular patch of degree N, returns a point on
|
||||
// that surface, at positions `u`, and `v`. A cubic bezier triangular patch
|
||||
// will have a list of 4 points in the first row, 3 in the second, 2 in the
|
||||
// third, and 1 in the last row.
|
||||
// Arguments:
|
||||
// tri = Triangular bezier patch to get point on.
|
||||
// u = The proportion of the way along the first dimension of the triangular patch to find the point of. 0<=`u`<=1
|
||||
// v = The proportion of the way along the second dimension of the triangular patch to find the point of. 0<=`v`<=(1-`u`)
|
||||
// Example(3D):
|
||||
// tri = [
|
||||
// [[-50,-33,0], [-25,16,40], [20,66,20]],
|
||||
// [[0,-33,30], [25,16,30]],
|
||||
// [[50,-33,0]]
|
||||
// ];
|
||||
// trace_bezier_patches(patches=[tri], size=1, showcps=true);
|
||||
// pt = bezier_triangle_point(tri, 0.5, 0.2);
|
||||
// translate(pt) color("magenta") sphere(d=3, $fn=12);
|
||||
function bezier_triangle_point(tri, u, v) =
|
||||
len(tri) == 1 ? tri[0][0] :
|
||||
function _bezier_rectangle(patch, splinesteps=16, style="default") =
|
||||
let(
|
||||
n = len(tri)-1,
|
||||
Pu = [for(i=[0:1:n-1]) [for (j=[1:1:len(tri[i])-1]) tri[i][j]]],
|
||||
Pv = [for(i=[0:1:n-1]) [for (j=[0:1:len(tri[i])-2]) tri[i][j]]],
|
||||
Pw = [for(i=[1:1:len(tri)-1]) tri[i]]
|
||||
uvals = lerpn(0,1,splinesteps.x+1),
|
||||
vvals = lerpn(1,0,splinesteps.y+1),
|
||||
pts = bezier_patch_points(patch, uvals, vvals)
|
||||
)
|
||||
bezier_triangle_point(u*Pu + v*Pv + (1-u-v)*Pw, u, v);
|
||||
vnf_vertex_array(pts, style=style, reverse=false);
|
||||
|
||||
|
||||
// Function: is_tripatch()
|
||||
// Function: bezier_vnf()
|
||||
// Usage:
|
||||
// bool = is_tripatch(x);
|
||||
// Topics: Bezier Patches, Type Checking
|
||||
// See Also: is_rectpatch(), is_patch()
|
||||
// Description:
|
||||
// Returns true if the given item is a triangular bezier patch.
|
||||
// Arguments:
|
||||
// x = The value to check the type of.
|
||||
function is_tripatch(x) =
|
||||
is_list(x) && is_list(x[0]) && is_vector(x[0][0]) && len(x[0])>1 && len(x[len(x)-1])==1;
|
||||
|
||||
|
||||
// Function: is_rectpatch()
|
||||
// Usage:
|
||||
// bool = is_rectpatch(x);
|
||||
// Topics: Bezier Patches, Type Checking
|
||||
// See Also: is_tripatch(), is_patch()
|
||||
// Description:
|
||||
// Returns true if the given item is a rectangular bezier patch.
|
||||
// Arguments:
|
||||
// x = The value to check the type of.
|
||||
function is_rectpatch(x) =
|
||||
is_list(x) && is_list(x[0]) && is_vector(x[0][0]) && len(x[0]) == len(x[len(x)-1]);
|
||||
|
||||
|
||||
// Function: is_patch()
|
||||
// Usage:
|
||||
// bool = is_patch(x);
|
||||
// Topics: Bezier Patches, Type Checking
|
||||
// See Also: is_tripatch(), is_rectpatch()
|
||||
// Description:
|
||||
// Returns true if the given item is a bezier patch.
|
||||
// Arguments:
|
||||
// x = The value to check the type of.
|
||||
function is_patch(x) =
|
||||
is_tripatch(x) || is_rectpatch(x);
|
||||
|
||||
|
||||
// Function: bezier_patch()
|
||||
// Usage:
|
||||
// vnf = bezier_patch(patch, [splinesteps], [style=]);
|
||||
// vnf = bezier_vnf(patches, [splinesteps], [style]);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_points(), bezier_curve(), bezpath_curve(), bezier_patch_points(), bezier_triangle_point()
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat()
|
||||
// Description:
|
||||
// Calculate vertices and faces for forming a partial polyhedron from the given bezier rectangular
|
||||
// or triangular patch. Returns a [VNF structure](vnf.scad): a list containing two elements. The first is the
|
||||
// list of unique vertices. The second is the list of faces, where each face is a list of indices into the
|
||||
// list of vertices. You can use {{vnf_join()}} to stitch together multiple bezier patches or other VNFs into a complete polyhedron.
|
||||
// Convert a patch or list of patches into the corresponding Bezier surface, representing the
|
||||
// result as a [VNF structure](vnf.scad). The `splinesteps` argument specifies the sampling grid of
|
||||
// the surface for each patch by specifying the number of segments on the borders of the surface.
|
||||
// It can be a scalar, which gives a uniform grid, or
|
||||
// it can be [USTEPS, VSTEPS], which gives difference spacing in the U and V parameters.
|
||||
// Note that the surface you produce may be disconnected and is not necessarily a valid manifold in OpenSCAD.
|
||||
// Arguments:
|
||||
// patch = The rectangular or triangular array of endpoints and control points for this bezier patch.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. For rectangular patches you can specify [XSTEPS,YSTEPS]. Default: 16
|
||||
// ---
|
||||
// patches = The bezier patch or list of bezier patches to convert into a vnf.
|
||||
// splinesteps = Number of segments on the border of the bezier surface. You can specify [USTEPS,VSTEPS]. Default: 16
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "min_edge", "quincunx", "convex" and "concave". See {{vnf_vertex_array()}}. Default: "default"
|
||||
// Example(3D):
|
||||
// patch = [
|
||||
|
@ -1007,17 +998,9 @@ function is_patch(x) =
|
|||
// [[-50, 50, 0], [-16, 50, -20], [ 16, 50, 20], [50, 50, 0]],
|
||||
// // u=0,v=1 u=1,v=1
|
||||
// ];
|
||||
// vnf = bezier_patch(patch, splinesteps=16);
|
||||
// vnf = bezier_vnf(patch, splinesteps=16);
|
||||
// vnf_polyhedron(vnf);
|
||||
// Example(3D):
|
||||
// tri = [
|
||||
// [[-50,-33,0], [-25,16,50], [0,66,0]],
|
||||
// [[0,-33,50], [25,16,50]],
|
||||
// [[50,-33,0]]
|
||||
// ];
|
||||
// vnf = bezier_patch(tri, splinesteps=16);
|
||||
// vnf_polyhedron(vnf);
|
||||
// Example(3D,FlatSpin,VPD=444): Merging multiple patches
|
||||
// Example(3D,FlatSpin,VPD=444): Combining multiple patches
|
||||
// patch = [
|
||||
// // u=0,v=0 u=1,v=0
|
||||
// [[0, 0,0], [33, 0, 0], [67, 0, 0], [100, 0,0]],
|
||||
|
@ -1027,15 +1010,30 @@ function is_patch(x) =
|
|||
// // u=0,v=1 u=1,v=1
|
||||
// ];
|
||||
// tpatch = translate([-50,-50,50], patch);
|
||||
// vnf = vnf_join([
|
||||
// bezier_patch(tpatch),
|
||||
// bezier_patch(xrot(90, tpatch)),
|
||||
// bezier_patch(xrot(-90, tpatch)),
|
||||
// bezier_patch(xrot(180, tpatch)),
|
||||
// bezier_patch(yrot(90, tpatch)),
|
||||
// bezier_patch(yrot(-90, tpatch))]);
|
||||
// vnf = bezier_vnf([
|
||||
// tpatch,
|
||||
// xrot(90, tpatch),
|
||||
// xrot(-90, tpatch),
|
||||
// xrot(180, tpatch),
|
||||
// yrot(90, tpatch),
|
||||
// yrot(-90, tpatch)]);
|
||||
// vnf_polyhedron(vnf);
|
||||
// Example(3D): Connecting Patches with Asymmetric Splinesteps
|
||||
// Example(3D):
|
||||
// patch1 = [
|
||||
// [[18,18,0], [33, 0, 0], [ 67, 0, 0], [ 82, 18,0]],
|
||||
// [[ 0,40,0], [ 0, 0,100], [100, 0, 20], [100, 40,0]],
|
||||
// [[ 0,60,0], [ 0,100,100], [100,100, 20], [100, 60,0]],
|
||||
// [[18,82,0], [33,100, 0], [ 67,100, 0], [ 82, 82,0]],
|
||||
// ];
|
||||
// patch2 = [
|
||||
// [[18,82,0], [33,100, 0], [ 67,100, 0], [ 82, 82,0]],
|
||||
// [[ 0,60,0], [ 0,100,-50], [100,100,-50], [100, 60,0]],
|
||||
// [[ 0,40,0], [ 0, 0,-50], [100, 0,-50], [100, 40,0]],
|
||||
// [[18,18,0], [33, 0, 0], [ 67, 0, 0], [ 82, 18,0]],
|
||||
// ];
|
||||
// vnf = bezier_vnf(patches=[patch1, patch2], splinesteps=16);
|
||||
// vnf_polyhedron(vnf);
|
||||
// Example(3D): Connecting Patches with asymmetric splinesteps. Note it is fastest to join all the VNFs at once, which happens in vnf_polyhedron, rather than generating intermediate joined partial surfaces.
|
||||
// steps = 8;
|
||||
// edge_patch = [
|
||||
// // u=0, v=0 u=1,v=0
|
||||
|
@ -1054,65 +1052,58 @@ function is_patch(x) =
|
|||
// face_patch = bezier_patch_flat([120,120],orient=LEFT);
|
||||
// edges = [
|
||||
// for (axrot=[[0,0,0],[0,90,0],[0,0,90]], xang=[-90:90:180])
|
||||
// bezier_patch(
|
||||
// splinesteps=[steps,1],
|
||||
// rot(a=axrot,
|
||||
// p=rot(a=[xang,0,0],
|
||||
// p=translate(v=[0,-100,100],p=edge_patch)
|
||||
// bezier_vnf(
|
||||
// splinesteps=[steps,1],
|
||||
// rot(a=axrot,
|
||||
// p=rot(a=[xang,0,0],
|
||||
// p=translate(v=[0,-100,100],p=edge_patch)
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ];
|
||||
// corners = [
|
||||
// for (xang=[0,180], zang=[-90:90:180])
|
||||
// bezier_patch(
|
||||
// splinesteps=steps,
|
||||
// rot(a=[xang,0,zang],
|
||||
// p=translate(v=[-100,-100,100],p=corner_patch)
|
||||
// bezier_vnf(
|
||||
// splinesteps=steps,
|
||||
// rot(a=[xang,0,zang],
|
||||
// p=translate(v=[-100,-100,100],p=corner_patch)
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ];
|
||||
// faces = [
|
||||
// for (axrot=[[0,0,0],[0,90,0],[0,0,90]], zang=[0,180])
|
||||
// bezier_patch(
|
||||
// splinesteps=1,
|
||||
// rot(a=axrot,
|
||||
// p=rot(a=[0,0,zang],
|
||||
// p=move([-100,0,0], p=face_patch)
|
||||
// bezier_vnf(
|
||||
// splinesteps=1,
|
||||
// rot(a=axrot,
|
||||
// p=zrot(zang,move([-100,0,0], face_patch))
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ];
|
||||
// vnf_polyhedron(concat(edges,corners,faces));
|
||||
function bezier_patch(patch, splinesteps=16, style="default") =
|
||||
function bezier_vnf(patches=[], splinesteps=16, style="default") =
|
||||
assert(is_num(splinesteps) || is_vector(splinesteps,2))
|
||||
assert(all_positive(splinesteps))
|
||||
is_tripatch(patch)? _bezier_triangle(patch, splinesteps=splinesteps) :
|
||||
let(
|
||||
splinesteps = is_list(splinesteps) ? splinesteps : [splinesteps,splinesteps],
|
||||
uvals = [
|
||||
for(step=[0:1:splinesteps.x])
|
||||
step/splinesteps.x
|
||||
],
|
||||
vvals = [
|
||||
for(step=[0:1:splinesteps.y])
|
||||
1-step/splinesteps.y
|
||||
],
|
||||
pts = bezier_patch_points(patch, uvals, vvals),
|
||||
vnf = vnf_vertex_array(pts, style=style, reverse=false)
|
||||
) vnf;
|
||||
let(splinesteps = force_list(splinesteps,2))
|
||||
is_bezier_patch(patches)? _bezier_rectangle(patches, splinesteps=splinesteps,style=style)
|
||||
: assert(is_list(patches),"Invalid patch list")
|
||||
vnf_join(
|
||||
[
|
||||
for (patch=patches)
|
||||
is_bezier_patch(patch)? _bezier_rectangle(patch, splinesteps=splinesteps,style=style)
|
||||
: assert(false,"Invalid patch list")
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
// Function: bezier_patch_degenerate()
|
||||
// Function: bezier_vnf_degenerate_patch()
|
||||
// Usage:
|
||||
// vnf = bezier_patch_degenerate(patch, [splinesteps], [reverse]);
|
||||
// vnf_edges = bezier_patch_degenerate(patch, [splinesteps], [reverse], return_edges=true);
|
||||
// vnf = bezier_vnf_degenerate_patch(patch, [splinesteps], [reverse]);
|
||||
// vnf_edges = bezier_vnf_degenerate_patch(patch, [splinesteps], [reverse], return_edges=true);
|
||||
// Description:
|
||||
// Returns a VNF for a degenerate rectangular bezier patch where some of the corners of the patch are
|
||||
// equal. If the resulting patch has no faces then returns an empty VNF. Note that due to the degeneracy,
|
||||
// the shape of the patch can be triangular even though the actual underlying patch is a rectangle. This is
|
||||
// a different method for creating triangular bezier patches than the triangular patch.
|
||||
// the shape of the surface can be triangular even though the underlying patch is a rectangle.
|
||||
// If you specify return_edges then the return is a list whose first element is the vnf and whose second
|
||||
// element lists the edges in the order [left, right, top, bottom], where each list is a list of the actual
|
||||
// point values, but possibly only a single point if that edge is degenerate.
|
||||
|
@ -1133,9 +1124,9 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe((bezier_patch(patch, splinesteps)),width=0.1);
|
||||
// vnf_wireframe((bezier_vnf(patch, splinesteps)),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example(3D,NoAxes): With bezier_patch_degenerate the degenerate point does not have excess triangles. The top half of the patch decreases the number of sampled points by 2 for each row.
|
||||
// Example(3D,NoAxes): With bezier_vnf_degenerate_patch the degenerate point does not have excess triangles. The top half of the patch decreases the number of sampled points by 2 for each row.
|
||||
// splinesteps=8;
|
||||
// patch=[
|
||||
// repeat([-12.5, 12.5, 15],5),
|
||||
|
@ -1144,7 +1135,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example(3D,NoAxes): With splinesteps odd you get one "odd" row where the point count decreases by 1 instead of 2. You may prefer even values for splinesteps to avoid this.
|
||||
// splinesteps=7;
|
||||
|
@ -1155,7 +1146,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example(3D,NoAxes): A more extreme degeneracy occurs when the top half of a patch is degenerate to a line. (For odd length patches the middle row must be degenerate to trigger this style.) In this case the number of points in each row decreases by 1 for every row. It doesn't matter of splinesteps is odd or even.
|
||||
// splinesteps=8;
|
||||
|
@ -1165,7 +1156,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([0,0,5],5),
|
||||
// repeat([0,0,10],5)
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example(3D,NoScales): Here is a degenerate cubic patch.
|
||||
// splinesteps=8;
|
||||
|
@ -1175,7 +1166,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([0,0,30],4)
|
||||
// ];
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// Example(3D,NoScales): A more extreme degenerate cubic patch, where two rows are equal.
|
||||
// splinesteps=8;
|
||||
// patch = [ [ [-20,0,0], [-10,0,0],[0,10,0],[0,20,0] ],
|
||||
|
@ -1184,13 +1175,13 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([-10,10,30],4)
|
||||
// ];
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// Example(3D,NoScales): Quadratic patch degenerate at the right side:
|
||||
// splinesteps=8;
|
||||
// patch = [[[0, -10, 0],[10, -5, 0],[20, 0, 0]],
|
||||
// [[0, 0, 0], [10, 0, 0], [20, 0, 0]],
|
||||
// [[0, 0, 10], [10, 0, 5], [20, 0, 0]]];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example(3D,NoAxes): Cubic patch degenerate at both ends. In this case the point count changes by 2 at every row.
|
||||
// splinesteps=8;
|
||||
|
@ -1200,11 +1191,11 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [ [-20,0,10], [-10,0,10],[0,10,10],[0,20,10] ],
|
||||
// repeat([-10,10,20],4),
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// vnf_wireframe(bezier_vnf_degenerate_patch(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
function bezier_patch_degenerate(patch, splinesteps=16, reverse=false, return_edges=false) =
|
||||
!return_edges ? bezier_patch_degenerate(patch, splinesteps, reverse, true)[0] :
|
||||
assert(is_rectpatch(patch), "Must supply rectangular bezier patch")
|
||||
function bezier_vnf_degenerate_patch(patch, splinesteps=16, reverse=false, return_edges=false) =
|
||||
!return_edges ? bezier_vnf_degenerate_patch(patch, splinesteps, reverse, true)[0] :
|
||||
assert(is_bezier_patch(patch), "Input is not a Bezier patch")
|
||||
assert(is_int(splinesteps) && splinesteps>0, "splinesteps must be a positive integer")
|
||||
let(
|
||||
row_degen = [for(row=patch) all_equal(row)],
|
||||
|
@ -1254,7 +1245,7 @@ function bezier_patch_degenerate(patch, splinesteps=16, reverse=false, return_ed
|
|||
] :
|
||||
bot_degen ? // only bottom is degenerate
|
||||
let(
|
||||
result = bezier_patch_degenerate(reverse(patch), splinesteps=splinesteps, reverse=!reverse, return_edges=true)
|
||||
result = bezier_vnf_degenerate_patch(reverse(patch), splinesteps=splinesteps, reverse=!reverse, return_edges=true)
|
||||
)
|
||||
[
|
||||
result[0],
|
||||
|
@ -1282,129 +1273,21 @@ function bezier_patch_degenerate(patch, splinesteps=16, reverse=false, return_ed
|
|||
] :
|
||||
// must have left or right degeneracy, so transpose and recurse
|
||||
let(
|
||||
result = bezier_patch_degenerate(transpose(patch), splinesteps=splinesteps, reverse=!reverse, return_edges=true)
|
||||
result = bezier_vnf_degenerate_patch(transpose(patch), splinesteps=splinesteps, reverse=!reverse, return_edges=true)
|
||||
)
|
||||
[result[0],
|
||||
select(result[1],[2,3,0,1])
|
||||
];
|
||||
|
||||
|
||||
function _tri_count(n) = (n*(1+n))/2;
|
||||
|
||||
|
||||
function _bezier_triangle(tri, splinesteps=16) =
|
||||
assert(is_num(splinesteps))
|
||||
let(
|
||||
pts = [
|
||||
for (
|
||||
u=[0:1:splinesteps],
|
||||
v=[0:1:splinesteps-u]
|
||||
) bezier_triangle_point(tri, u/splinesteps, v/splinesteps)
|
||||
],
|
||||
tricnt = _tri_count(splinesteps+1),
|
||||
faces = [
|
||||
for (
|
||||
u=[0:1:splinesteps-1],
|
||||
v=[0:1:splinesteps-u-1]
|
||||
) let (
|
||||
v1 = v + (tricnt - _tri_count(splinesteps+1-u)),
|
||||
v2 = v1 + 1,
|
||||
v3 = v + (tricnt - _tri_count(splinesteps-u)),
|
||||
v4 = v3 + 1,
|
||||
allfaces = concat(
|
||||
[[v1,v2,v3]],
|
||||
((u<splinesteps-1 && v<splinesteps-u-1)? [[v2,v4,v3]] : [])
|
||||
)
|
||||
) for (face=allfaces) face
|
||||
]
|
||||
) [pts, faces];
|
||||
|
||||
|
||||
|
||||
// Function: bezier_patch_flat()
|
||||
// Usage:
|
||||
// patch = bezier_patch_flat(size, [N=], [spin=], [orient=], [trans=]);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_patch_points()
|
||||
// Description:
|
||||
// Returns a flat rectangular bezier patch of degree `N`, centered on the XY plane.
|
||||
// Arguments:
|
||||
// size = 2D XY size of the patch.
|
||||
// ---
|
||||
// N = Degree of the patch to generate. Since this is flat, a degree of 1 should usually be sufficient.
|
||||
// orient = The orientation to rotate the edge patch into. Given as an [X,Y,Z] rotation angle list.
|
||||
// trans = Amount to translate patch, after rotating to `orient`.
|
||||
// Example(3D):
|
||||
// patch = bezier_patch_flat(size=[100,100], N=3);
|
||||
// trace_bezier_patches([patch], size=1, showcps=true);
|
||||
function bezier_patch_flat(size=[100,100], N=4, spin=0, orient=UP, trans=[0,0,0]) =
|
||||
let(
|
||||
patch = [
|
||||
for (x=[0:1:N]) [
|
||||
for (y=[0:1:N])
|
||||
v_mul(point3d(size), [x/N-0.5, 0.5-y/N, 0])
|
||||
]
|
||||
],
|
||||
m = move(trans) * rot(a=spin, from=UP, to=orient)
|
||||
) [for (row=patch) apply(m, row)];
|
||||
|
||||
|
||||
|
||||
// Function: patch_reverse()
|
||||
// Usage:
|
||||
// rpatch = patch_reverse(patch);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat()
|
||||
// Description:
|
||||
// Reverses the patch, so that the faces generated from it are flipped back to front.
|
||||
// Arguments:
|
||||
// patch = The patch to reverse.
|
||||
function patch_reverse(patch) =
|
||||
[for (row=patch) reverse(row)];
|
||||
|
||||
|
||||
// Section: Bezier Surface Modules
|
||||
|
||||
|
||||
// Function: bezier_surface()
|
||||
// Usage:
|
||||
// vnf = bezier_surface(patches, [splinesteps], [style]);
|
||||
// Topics: Bezier Patches
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat()
|
||||
// Description:
|
||||
// Calculate vertices and faces for forming a (possibly partial) polyhedron from the given
|
||||
// rectangular and/or triangular bezier patches. Returns a [VNF structure](vnf.scad): a list
|
||||
// containing two elements. The first is the the list of vertices. The second is the list
|
||||
// of faces, where each face is a list of indices into the list of vertices.
|
||||
// Arguments:
|
||||
// patches = A list of triangular and/or rectangular bezier patches.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", and "quincunx".
|
||||
// Example(3D):
|
||||
// patch1 = [
|
||||
// [[18,18,0], [33, 0, 0], [ 67, 0, 0], [ 82, 18,0]],
|
||||
// [[ 0,40,0], [ 0, 0,100], [100, 0, 20], [100, 40,0]],
|
||||
// [[ 0,60,0], [ 0,100,100], [100,100, 20], [100, 60,0]],
|
||||
// [[18,82,0], [33,100, 0], [ 67,100, 0], [ 82, 82,0]],
|
||||
// ];
|
||||
// patch2 = [
|
||||
// [[18,82,0], [33,100, 0], [ 67,100, 0], [ 82, 82,0]],
|
||||
// [[ 0,60,0], [ 0,100,-50], [100,100,-50], [100, 60,0]],
|
||||
// [[ 0,40,0], [ 0, 0,-50], [100, 0,-50], [100, 40,0]],
|
||||
// [[18,18,0], [33, 0, 0], [ 67, 0, 0], [ 82, 18,0]],
|
||||
// ];
|
||||
// vnf = bezier_surface(patches=[patch1, patch2], splinesteps=16);
|
||||
// polyhedron(points=vnf[0], faces=vnf[1]);
|
||||
function bezier_surface(patches=[], splinesteps=16, style="default") =
|
||||
vnf_join([for(patch=patches) bezier_patch(patch, splinesteps=splinesteps, style=style)]);
|
||||
|
||||
|
||||
// Section: Debugging Beziers
|
||||
|
||||
|
||||
// Module: trace_bezier()
|
||||
// Module: debug_bezier()
|
||||
// Usage:
|
||||
// trace_bezier(bez, [size], [N=]);
|
||||
// debug_bezier(bez, [size], [N=]);
|
||||
// Topics: Bezier Paths, Debugging
|
||||
// See Also: bezpath_curve()
|
||||
// Description:
|
||||
|
@ -1422,8 +1305,8 @@ function bezier_surface(patches=[], splinesteps=16, style="default") =
|
|||
// [ 14, -5], [ 15, 0], [16, 5],
|
||||
// [ 5, 10], [ 0, 10]
|
||||
// ];
|
||||
// trace_bezier(bez, N=3, width=0.5);
|
||||
module trace_bezier(bezpath, width=1, N=3) {
|
||||
// debug_bezier(bez, N=3, width=0.5);
|
||||
module debug_bezier(bezpath, width=1, N=3) {
|
||||
assert(is_path(bezpath));
|
||||
assert(is_int(N));
|
||||
assert(len(bezpath)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||
|
@ -1453,17 +1336,17 @@ module trace_bezier(bezpath, width=1, N=3) {
|
|||
}
|
||||
|
||||
|
||||
// Module: trace_bezier_patches()
|
||||
// Module: debug_bezier_patches()
|
||||
// Usage:
|
||||
// trace_bezier_patches(patches, [size=], [splinesteps=], [showcps=], [showdots=], [showpatch=], [convexity=], [style=]);
|
||||
// debug_bezier_patches(patches, [size=], [splinesteps=], [showcps=], [showdots=], [showpatch=], [convexity=], [style=]);
|
||||
// Topics: Bezier Patches, Debugging
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat(), bezier_surface()
|
||||
// See Also: bezier_patch_points(), bezier_patch_flat(), bezier_vnf()
|
||||
// Description:
|
||||
// Shows the surface, and optionally, control points of a list of bezier patches.
|
||||
// Arguments:
|
||||
// patches = A list of rectangular bezier patches.
|
||||
// ---
|
||||
// splinesteps = Number of steps to divide each bezier segment into. default=16
|
||||
// splinesteps = Number of segments to divide each bezier curve into. Default: 16
|
||||
// showcps = If true, show the controlpoints as well as the surface. Default: true.
|
||||
// showdots = If true, shows the calculated surface vertices. Default: false.
|
||||
// showpatch = If true, shows the surface faces. Default: true.
|
||||
|
@ -1483,12 +1366,12 @@ module trace_bezier(bezpath, width=1, N=3) {
|
|||
// [[ 0,33,0], [33, 33,-50], [ 67, 33,-50], [100, 33,0]],
|
||||
// [[15,15,0], [33, 0, 0], [ 67, 0, 0], [ 85, 15,0]],
|
||||
// ];
|
||||
// trace_bezier_patches(patches=[patch1, patch2], splinesteps=8, showcps=true);
|
||||
module trace_bezier_patches(patches=[], size, splinesteps=16, showcps=true, showdots=false, showpatch=true, convexity=10, style="default")
|
||||
// debug_bezier_patches(patches=[patch1, patch2], splinesteps=8, showcps=true);
|
||||
module debug_bezier_patches(patches=[], size, splinesteps=16, showcps=true, showdots=false, showpatch=true, convexity=10, style="default")
|
||||
{
|
||||
assert(is_undef(size)||is_num(size));
|
||||
assert(is_int(splinesteps) && splinesteps>0);
|
||||
assert(is_list(patches) && all([for (patch=patches) is_patch(patch)]));
|
||||
assert(is_list(patches) && all([for (patch=patches) is_bezier_patch(patch)]));
|
||||
assert(is_bool(showcps));
|
||||
assert(is_bool(showdots));
|
||||
assert(is_bool(showpatch));
|
||||
|
@ -1499,23 +1382,14 @@ module trace_bezier_patches(patches=[], size, splinesteps=16, showcps=true, show
|
|||
max(bounds[1]-bounds[0])*0.01;
|
||||
if (showcps) {
|
||||
move_copies(flatten(patch)) color("red") sphere(d=size*2);
|
||||
color("cyan") {
|
||||
if (is_tripatch(patch)) {
|
||||
for (i=[0:1:len(patch)-2], j=[0:1:len(patch[i])-2]) {
|
||||
extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size);
|
||||
extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
|
||||
extrude_from_to(patch[i+1][j], patch[i][j+1]) circle(d=size);
|
||||
}
|
||||
} else {
|
||||
for (i=[0:1:len(patch)-1], j=[0:1:len(patch[i])-1]) {
|
||||
if (i<len(patch)-1) extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size);
|
||||
if (j<len(patch[i])-1) extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
|
||||
}
|
||||
}
|
||||
}
|
||||
color("cyan")
|
||||
for (i=[0:1:len(patch)-1], j=[0:1:len(patch[i])-1]) {
|
||||
if (i<len(patch)-1) extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size);
|
||||
if (j<len(patch[i])-1) extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
|
||||
}
|
||||
}
|
||||
if (showpatch || showdots){
|
||||
vnf = bezier_patch(patch, splinesteps=splinesteps, style=style);
|
||||
vnf = bezier_vnf(patch, splinesteps=splinesteps, style=style);
|
||||
if (showpatch) vnf_polyhedron(vnf, convexity=convexity);
|
||||
if (showdots) color("blue") move_copies(vnf[0]) sphere(d=size);
|
||||
}
|
||||
|
|
|
@ -1803,21 +1803,21 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([path3d(poly),[]],faces=false,size=1);
|
||||
// color("black") up(3) debug_vnf([path3d(poly),[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with a hole and one "contact" edge; see from above
|
||||
// poly = [ [-10,0], [10,0], [0,10], [-10,0], [-4,4], [4,4], [0,2], [-4,4] ];
|
||||
// tris = polygon_triangulate(poly);
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([path3d(poly),[]],faces=false,size=1);
|
||||
// color("black") up(3) debug_vnf([path3d(poly),[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with "touching" vertices and no holes; see from above
|
||||
// poly = [ [0,0], [5,5], [-5,5], [0,0], [-5,-5], [5,-5] ];
|
||||
// tris = polygon_triangulate(poly);
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([path3d(poly),[]],faces=false,size=1);
|
||||
// color("black") up(3) debug_vnf([path3d(poly),[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with "contact" edges and no holes; see from above
|
||||
// poly = [ [0,0], [10,0], [10,10], [0,10], [0,0], [3,3], [7,3],
|
||||
// [7,7], [7,3], [3,3] ];
|
||||
|
@ -1825,7 +1825,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([path3d(poly),[]],faces=false,size=1);
|
||||
// color("black") up(3) debug_vnf([path3d(poly),[]],faces=false,size=1);
|
||||
// Example(3D):
|
||||
// include <BOSL2/polyhedra.scad>
|
||||
// vnf = regular_polyhedron_info(name="dodecahedron",side=5,info="vnf");
|
||||
|
|
|
@ -347,7 +347,7 @@ function _bezcorner(points, parm) =
|
|||
] : _smooth_bez_fill(points,parm),
|
||||
N = max(3,$fn>0 ?$fn : ceil(bezier_length(P)/$fs))
|
||||
)
|
||||
bezier_curve(P,N+1,endpoint=true);
|
||||
bezier_curve(P,N,endpoint=true);
|
||||
|
||||
function _chamfcorner(points, parm) =
|
||||
let(
|
||||
|
@ -1829,7 +1829,7 @@ module rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_bot
|
|||
{
|
||||
if (debug){
|
||||
vnf_polyhedron(vnf, convexity=convexity);
|
||||
trace_bezier_patches(result[0], showcps=true, splinesteps=splinesteps, $fn=16, showdots=false, showpatch=false);
|
||||
debug_bezier_patches(result[0], showcps=true, splinesteps=splinesteps, $fn=16, showdots=false, showpatch=false);
|
||||
}
|
||||
else vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
|
@ -1918,8 +1918,8 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
|
|||
let(
|
||||
// Entries in the next two lists have the form [edges, vnf] where
|
||||
// edges is a list [leftedge, rightedge, topedge, botedge]
|
||||
top_samples = [for(patch=top_patch) bezier_patch_degenerate(patch,splinesteps,reverse=false,return_edges=true) ],
|
||||
bot_samples = [for(patch=bot_patch) bezier_patch_degenerate(patch,splinesteps,reverse=true,return_edges=true) ],
|
||||
top_samples = [for(patch=top_patch) bezier_vnf_degenerate_patch(patch,splinesteps,reverse=false,return_edges=true) ],
|
||||
bot_samples = [for(patch=bot_patch) bezier_vnf_degenerate_patch(patch,splinesteps,reverse=true,return_edges=true) ],
|
||||
leftidx=0,
|
||||
rightidx=1,
|
||||
topidx=2,
|
||||
|
|
8
vnf.scad
8
vnf.scad
|
@ -1240,9 +1240,9 @@ module _show_faces(vertices, faces, size=1) {
|
|||
|
||||
|
||||
|
||||
// Module: vnf_debug()
|
||||
// Module: debug_vnf()
|
||||
// Usage:
|
||||
// vnf_debug(vnfs, [faces], [vertices], [opacity], [size], [convexity]);
|
||||
// debug_vnf(vnfs, [faces], [vertices], [opacity], [size], [convexity]);
|
||||
// Description:
|
||||
// A drop-in module to replace `vnf_polyhedron()` to help debug vertices and faces.
|
||||
// Draws all the vertices at their 3D position, numbered in blue by their
|
||||
|
@ -1266,8 +1266,8 @@ module _show_faces(vertices, faces, size=1) {
|
|||
// Example(EdgesMed):
|
||||
// verts = [for (z=[-10,10], a=[0:120:359.9]) [10*cos(a),10*sin(a),z]];
|
||||
// faces = [[0,1,2], [5,4,3], [0,3,4], [0,4,1], [1,4,5], [1,5,2], [2,5,3], [2,3,0]];
|
||||
// vnf_debug([verts,faces], size=2);
|
||||
module vnf_debug(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=6 ) {
|
||||
// debug_vnf([verts,faces], size=2);
|
||||
module debug_vnf(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=6 ) {
|
||||
no_children($children);
|
||||
if (faces)
|
||||
_show_faces(vertices=vnf[0], faces=vnf[1], size=size);
|
||||
|
|
Loading…
Reference in a new issue