mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-04 03:09:45 +00:00
commit
7992c7b8a0
5 changed files with 121 additions and 271 deletions
44
affine.scad
44
affine.scad
|
@ -274,7 +274,7 @@ function affine3d_rot_from_to(from, to) =
|
|||
// Returns a transformation that maps one coordinate frame to another. You must specify two or three of `x`, `y`, and `z`. The specified
|
||||
// axes are mapped to the vectors you supplied. If you give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand coordinate system.
|
||||
// If the vectors you give are orthogonal the result will be a rotation and the `reverse` parameter will supply the inverse map, which enables you
|
||||
// to map two arbitrary coordinate systems to each other by using the canonical coordinate system as an intermediary. You cannot use the `reverse` option
|
||||
// to map two arbitrary coordinate systems to each other by using the canonical coordinate system as an intermediary. You cannot use the `reverse` option
|
||||
// with non-orthogonal inputs.
|
||||
// Arguments:
|
||||
// x = Destination vector for x axis
|
||||
|
@ -423,24 +423,28 @@ function affine3d_chain(affines, _m=undef, _i=0) =
|
|||
// pts = apply(transform, points);
|
||||
// Description:
|
||||
// Applies the specified transformation matrix to a point list (or single point). Both inputs can be 2d or 3d, and it is also allowed
|
||||
// to supply 3d transformations with 2d data as long as the the only action on the z coordinate is a simple scaling.
|
||||
// to supply 3d transformations with 2d data as long as the the only action on the z coordinate is a simple scaling.
|
||||
// Examples:
|
||||
// transformed = apply(xrot(45), path3d(circle(r=3))); // Rotates 3d circle data around x axis
|
||||
// transformed = apply(rot(45), circle(r=3)); // Rotates 2d circle data by 45 deg
|
||||
// transformed = apply(rot(45)*right(4)*scale(3), circle(r=3)); // Scales, translates and rotates 2d circle data
|
||||
function apply(transform,points) =
|
||||
points==[] ? [] :
|
||||
is_vector(points) ? apply(transform, [points])[0] :
|
||||
let(
|
||||
tdim = len(transform[0])-1,
|
||||
datadim = len(points[0])
|
||||
)
|
||||
tdim == 3 && datadim == 3 ? [for(p=points) point3d(transform*concat(p,[1]))] :
|
||||
tdim == 2 && datadim == 2 ? [for(p=points) point2d(transform*concat(p,[1]))] :
|
||||
tdim == 3 && datadim == 2 ?
|
||||
assert(is_2d_transform(transform),str("Transforms is 3d but points are 2d"))
|
||||
[for(p=points) point2d(transform*concat(p,[0,1]))] :
|
||||
assert(false,str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
|
||||
points==[] ? [] :
|
||||
is_vector(points) ? apply(transform, [points])[0] :
|
||||
is_list(points) && len(points)==2 && is_path(points[0],3) && is_list(points[1]) && is_vector(points[1][0])
|
||||
? [apply(transform, points[0]), points[1]] :
|
||||
is_list(points) && is_list(points[0]) && is_vector(points[0][0])
|
||||
? [for (x=points) apply(transform,x)] :
|
||||
let(
|
||||
tdim = len(transform[0])-1,
|
||||
datadim = len(points[0])
|
||||
)
|
||||
tdim == 3 && datadim == 3 ? [for(p=points) point3d(transform*concat(p,[1]))] :
|
||||
tdim == 2 && datadim == 2 ? [for(p=points) point2d(transform*concat(p,[1]))] :
|
||||
tdim == 3 && datadim == 2 ?
|
||||
assert(is_2d_transform(transform), str("Transforms is 3d but points are 2d"))
|
||||
[for(p=points) point2d(transform*concat(p,[0,1]))] :
|
||||
assert(false, str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
|
||||
|
||||
|
||||
// Function: apply_list()
|
||||
|
@ -451,7 +455,7 @@ function apply(transform,points) =
|
|||
// the list are applied in the order they appear in the list (as in right multiplication of matrices). Both inputs can be
|
||||
// 2d or 3d, and it is also allowed to supply 3d transformations with 2d data as long as the the only action on the z coordinate
|
||||
// is a simple scaling. All transformations on `transform_list` must have the same dimension: you cannot mix 2d and 3d transformations
|
||||
// even when acting on 2d data.
|
||||
// even when acting on 2d data.
|
||||
// Examples:
|
||||
// transformed = apply_list(path3d(circle(r=3)),[xrot(45)]); // Rotates 3d circle data around x axis
|
||||
// transformed = apply_list(circle(r=3), [scale(3), right(4), rot(45)]); // Scales, then translates, and then rotates 2d circle data
|
||||
|
@ -466,21 +470,21 @@ function apply_list(points,transform_list) =
|
|||
let( tdim = tdims[1]-1 )
|
||||
tdim==2 && datadim == 2 ? apply(affine2d_chain(transform_list), points) :
|
||||
tdim==3 && datadim == 3 ? apply(affine3d_chain(transform_list), points) :
|
||||
tdim==3 && datadim == 2 ?
|
||||
tdim==3 && datadim == 2 ?
|
||||
let(
|
||||
badlist = [for(i=idx(transform_list)) if (!is_2d_transform(transform_list[i])) i]
|
||||
)
|
||||
assert(badlist==[],str("Transforms with indices ",badlist," are 3d but points are 2d"))
|
||||
apply(affine3d_chain(transform_list), points) :
|
||||
assert(false,str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
|
||||
|
||||
assert(false,str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
|
||||
|
||||
|
||||
// Function: is_2d_transform()
|
||||
// Usage:
|
||||
// x = is_2d_transform(t);
|
||||
// Description:
|
||||
// Checks if the input is a 3d transform that does not act on the z coordinate, except
|
||||
// possibly for a simple scaling of z. Note that an input which is only a zscale returns false.
|
||||
// possibly for a simple scaling of z. Note that an input which is only a zscale returns false.
|
||||
function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][2]!=1 so scale() works
|
||||
t[2][0]==0 && t[2][1]==0 && t[2][3]==0 && t[0][2] == 0 && t[1][2]==0 &&
|
||||
(t[2][2]==1 || !(t[0][0]==1 && t[0][1]==0 && t[1][0]==0 && t[1][1]==1)); // But rule out zscale()
|
||||
|
@ -499,7 +503,7 @@ function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][
|
|||
// This decomposition makes it possible to perform interpolation. If you construct a transformation using `rot`
|
||||
// the decoding may flip the axis (if you gave an angle outside of [0,180]). The returned axis will be a unit vector,
|
||||
// and the centerpoint lies on the plane through the origin that is perpendicular to the axis. It may be different
|
||||
// than the centerpoint you used to construct the transformation.
|
||||
// than the centerpoint you used to construct the transformation.
|
||||
// Example:
|
||||
// rot_decode(rot(45)); // Returns [45,[0,0,1], [0,0,0], [0,0,0]]
|
||||
// rot_decode(rot(a=37, v=[1,2,3], cp=[4,3,-7]))); // Returns [37, [0.26, 0.53, 0.80], [4.8, 4.6, -4.6], [0,0,0]]
|
||||
|
|
342
beziers.scad
342
beziers.scad
|
@ -36,11 +36,14 @@
|
|||
|
||||
// Function: bezier_points()
|
||||
// Usage:
|
||||
// bezier_points(curve, u)
|
||||
// pt = bezier_points(curve, u);
|
||||
// ptlist = bezier_points(curve, RANGE);
|
||||
// ptlist = bezier_points(curve, LIST);
|
||||
// Description:
|
||||
// Computes bezier points for bezier with control points specified by `curve` at parameter values specified by `u`, which can be a scalar or a list.
|
||||
// This function uses an optimized method which is best when `u` is a long list and the bezier degree is 10 or less.
|
||||
// The degree of the bezier curve given is `len(curve)-1`.
|
||||
// Computes bezier points for bezier with control points specified by `curve` at parameter values
|
||||
// specified by `u`, which can be a scalar or a list. This function uses an optimized method which
|
||||
// is best when `u` is a long list and the bezier degree is 10 or less. The degree of the bezier
|
||||
// curve given is `len(curve)-1`.
|
||||
// Arguments:
|
||||
// curve = The list of endpoints and control points for this bezier segment.
|
||||
// u = The proportion of the way along the curve to find the point of. 0<=`u`<=1 If given as a list or range, returns a list of point, one for each u value.
|
||||
|
@ -179,7 +182,9 @@ function _bezier_matrix(N) =
|
|||
|
||||
// Function: bezier_derivative()
|
||||
// Usage:
|
||||
// d = bezier_derivative(curve, u, [order]);
|
||||
// deriv = bezier_derivative(curve, u, <order>);
|
||||
// derivs = bezier_derivative(curve, LIST, <order>);
|
||||
// derivs = bezier_derivative(curve, RANGE, <order>);
|
||||
// Description:
|
||||
// Finds the `order`th derivative of the bezier segment at the given position `u`.
|
||||
// The degree of the bezier segment is one less than the number of points in `curve`.
|
||||
|
@ -199,7 +204,9 @@ function bezier_derivative(curve, u, order=1) =
|
|||
|
||||
// Function: bezier_tangent()
|
||||
// Usage:
|
||||
// tanvec= bezier_tangent(curve, u);
|
||||
// tanvec = bezier_tangent(curve, u);
|
||||
// tanvecs = bezier_tangent(curve, LIST);
|
||||
// tanvecs = bezier_tangent(curve, RANGE);
|
||||
// Description:
|
||||
// Returns the unit vector of the tangent at the given position `u` on the bezier segment `curve`.
|
||||
// Arguments:
|
||||
|
@ -216,6 +223,8 @@ function bezier_tangent(curve, u) =
|
|||
// Function: bezier_curvature()
|
||||
// Usage:
|
||||
// crv = bezier_curvature(curve, u);
|
||||
// crvlist = bezier_curvature(curve, LIST);
|
||||
// crvlist = bezier_curvature(curve, RANGE);
|
||||
// Description:
|
||||
// Returns the curvature value for the given position `u` on the bezier segment `curve`.
|
||||
// The curvature is the inverse of the radius of the tangent circle at the given point.
|
||||
|
@ -240,7 +249,7 @@ function bezier_curvature(curve, u) =
|
|||
|
||||
// Function: bezier_curve()
|
||||
// Usage:
|
||||
// bezier_curve(curve, n, [endpoint]);
|
||||
// path = bezier_curve(curve, n, <endpoint>);
|
||||
// Description:
|
||||
// Takes a list of bezier curve control points and generates n points along the bezier path.
|
||||
// Points start at the first control point and are sampled every `1/n`th
|
||||
|
@ -270,7 +279,7 @@ function bezier_curve(curve,n,endpoint) = [each bezier_points(curve, [0:1/n:(n-0
|
|||
|
||||
// Function: bezier_segment_closest_point()
|
||||
// Usage:
|
||||
// bezier_segment_closest_point(bezier,pt)
|
||||
// u = bezier_segment_closest_point(bezier, pt, <max_err>);
|
||||
// Description:
|
||||
// Finds the closest part of the given bezier segment to point `pt`.
|
||||
// The degree of the curve, N, is one less than the number of points in `curve`.
|
||||
|
@ -319,7 +328,7 @@ function bezier_segment_closest_point(curve, pt, max_err=0.01, u=0, end_u=1) =
|
|||
|
||||
// Function: bezier_segment_length()
|
||||
// Usage:
|
||||
// bezier_segment_length(curve, [start_u], [end_u], [max_deflect]);
|
||||
// pathlen = bezier_segment_length(curve, <start_u>, <end_u>, <max_deflect>);
|
||||
// Description:
|
||||
// Approximates the length of the bezier segment between start_u and end_u.
|
||||
// Arguments:
|
||||
|
@ -354,18 +363,19 @@ function bezier_segment_length(curve, start_u=0, end_u=1, max_deflect=0.01) =
|
|||
|
||||
// Function: fillet3pts()
|
||||
// Usage:
|
||||
// fillet3pts(p0, p1, p2, r|d);
|
||||
// bez_path_pts = fillet3pts(p0, p1, p2, r);
|
||||
// bez_path_pts = fillet3pts(p0, p1, p2, d=);
|
||||
// Description:
|
||||
// Takes three points, defining two line segments, and works out the
|
||||
// cubic (degree 3) bezier segment (and surrounding control points)
|
||||
// needed to approximate a rounding of the corner with radius `r`.
|
||||
// If there isn't room for a radius `r` rounding, uses the largest
|
||||
// radius that will fit. Returns [cp1, endpt1, cp2, cp3, endpt2, cp4]
|
||||
// Takes three points, defining two line segments, and works out the cubic (degree 3) bezier segment
|
||||
// (and surrounding control points) needed to approximate a rounding of the corner with radius `r`.
|
||||
// If there isn't room for a radius `r` rounding, uses the largest radius that will fit. Returns
|
||||
// [cp1, endpt1, cp2, cp3, endpt2, cp4]
|
||||
// Arguments:
|
||||
// p0 = The starting point.
|
||||
// p1 = The middle point.
|
||||
// p2 = The ending point.
|
||||
// r = The radius of the fillet/rounding.
|
||||
// ---
|
||||
// d = The diameter of the fillet/rounding.
|
||||
// maxerr = Max amount bezier curve should diverge from actual curve. Default: 0.1
|
||||
// Example(2D):
|
||||
|
@ -401,7 +411,9 @@ function fillet3pts(p0, p1, p2, r, d, maxerr=0.1, w=0.5, dw=0.25) = let(
|
|||
|
||||
// Function: bezier_path_point()
|
||||
// Usage:
|
||||
// bezier_path_point(path, seg, u, [N])
|
||||
// pt = bezier_path_point(path, seg, u, <N>);
|
||||
// ptlist = bezier_path_point(path, seg, LIST, <N>);
|
||||
// path = bezier_path_point(path, seg, RANGE, <N>);
|
||||
// Description:
|
||||
// Returns the coordinates of bezier path segment `seg` at position `u`.
|
||||
// Arguments:
|
||||
|
@ -416,7 +428,7 @@ function bezier_path_point(path, seg, u, N=3) =
|
|||
|
||||
// Function: bezier_path_closest_point()
|
||||
// Usage:
|
||||
// bezier_path_closest_point(bezier,pt)
|
||||
// res = bezier_path_closest_point(bezier,pt);
|
||||
// Description:
|
||||
// Finds the closest part of the given bezier path to point `pt`.
|
||||
// Returns [segnum, u] for the closest position on the bezier path to the given point `pt`.
|
||||
|
@ -458,7 +470,7 @@ function bezier_path_closest_point(path, pt, N=3, max_err=0.01, seg=0, min_seg=u
|
|||
|
||||
// Function: bezier_path_length()
|
||||
// Usage:
|
||||
// bezier_path_length(path, [N], [max_deflect]);
|
||||
// plen = bezier_path_length(path, <N>, <max_deflect>);
|
||||
// Description:
|
||||
// Approximates the length of the bezier path.
|
||||
// Arguments:
|
||||
|
@ -482,7 +494,7 @@ function bezier_path_length(path, N=3, max_deflect=0.001) =
|
|||
|
||||
// Function: bezier_path()
|
||||
// Usage:
|
||||
// bezier_path(bezier, [splinesteps], [N])
|
||||
// path = bezier_path(bezier, <splinesteps>, <N>)
|
||||
// Description:
|
||||
// Takes a bezier path and converts it into a path of points.
|
||||
// Arguments:
|
||||
|
@ -515,28 +527,29 @@ function bezier_path(bezier, splinesteps=16, N=3) =
|
|||
|
||||
// Function: path_to_bezier()
|
||||
// Usage:
|
||||
// path_to_bezier(path, [size|relsize], [tangents], [uniform], [closed])
|
||||
// bezpath = path_to_bezier(path, <closed>, <tangents>, <uniform>, <size=>|<relsize=>);
|
||||
// Description:
|
||||
// Given a 2d or 3d input path and optional list of tangent vectors, computes a cubic (dgree 3) bezier
|
||||
// path that passes through every poin on the input path and matches the tangent vectors. If you do
|
||||
// not supply the tangent it will be computed using path_tangents. If the path is closed specify this
|
||||
// by setting closed=true. The size or relsize parameter determines how far the curve can deviate from
|
||||
// Given a 2d or 3d input path and optional list of tangent vectors, computes a cubic (degree 3) bezier
|
||||
// path that passes through every point on the input path and matches the tangent vectors. If you do
|
||||
// not supply the tangent it will be computed using `path_tangents()`. If the path is closed specify this
|
||||
// by setting `closed=true`. The size or relsize parameter determines how far the curve can deviate from
|
||||
// the input path. In the case where the curve has a single hump, the size specifies the exact distance
|
||||
// between the specified path and the bezier. If you give relsize then it is relative to the segment
|
||||
// length (e.g. 0.05 means 5% of the segment length). In 2d when the bezier curve makes an S-curve
|
||||
// the size parameter specifies the sum of the deviations of the two peaks of the curve. In 3-space
|
||||
// the bezier curve may have three extrema: two maxima and one minimum. In this case the size specifies
|
||||
// the sum of the maxima minus the minimum. If you do not supply the tangents then they are
|
||||
// computed using path_tangents with uniform=false by default. Tangents computed on non-uniform
|
||||
// data tend to display overshoots. See smooth_path for examples.
|
||||
// the sum of the maxima minus the minimum. If you do not supply the tangents then they are computed
|
||||
// using `path_tangents()` with `uniform=false` by default. Tangents computed on non-uniform data tend
|
||||
// to display overshoots. See `smooth_path()` for examples.
|
||||
// Arguments:
|
||||
// path = 2d or 3d point list that the curve must pass through
|
||||
// size = absolute size specification for the curve, a number or vector
|
||||
// relsize = relative size specification for the curve, a number or vector. Default: 0.1.
|
||||
// path = 2D or 3D point list that the curve must pass through
|
||||
// closed = true if the curve is closed . Default: false
|
||||
// tangents = tangents constraining curve direction at each point
|
||||
// uniform = set to true to compute tangents with uniform=true. Default: false
|
||||
// closed = true if the curve is closed . Default: false
|
||||
function path_to_bezier(path, tangents, size, relsize, uniform=false, closed=false) =
|
||||
// ---
|
||||
// size = absolute size specification for the curve, a number or vector
|
||||
// relsize = relative size specification for the curve, a number or vector. Default: 0.1.
|
||||
function path_to_bezier(path, closed=false, tangents, uniform=false, size, relsize) =
|
||||
assert(is_bool(closed))
|
||||
assert(is_bool(uniform))
|
||||
assert(num_defined([size,relsize])<=1, "Can't define both size and relsize")
|
||||
|
@ -594,7 +607,7 @@ function path_to_bezier(path, tangents, size, relsize, uniform=false, closed=fal
|
|||
|
||||
// Function: fillet_path()
|
||||
// Usage:
|
||||
// fillet_path(pts, fillet, [maxerr]);
|
||||
// bezpath = fillet_path(pts, fillet, <maxerr>);
|
||||
// Description:
|
||||
// Takes a 3D path and fillets the corners, returning a 3d cubic (degree 3) bezier path.
|
||||
// Arguments:
|
||||
|
@ -621,13 +634,13 @@ function fillet_path(pts, fillet, maxerr=0.1) = concat(
|
|||
|
||||
// Function: bezier_close_to_axis()
|
||||
// Usage:
|
||||
// bezier_close_to_axis(bezier, [N], [axis]);
|
||||
// bezpath = bezier_close_to_axis(bezier, <axis>, <N>);
|
||||
// Description:
|
||||
// Takes a 2D bezier path and closes it to the specified axis.
|
||||
// Arguments:
|
||||
// bezier = The 2D bezier path to close to the axis.
|
||||
// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3
|
||||
// axis = The axis to close to, "X", or "Y". Default: "X"
|
||||
// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3
|
||||
// Example(2D):
|
||||
// bez = [[50,30], [40,10], [10,50], [0,30], [-10, 10], [-30,10], [-50,20]];
|
||||
// closed = bezier_close_to_axis(bez);
|
||||
|
@ -636,7 +649,7 @@ function fillet_path(pts, fillet, maxerr=0.1) = concat(
|
|||
// bez = [[30,50], [10,40], [50,10], [30,0], [10, -10], [10,-30], [20,-50]];
|
||||
// closed = bezier_close_to_axis(bez, axis="Y");
|
||||
// trace_bezier(closed, size=1);
|
||||
function bezier_close_to_axis(bezier, N=3, axis="X") =
|
||||
function bezier_close_to_axis(bezier, axis="X", N=3) =
|
||||
assert(is_path(bezier,2), "bezier_close_to_axis() can only work on 2D bezier paths.")
|
||||
assert(is_int(N))
|
||||
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."))
|
||||
|
@ -661,7 +674,7 @@ function bezier_close_to_axis(bezier, N=3, axis="X") =
|
|||
|
||||
// Function: bezier_offset()
|
||||
// Usage:
|
||||
// bezier_offset(offset, bezier, [N]);
|
||||
// bezpath = bezier_offset(offset, bezier, <N>);
|
||||
// Description:
|
||||
// Takes a 2D bezier path and closes it with a matching reversed path that is offset by the given `offset` [X,Y] distance.
|
||||
// Arguments:
|
||||
|
@ -698,7 +711,7 @@ function bezier_offset(offset, bezier, N=3) =
|
|||
|
||||
// Module: bezier_polygon()
|
||||
// Usage:
|
||||
// bezier_polygon(bezier, [splinesteps], [N]) {
|
||||
// bezier_polygon(bezier, <splinesteps>, <N>) {
|
||||
// Description:
|
||||
// Takes a closed 2D bezier path, and creates a 2D polygon from it.
|
||||
// Arguments:
|
||||
|
@ -725,171 +738,18 @@ module bezier_polygon(bezier, splinesteps=16, N=3) {
|
|||
}
|
||||
|
||||
|
||||
// Module: linear_sweep_bezier()
|
||||
// Usage:
|
||||
// linear_sweep_bezier(bezier, height, [splinesteps], [N], [center], [convexity], [twist], [slices], [scale]);
|
||||
// Description:
|
||||
// Takes a closed 2D bezier path, centered on the XY plane, and
|
||||
// extrudes it linearly upwards, forming a solid.
|
||||
// Arguments:
|
||||
// bezier = Array of 2D points of a bezier path, to be extruded.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. default=16
|
||||
// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3
|
||||
// convexity = max number of walls a line could pass through, for preview. default=10
|
||||
// twist = Angle in degrees to twist over the length of extrusion. default=0
|
||||
// scale = Relative size of top of extrusion to the bottom. default=1.0
|
||||
// slices = Number of vertical slices to use for twisted extrusion. default=20
|
||||
// center = If true, the extruded solid is centered vertically at z=0.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `BOTTOM`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example:
|
||||
// bez = [
|
||||
// [-10, 0], [-15, -5],
|
||||
// [ -5, -10], [ 0, -10], [ 5, -10],
|
||||
// [ 10, -5], [ 15, 0], [10, 5],
|
||||
// [ 5, 10], [ 0, 10], [-5, 10],
|
||||
// [ 25, -15], [-10, 0]
|
||||
// ];
|
||||
// linear_sweep_bezier(bez, height=20, splinesteps=32);
|
||||
module linear_sweep_bezier(bezier, height=100, splinesteps=16, N=3, center, convexity, twist, slices, scale, anchor, spin=0, orient=UP) {
|
||||
assert(is_path(bezier,2), "linear_sweep_bezier() can only work on 2D bezier paths.");
|
||||
assert(is_num(height));
|
||||
assert(is_int(splinesteps));
|
||||
assert(is_int(N));
|
||||
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||
maxx = max([for (pt = bezier) abs(pt[0])]);
|
||||
maxy = max([for (pt = bezier) abs(pt[1])]);
|
||||
anchor = get_anchor(anchor,center,BOT,BOT);
|
||||
attachable(anchor,spin,orient, size=[maxx*2,maxy*2,height]) {
|
||||
if (height > 0) {
|
||||
linear_extrude(height=height, center=true, convexity=convexity, twist=twist, slices=slices, scale=scale) {
|
||||
bezier_polygon(bezier, splinesteps=splinesteps, N=N);
|
||||
}
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: rotate_sweep_bezier()
|
||||
// Usage:
|
||||
// rotate_sweep_bezier(bezier, [splinesteps], [N], [convexity], [angle])
|
||||
// Description:
|
||||
// Takes a closed 2D bezier and rotates it around the Z axis, forming a solid.
|
||||
// Behaves like rotate_extrude(), except for beziers instead of shapes.
|
||||
// Arguments:
|
||||
// bezier = array of 2D points for the bezier path to rotate.
|
||||
// splinesteps = number of segments to divide each bezier segment into. default=16
|
||||
// N = number of points in each bezier segment. default=3 (cubic)
|
||||
// convexity = max number of walls a line could pass through, for preview. default=2
|
||||
// angle = Degrees of sweep to make. Default: 360
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example(Spin):
|
||||
// path = [
|
||||
// [ 0, 10], [ 50, 0], [ 50, 40],
|
||||
// [ 95, 40], [100, 40], [100, 45],
|
||||
// [ 95, 45], [ 66, 45], [ 0, 20],
|
||||
// [ 0, 12], [ 0, 12], [ 0, 10],
|
||||
// [ 0, 10]
|
||||
// ];
|
||||
// rotate_sweep_bezier(path, splinesteps=32, $fn=180);
|
||||
module rotate_sweep_bezier(bezier, splinesteps=16, N=3, convexity=undef, angle=360, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
assert(is_path(bezier,2), "rotate_sweep_bezier() can only work on 2D bezier paths.");
|
||||
assert(is_int(splinesteps));
|
||||
assert(is_int(N));
|
||||
assert(is_num(angle));
|
||||
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||
oline = bezier_path(bezier, splinesteps=splinesteps, N=N);
|
||||
maxx = max([for (pt = oline) abs(pt[0])]);
|
||||
miny = min(subindex(oline,1));
|
||||
maxy = max(subindex(oline,1));
|
||||
attachable(anchor,spin,orient, r=maxx, l=max(abs(miny),abs(maxy))*2) {
|
||||
rotate_extrude(convexity=convexity, angle=angle) {
|
||||
polygon(oline);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: bezier_path_extrude()
|
||||
// Usage:
|
||||
// bezier_path_extrude(bezier, [splinesteps], [N], [convexity], [clipsize]) ...
|
||||
// Description:
|
||||
// Extrudes 2D shape children along a bezier path.
|
||||
// Arguments:
|
||||
// bezier = array of points for the bezier path to extrude along.
|
||||
// splinesteps = number of segments to divide each bezier segment into. default=16
|
||||
// N = The degree of the bezier path to extrude.
|
||||
// convexity = max number of walls a line could pass through, for preview. default=2
|
||||
// clipsize = Size of cube to use for clipping beveled ends with.
|
||||
// Example(FR):
|
||||
// path = [ [0, 0, 0], [33, 33, 33], [66, -33, -33], [100, 0, 0] ];
|
||||
// bezier_path_extrude(path) difference(){
|
||||
// circle(r=10);
|
||||
// fwd(10/2) circle(r=8);
|
||||
// }
|
||||
module bezier_path_extrude(bezier, splinesteps=16, N=3, convexity=undef, clipsize=1000) {
|
||||
assert(is_path(bezier));
|
||||
assert(is_int(splinesteps));
|
||||
assert(is_int(N));
|
||||
assert(is_num(clipsize));
|
||||
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||
path = slice(bezier_path(bezier, splinesteps, N), 0, -1);
|
||||
path_extrude(path, convexity=convexity, clipsize=clipsize) children();
|
||||
}
|
||||
|
||||
|
||||
// Module: bezier_sweep_bezier()
|
||||
// Usage:
|
||||
// bezier_sweep_bezier(bezier, path, [pathsteps], [bezsteps], [bezN], [pathN]);
|
||||
// Description:
|
||||
// Takes a closed 2D bezier path, centered on the XY plane, and
|
||||
// extrudes it perpendicularly along a 3D bezier path, forming a solid.
|
||||
// Arguments:
|
||||
// bezier = Array of 2D points of a bezier path, to be extruded.
|
||||
// path = Array of 3D points of a bezier path, to extrude along.
|
||||
// pathsteps = number of steps to divide each path segment into.
|
||||
// bezsteps = number of steps to divide each bezier segment into.
|
||||
// bezN = number of points in each extruded bezier segment. default=3 (cubic)
|
||||
// pathN = number of points in each path bezier segment. default=3 (cubic)
|
||||
// Example(FlatSpin):
|
||||
// bez = [
|
||||
// [-10, 0], [-15, -5],
|
||||
// [ -5, -10], [ 0, -10], [ 5, -10],
|
||||
// [ 10, -5], [ 15, 0], [10, 5],
|
||||
// [ 5, 10], [ 0, 10], [-5, 10],
|
||||
// [ 25, -15], [-10, 0]
|
||||
// ];
|
||||
// path = [ [0, 0, 0], [33, 33, 33], [90, 33, -33], [100, 0, 0] ];
|
||||
// bezier_sweep_bezier(bez, path, pathsteps=32, bezsteps=16);
|
||||
module bezier_sweep_bezier(bezier, path, pathsteps=16, bezsteps=16, bezN=3, pathN=3) {
|
||||
assert(is_path(bezier,2), "Argument bezier must be a 2D bezier path.");
|
||||
assert(is_path(path));
|
||||
assert(is_int(pathsteps));
|
||||
assert(is_int(bezsteps));
|
||||
assert(is_int(bezN));
|
||||
assert(is_int(pathN));
|
||||
assert(len(bezier)%bezN == 1, str("For argument bezier, a degree ",bezN," bezier path shound have a multiple of ",bezN," points in it, plus 1."));
|
||||
assert(len(path)%pathN == 1, str("For argument bezier, a degree ",pathN," bezier path shound have a multiple of ",pathN," points in it, plus 1."));
|
||||
bez_points = simplify_path(bezier_path(bezier, bezsteps, bezN));
|
||||
path_points = simplify_path(path3d(bezier_path(path, pathsteps, pathN)));
|
||||
path_sweep(bez_points, path_points);
|
||||
}
|
||||
|
||||
|
||||
// Module: trace_bezier()
|
||||
// Usage:
|
||||
// trace_bezier(bez, <size>, <N=>) {
|
||||
// Description:
|
||||
// Renders 2D or 3D bezier paths and their associated control points.
|
||||
// Useful for debugging bezier paths.
|
||||
// Arguments:
|
||||
// bez = the array of points in the bezier.
|
||||
// N = Mark the first and every Nth vertex after in a different color and shape.
|
||||
// size = diameter of the lines drawn.
|
||||
// ---
|
||||
// N = Mark the first and every Nth vertex after in a different color and shape.
|
||||
// Example(2D):
|
||||
// bez = [
|
||||
// [-10, 0], [-15, -5],
|
||||
|
@ -898,7 +758,7 @@ module bezier_sweep_bezier(bezier, path, pathsteps=16, bezsteps=16, bezN=3, path
|
|||
// [ 5, 10], [ 0, 10]
|
||||
// ];
|
||||
// trace_bezier(bez, N=3, size=0.5);
|
||||
module trace_bezier(bez, N=3, size=1) {
|
||||
module trace_bezier(bez, size=1, N=3) {
|
||||
assert(is_path(bez));
|
||||
assert(is_int(N));
|
||||
assert(len(bez)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||
|
@ -913,13 +773,14 @@ module trace_bezier(bez, N=3, size=1) {
|
|||
|
||||
// Function: bezier_patch_points()
|
||||
// Usage:
|
||||
// bezier_patch_points(patch, u, v)
|
||||
// pt = bezier_patch_points(patch, u, v);
|
||||
// ptgrid = bezier_patch_points(patch, LIST, LIST);
|
||||
// ptgrid = bezier_patch_points(patch, RANGE, RANGE);
|
||||
// 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 will be 4x4
|
||||
// points in size. If given a non-square array, each direction will have
|
||||
// its own degree.
|
||||
// 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
|
||||
// will be 4x4 points in size. If given a non-square array, each direction will have its own
|
||||
// degree.
|
||||
// Arguments:
|
||||
// patch = The 2D array of endpoints and control points for this bezier patch.
|
||||
// u = The proportion of the way along the horizontal inner list of the patch to find the point of. 0<=`u`<=1. If given as a list or range of values, returns a list of point lists.
|
||||
|
@ -956,7 +817,7 @@ function bezier_patch_points(patch, u, v) =
|
|||
|
||||
// Function: bezier_triangle_point()
|
||||
// Usage:
|
||||
// bezier_triangle_point(tri, u, v)
|
||||
// pt = bezier_triangle_point(tri, u, v);
|
||||
// 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
|
||||
|
@ -988,26 +849,41 @@ function bezier_triangle_point(tri, u, v) =
|
|||
|
||||
|
||||
// Function: is_tripatch()
|
||||
// Usage:
|
||||
// bool = is_tripatch(x);
|
||||
// Description:
|
||||
// Returns true if the given item is a triangular bezier patch.
|
||||
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;
|
||||
// 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);
|
||||
// Description:
|
||||
// Returns true if the given item is a rectangular bezier patch.
|
||||
function is_rectpatch(x) = is_list(x) && is_list(x[0]) && is_vector(x[0][0]) && len(x[0]) == len(x[len(x)-1]);
|
||||
// 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);
|
||||
// Description:
|
||||
// Returns true if the given item is a bezier patch.
|
||||
function is_patch(x) = is_tripatch(x) || is_rectpatch(x);
|
||||
// Arguments:
|
||||
// x = The value to check the type of.
|
||||
function is_patch(x) =
|
||||
is_tripatch(x) || is_rectpatch(x);
|
||||
|
||||
|
||||
// Function: bezier_patch()
|
||||
// Usage:
|
||||
// bezier_patch(patch, [splinesteps], [vnf], [style]);
|
||||
// vnf = bezier_patch(patch, <splinesteps>, <vnf=>, <style=>);
|
||||
// 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
|
||||
|
@ -1017,6 +893,7 @@ function is_patch(x) = is_tripatch(x) || is_rectpatch(x);
|
|||
// 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
|
||||
// ---
|
||||
// vnf = Vertices'n'Faces [VNF structure](vnf.scad) to add new vertices and faces to. Default: empty VNF
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", and "quincunx".
|
||||
// Example(3D):
|
||||
|
@ -1155,11 +1032,12 @@ function _bezier_triangle(tri, splinesteps=16, vnf=EMPTY_VNF) =
|
|||
|
||||
// Function: bezier_patch_flat()
|
||||
// Usage:
|
||||
// bezier_patch_flat(size, [N], [spin], [orient], [trans]);
|
||||
// patch = bezier_patch_flat(size, <N=>, <spin=>, <orient=>, <trans=>);
|
||||
// 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`.
|
||||
|
@ -1181,17 +1059,21 @@ function bezier_patch_flat(size=[100,100], N=4, spin=0, orient=UP, trans=[0,0,0]
|
|||
|
||||
// Function: patch_reverse()
|
||||
// Usage:
|
||||
// patch_reverse(patch)
|
||||
// rpatch = patch_reverse(patch);
|
||||
// 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)];
|
||||
function patch_reverse(patch) =
|
||||
[for (row=patch) reverse(row)];
|
||||
|
||||
|
||||
// Section: Bezier Surface Modules
|
||||
|
||||
|
||||
// Function: bezier_surface()
|
||||
// Usage:
|
||||
// bezier_surface(patches, [splinesteps], [vnf], [style]);
|
||||
// vnf = bezier_surface(patches, <splinesteps>, <vnf=>, <style=>);
|
||||
// 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
|
||||
|
@ -1202,6 +1084,7 @@ function patch_reverse(patch) = [for (row=patch) reverse(row)];
|
|||
// Arguments:
|
||||
// patches = A list of triangular and/or rectangular bezier patches.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// ---
|
||||
// vnf = Vertices'n'Faces [VNF structure](vnf.scad) to add new vertices and faces to. Default: empty VNF
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", and "quincunx".
|
||||
// Example(3D):
|
||||
|
@ -1228,43 +1111,6 @@ function bezier_surface(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="defaul
|
|||
|
||||
|
||||
|
||||
// Section: Bezier Surface Modules
|
||||
|
||||
|
||||
// Module: bezier_polyhedron()
|
||||
// Usage:
|
||||
// bezier_polyhedron(patches, [splinesteps], [vnf], [style], [convexity])
|
||||
// Description:
|
||||
// Takes a list of two or more bezier patches and attempts to make a complete polyhedron from them.
|
||||
// Arguments:
|
||||
// patches = A list of triangular and/or rectangular bezier patches.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// vnf = Vertices'n'Faces [VNF structure](vnf.scad) to add extra vertices and faces to. Default: empty VNF
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", and "quincunx".
|
||||
// convexity = Max number of times a line could intersect a wall of the shape.
|
||||
// Example:
|
||||
// patch1 = [
|
||||
// [[18,18,0], [33, 0, 0], [ 67, 0, 0], [ 82, 18,0]],
|
||||
// [[ 0,40,0], [ 0, 0, 20], [100, 0, 20], [100, 40,0]],
|
||||
// [[ 0,60,0], [ 0,100, 20], [100,100,100], [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]],
|
||||
// ];
|
||||
// bezier_polyhedron([patch1, patch2], splinesteps=8);
|
||||
module bezier_polyhedron(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="default", convexity=10)
|
||||
{
|
||||
vnf_polyhedron(
|
||||
bezier_surface(patches=patches, splinesteps=splinesteps, vnf=vnf, style=style),
|
||||
convexity=convexity
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Module: trace_bezier_patches()
|
||||
// Usage:
|
||||
|
|
|
@ -20,7 +20,7 @@ function CR_corner(size, spin=0, orient=UP, trans=[0,0,0]) =
|
|||
)
|
||||
translate(trans,
|
||||
p=rot(a=spin, from=UP, to=orient,
|
||||
p=scale(size, patch)
|
||||
p=scale(size, p=patch)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ function zrot(a=0, cp=undef, p=undef) = rot(a, cp=cp, p=p);
|
|||
// path = circle(d=50,$fn=12);
|
||||
// #stroke(path,closed=true);
|
||||
// stroke(scale([1.5,3],p=path),closed=true);
|
||||
function scale(v=1, cp=[0,0,0], p=undef) =
|
||||
function scale(v=1, cp=[0,0,0], p) =
|
||||
assert(is_num(v) || is_vector(v))
|
||||
assert(is_undef(p) || is_list(p))
|
||||
let( v = is_num(v)? [v,v,v] : v )
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,528];
|
||||
BOSL_VERSION = [2,0,531];
|
||||
|
||||
|
||||
// Section: BOSL Library Version Functions
|
||||
|
|
Loading…
Reference in a new issue