mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-01-16 13:50:23 +01:00
commit
69e8cdc845
238
mutators.scad
238
mutators.scad
@ -19,6 +19,7 @@
|
|||||||
// Returns an axis-aligned cube shape that exactly contains all the 3D children given.
|
// Returns an axis-aligned cube shape that exactly contains all the 3D children given.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// excess = The amount that the bounding box should be larger than needed to bound the children, in each axis.
|
// excess = The amount that the bounding box should be larger than needed to bound the children, in each axis.
|
||||||
|
// planar = If true, creates a 2D bounding rectangle. Is false, creates a 3D bounding cube. Default: false
|
||||||
// Example:
|
// Example:
|
||||||
// #bounding_box() {
|
// #bounding_box() {
|
||||||
// translate([10,8,4]) cube(5);
|
// translate([10,8,4]) cube(5);
|
||||||
@ -26,32 +27,46 @@
|
|||||||
// }
|
// }
|
||||||
// translate([10,8,4]) cube(5);
|
// translate([10,8,4]) cube(5);
|
||||||
// translate([3,0,12]) cube(2);
|
// translate([3,0,12]) cube(2);
|
||||||
module bounding_box(excess=0) {
|
module bounding_box(excess=0, planar=true) {
|
||||||
xs = excess>.1? excess : 1;
|
xs = excess>.1? excess : 1;
|
||||||
// a 3D approx. of the children projection on X axis
|
// a 3D approx. of the children projection on X axis
|
||||||
module _xProjection()
|
module _xProjection()
|
||||||
linear_extrude(xs, center=true)
|
if (planar) {
|
||||||
projection()
|
projection()
|
||||||
rotate([90,0,0])
|
rotate([90,0,0])
|
||||||
linear_extrude(xs, center=true)
|
linear_extrude(xs, center=true)
|
||||||
projection()
|
hull()
|
||||||
hull()
|
children();
|
||||||
children();
|
} else {
|
||||||
|
linear_extrude(xs, center=true)
|
||||||
|
projection()
|
||||||
|
rotate([90,0,0])
|
||||||
|
linear_extrude(xs, center=true)
|
||||||
|
projection()
|
||||||
|
hull()
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
|
||||||
// a bounding box with an offset of 1 in all axis
|
// a bounding box with an offset of 1 in all axis
|
||||||
module _oversize_bbox() {
|
module _oversize_bbox() {
|
||||||
minkowski() {
|
if (planar) {
|
||||||
_xProjection() children(); // x axis
|
minkowski() {
|
||||||
rotate(-90) _xProjection() rotate(90) children(); // y axis
|
_xProjection() children(); // x axis
|
||||||
rotate([0,-90,0]) _xProjection() rotate([0,90,0]) children(); // z axis
|
rotate(-90) _xProjection() rotate(90) children(); // y axis
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
minkowski() {
|
||||||
|
_xProjection() children(); // x axis
|
||||||
|
rotate(-90) _xProjection() rotate(90) children(); // y axis
|
||||||
|
rotate([0,-90,0]) _xProjection() rotate([0,90,0]) children(); // z axis
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset children() (a cube) by -1 in all axis
|
|
||||||
module _shrink_cube() {
|
module _shrink_cube() {
|
||||||
intersection() {
|
intersection() {
|
||||||
translate((1-excess)*[ 1, 1, 1]) children();
|
translate((1-excess)*[ 1, 1, planar?0: 1]) children();
|
||||||
translate((1-excess)*[-1,-1,-1]) children();
|
translate((1-excess)*[-1,-1, planar?0:-1]) children();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +224,6 @@ function left_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
|||||||
// right_half([s], [x]) ...
|
// right_half([s], [x]) ...
|
||||||
// right_half(planar=true, [s], [x]) ...
|
// right_half(planar=true, [s], [x]) ...
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Description:
|
// Description:
|
||||||
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is left of it.
|
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is left of it.
|
||||||
//
|
//
|
||||||
@ -516,31 +530,103 @@ module cylindrical_extrude(or, ir, od, id, size=1000, convexity=10, spin=0, orie
|
|||||||
// Section: Offset Mutators
|
// Section: Offset Mutators
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Module: round3d()
|
// Module: minkowski_difference()
|
||||||
// Usage:
|
// Usage:
|
||||||
// round3d(r) ...
|
// minkowski_difference() { base_shape(); diff_shape(); ... }
|
||||||
// round3d(or) ...
|
|
||||||
// round3d(ir) ...
|
|
||||||
// round3d(or, ir) ...
|
|
||||||
// Description:
|
// Description:
|
||||||
// Rounds arbitrary 3D objects. Giving `r` rounds all concave and convex corners. Giving just `ir`
|
// Takes a 3D base shape and one or more 3D diff shapes, carves out the diff shapes from the
|
||||||
|
// surface of the base shape, in a way complementary to how `minkowski()` unions shapes to the
|
||||||
|
// surface of its base shape.
|
||||||
|
// Arguments:
|
||||||
|
// planar = If true, performs minkowski difference in 2D. Default: false (3D)
|
||||||
|
// Example:
|
||||||
|
// minkowski_difference() {
|
||||||
|
// union() {
|
||||||
|
// cube([120,70,70], center=true);
|
||||||
|
// cube([70,120,70], center=true);
|
||||||
|
// cube([70,70,120], center=true);
|
||||||
|
// }
|
||||||
|
// sphere(r=10);
|
||||||
|
// }
|
||||||
|
module minkowski_difference(planar=false) {
|
||||||
|
difference() {
|
||||||
|
bounding_box(excess=0, planar=planar) children(0);
|
||||||
|
render(convexity=20) {
|
||||||
|
minkowski() {
|
||||||
|
difference() {
|
||||||
|
bounding_box(excess=1, planar=planar) children(0);
|
||||||
|
children(0);
|
||||||
|
}
|
||||||
|
for (i=[1:1:$children-1]) children(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Module: round2d()
|
||||||
|
// Usage:
|
||||||
|
// round2d(r) ...
|
||||||
|
// round2d(or) ...
|
||||||
|
// round2d(ir) ...
|
||||||
|
// round2d(or, ir) ...
|
||||||
|
// Description:
|
||||||
|
// Rounds arbitrary 2D objects. Giving `r` rounds all concave and convex corners. Giving just `ir`
|
||||||
// rounds just concave corners. Giving just `or` rounds convex corners. Giving both `ir` and `or`
|
// rounds just concave corners. Giving just `or` rounds convex corners. Giving both `ir` and `or`
|
||||||
// can let you round to different radii for concave and convex corners. The 3D object must not have
|
// can let you round to different radii for concave and convex corners. The 2D object must not have
|
||||||
// any parts narrower than twice the `or` radius. Such parts will disappear. This is an *extremely*
|
// any parts narrower than twice the `or` radius. Such parts will disappear.
|
||||||
// slow operation. I cannot emphasize enough just how slow it is. It uses `minkowski()` multiple times.
|
|
||||||
// Use this as a last resort. This is so slow that no example images will be rendered.
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// r = Radius to round all concave and convex corners to.
|
// r = Radius to round all concave and convex corners to.
|
||||||
// or = Radius to round only outside (convex) corners to. Use instead of `r`.
|
// or = Radius to round only outside (convex) corners to. Use instead of `r`.
|
||||||
// ir = Radius to round only inside (concave) corners to. Use instead of `r`.
|
// ir = Radius to round only inside (concave) corners to. Use instead of `r`.
|
||||||
module round3d(r, or, ir, size=100)
|
// Examples(2D):
|
||||||
|
// round2d(r=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// round2d(or=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// round2d(ir=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// round2d(or=16,ir=8) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
module round2d(r, or, ir)
|
||||||
{
|
{
|
||||||
or = get_radius(r1=or, r=r, dflt=0);
|
or = get_radius(r1=or, r=r, dflt=0);
|
||||||
ir = get_radius(r1=ir, r=r, dflt=0);
|
ir = get_radius(r1=ir, r=r, dflt=0);
|
||||||
offset3d(or, size=size)
|
offset(or) offset(-ir-or) offset(delta=ir,chamfer=true) children();
|
||||||
offset3d(-ir-or, size=size)
|
}
|
||||||
offset3d(ir, size=size)
|
|
||||||
|
|
||||||
|
// Module: shell2d()
|
||||||
|
// Usage:
|
||||||
|
// shell2d(thickness, [or], [ir], [fill], [round])
|
||||||
|
// Description:
|
||||||
|
// Creates a hollow shell from 2D children, with optional rounding.
|
||||||
|
// Arguments:
|
||||||
|
// thickness = Thickness of the shell. Positive to expand outward, negative to shrink inward, or a two-element list to do both.
|
||||||
|
// or = Radius to round corners on the outside of the shell. If given a list of 2 radii, [CONVEX,CONCAVE], specifies the radii for convex and concave corners separately. Default: 0 (no outside rounding)
|
||||||
|
// ir = Radius to round corners on the inside of the shell. If given a list of 2 radii, [CONVEX,CONCAVE], specifies the radii for convex and concave corners separately. Default: 0 (no inside rounding)
|
||||||
|
// Examples(2D):
|
||||||
|
// shell2d(10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(-10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d([-10,10]) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(10,or=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(10,ir=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(10,round=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(10,fill=10) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
// shell2d(8,or=16,ir=8,round=16,fill=8) {square([40,100], center=true); square([100,40], center=true);}
|
||||||
|
module shell2d(thickness, or=0, ir=0)
|
||||||
|
{
|
||||||
|
thickness = is_num(thickness)? (
|
||||||
|
thickness<0? [thickness,0] : [0,thickness]
|
||||||
|
) : (thickness[0]>thickness[1])? (
|
||||||
|
[thickness[1],thickness[0]]
|
||||||
|
) : thickness;
|
||||||
|
orad = is_finite(or)? [or,or] : or;
|
||||||
|
irad = is_finite(ir)? [ir,ir] : ir;
|
||||||
|
difference() {
|
||||||
|
round2d(or=orad[0],ir=orad[1])
|
||||||
|
offset(delta=thickness[1])
|
||||||
children();
|
children();
|
||||||
|
round2d(or=irad[1],ir=irad[0])
|
||||||
|
offset(delta=thickness[0])
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -583,101 +669,31 @@ module offset3d(r=1, size=100, convexity=10) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Module: round2d()
|
// Module: round3d()
|
||||||
// Usage:
|
// Usage:
|
||||||
// round2d(r) ...
|
// round3d(r) ...
|
||||||
// round2d(or) ...
|
// round3d(or) ...
|
||||||
// round2d(ir) ...
|
// round3d(ir) ...
|
||||||
// round2d(or, ir) ...
|
// round3d(or, ir) ...
|
||||||
// Description:
|
// Description:
|
||||||
// Rounds arbitrary 2D objects. Giving `r` rounds all concave and convex corners. Giving just `ir`
|
// Rounds arbitrary 3D objects. Giving `r` rounds all concave and convex corners. Giving just `ir`
|
||||||
// rounds just concave corners. Giving just `or` rounds convex corners. Giving both `ir` and `or`
|
// rounds just concave corners. Giving just `or` rounds convex corners. Giving both `ir` and `or`
|
||||||
// can let you round to different radii for concave and convex corners. The 2D object must not have
|
// can let you round to different radii for concave and convex corners. The 3D object must not have
|
||||||
// any parts narrower than twice the `or` radius. Such parts will disappear.
|
// any parts narrower than twice the `or` radius. Such parts will disappear. This is an *extremely*
|
||||||
|
// slow operation. I cannot emphasize enough just how slow it is. It uses `minkowski()` multiple times.
|
||||||
|
// Use this as a last resort. This is so slow that no example images will be rendered.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// r = Radius to round all concave and convex corners to.
|
// r = Radius to round all concave and convex corners to.
|
||||||
// or = Radius to round only outside (convex) corners to. Use instead of `r`.
|
// or = Radius to round only outside (convex) corners to. Use instead of `r`.
|
||||||
// ir = Radius to round only inside (concave) corners to. Use instead of `r`.
|
// ir = Radius to round only inside (concave) corners to. Use instead of `r`.
|
||||||
// Examples(2D):
|
module round3d(r, or, ir, size=100)
|
||||||
// round2d(r=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// round2d(or=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// round2d(ir=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// round2d(or=16,ir=8) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
module round2d(r, or, ir)
|
|
||||||
{
|
{
|
||||||
or = get_radius(r1=or, r=r, dflt=0);
|
or = get_radius(r1=or, r=r, dflt=0);
|
||||||
ir = get_radius(r1=ir, r=r, dflt=0);
|
ir = get_radius(r1=ir, r=r, dflt=0);
|
||||||
offset(or) offset(-ir-or) offset(delta=ir,chamfer=true) children();
|
offset3d(or, size=size)
|
||||||
}
|
offset3d(-ir-or, size=size)
|
||||||
|
offset3d(ir, size=size)
|
||||||
|
|
||||||
// Module: shell2d()
|
|
||||||
// Usage:
|
|
||||||
// shell2d(thickness, [or], [ir], [fill], [round])
|
|
||||||
// Description:
|
|
||||||
// Creates a hollow shell from 2D children, with optional rounding.
|
|
||||||
// Arguments:
|
|
||||||
// thickness = Thickness of the shell. Positive to expand outward, negative to shrink inward, or a two-element list to do both.
|
|
||||||
// or = Radius to round convex corners/pointy bits on the outside of the shell.
|
|
||||||
// ir = Radius to round concave corners on the outside of the shell.
|
|
||||||
// round = Radius to round convex corners/pointy bits on the inside of the shell.
|
|
||||||
// fill = Radius to round concave corners on the inside of the shell.
|
|
||||||
// Examples(2D):
|
|
||||||
// shell2d(10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(-10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d([-10,10]) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(10,or=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(10,ir=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(10,round=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(10,fill=10) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
// shell2d(8,or=16,ir=8,round=16,fill=8) {square([40,100], center=true); square([100,40], center=true);}
|
|
||||||
module shell2d(thickness, or=0, ir=0, fill=0, round=0)
|
|
||||||
{
|
|
||||||
thickness = is_num(thickness)? (
|
|
||||||
thickness<0? [thickness,0] : [0,thickness]
|
|
||||||
) : (thickness[0]>thickness[1])? (
|
|
||||||
[thickness[1],thickness[0]]
|
|
||||||
) : thickness;
|
|
||||||
difference() {
|
|
||||||
round2d(or=or,ir=ir)
|
|
||||||
offset(delta=thickness[1])
|
|
||||||
children();
|
children();
|
||||||
round2d(or=fill,ir=round)
|
|
||||||
offset(delta=thickness[0])
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Module: minkowski_difference()
|
|
||||||
// Usage:
|
|
||||||
// minkowski_difference() { base_shape(); diff_shape(); ... }
|
|
||||||
// Description:
|
|
||||||
// Takes a 3D base shape and one or more 3D diff shapes, carves out the diff shapes from the
|
|
||||||
// surface of the base shape, in a way complementary to how `minkowski()` unions shapes to the
|
|
||||||
// surface of its base shape.
|
|
||||||
// Example:
|
|
||||||
// minkowski_difference() {
|
|
||||||
// union() {
|
|
||||||
// cube([120,70,70], center=true);
|
|
||||||
// cube([70,120,70], center=true);
|
|
||||||
// cube([70,70,120], center=true);
|
|
||||||
// }
|
|
||||||
// sphere(r=10);
|
|
||||||
// }
|
|
||||||
module minkowski_difference() {
|
|
||||||
difference() {
|
|
||||||
bounding_box(excess=0) children(0);
|
|
||||||
render(convexity=10) {
|
|
||||||
minkowski() {
|
|
||||||
difference() {
|
|
||||||
bounding_box(excess=1) children(0);
|
|
||||||
children(0);
|
|
||||||
}
|
|
||||||
for (i=[1:1:$children-1]) children(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
152
paths.scad
152
paths.scad
@ -407,6 +407,158 @@ function path_torsion(path, closed=false) =
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// Function: path_chamfer_and_rounding()
|
||||||
|
// Usage:
|
||||||
|
// path2 = path_chamfer_and_rounding(path, [closed], [chamfer], [rounding]);
|
||||||
|
// Description:
|
||||||
|
// Rounds or chamfers corners in the given path.
|
||||||
|
// Arguments:
|
||||||
|
// path = The path to chamfer and/or round.
|
||||||
|
// closed = If true, treat path like a closed polygon. Default: true
|
||||||
|
// chamfer = The length of the chamfer faces at the corners. If given as a list of numbers, gives individual chamfers for each corner, from first to last. Default: 0 (no chamfer)
|
||||||
|
// rounding = The rounding radius for the corners. If given as a list of numbers, gives individual radii for each corner, from first to last. Default: 0 (no rounding)
|
||||||
|
// Example(2D): Chamfering a Path
|
||||||
|
// path = star(5, step=2, d=100);
|
||||||
|
// path2 = path_chamfer_and_rounding(path, closed=true, chamfer=5);
|
||||||
|
// stroke(path2, closed=true);
|
||||||
|
// Example(2D): Per-Corner Chamfering
|
||||||
|
// path = star(5, step=2, d=100);
|
||||||
|
// chamfs = [for (i=[0:1:4]) each 3*[i,i]];
|
||||||
|
// path2 = path_chamfer_and_rounding(path, closed=true, chamfer=chamfs);
|
||||||
|
// stroke(path2, closed=true);
|
||||||
|
// Example(2D): Rounding a Path
|
||||||
|
// path = star(5, step=2, d=100);
|
||||||
|
// path2 = path_chamfer_and_rounding(path, closed=true, rounding=5);
|
||||||
|
// stroke(path2, closed=true);
|
||||||
|
// Example(2D): Per-Corner Chamfering
|
||||||
|
// path = star(5, step=2, d=100);
|
||||||
|
// rs = [for (i=[0:1:4]) each 2*[i,i]];
|
||||||
|
// path2 = path_chamfer_and_rounding(path, closed=true, rounding=rs);
|
||||||
|
// stroke(path2, closed=true);
|
||||||
|
// Example(2D): Mixing Chamfers and Roundings
|
||||||
|
// path = star(5, step=2, d=100);
|
||||||
|
// chamfs = [for (i=[0:4]) each [5,0]];
|
||||||
|
// rs = [for (i=[0:4]) each [0,10]];
|
||||||
|
// path2 = path_chamfer_and_rounding(path, closed=true, chamfer=chamfs, rounding=rs);
|
||||||
|
// stroke(path2, closed=true);
|
||||||
|
function path_chamfer_and_rounding(path, closed, chamfer, rounding) =
|
||||||
|
let (
|
||||||
|
path = deduplicate(path,closed=true),
|
||||||
|
lp = len(path),
|
||||||
|
chamfer = is_undef(chamfer)? repeat(0,lp) :
|
||||||
|
is_vector(chamfer)? list_pad(chamfer,lp,0) :
|
||||||
|
is_num(chamfer)? repeat(chamfer,lp) :
|
||||||
|
assert(false, "Bad chamfer value."),
|
||||||
|
rounding = is_undef(rounding)? repeat(0,lp) :
|
||||||
|
is_vector(rounding)? list_pad(rounding,lp,0) :
|
||||||
|
is_num(rounding)? repeat(rounding,lp) :
|
||||||
|
assert(false, "Bad rounding value."),
|
||||||
|
corner_paths = [
|
||||||
|
for (i=(closed? [0:1:lp-1] : [1:1:lp-2])) let(
|
||||||
|
p1 = select(path,i-1),
|
||||||
|
p2 = select(path,i),
|
||||||
|
p3 = select(path,i+1)
|
||||||
|
)
|
||||||
|
chamfer[i] > 0? _corner_chamfer_path(p1, p2, p3, side=chamfer[i]) :
|
||||||
|
rounding[i] > 0? _corner_roundover_path(p1, p2, p3, r=rounding[i]) :
|
||||||
|
[p2]
|
||||||
|
],
|
||||||
|
out = [
|
||||||
|
if (!closed) path[0],
|
||||||
|
for (i=(closed? [0:1:lp-1] : [1:1:lp-2])) let(
|
||||||
|
p1 = select(path,i-1),
|
||||||
|
p2 = select(path,i),
|
||||||
|
crn1 = select(corner_paths,i-1),
|
||||||
|
crn2 = corner_paths[i],
|
||||||
|
l1 = norm(select(crn1,-1)-p1),
|
||||||
|
l2 = norm(crn2[0]-p2),
|
||||||
|
needed = l1 + l2,
|
||||||
|
seglen = norm(p2-p1),
|
||||||
|
check = assert(seglen >= needed, str("Path segment ",i," is too short to fulfill rounding/chamfering for the adjacent corners."))
|
||||||
|
) each crn2,
|
||||||
|
if (!closed) select(path,-1)
|
||||||
|
]
|
||||||
|
) deduplicate(out);
|
||||||
|
|
||||||
|
|
||||||
|
function _corner_chamfer_path(p1, p2, p3, dist1, dist2, side, angle) =
|
||||||
|
let(
|
||||||
|
v1 = unit(p1 - p2),
|
||||||
|
v2 = unit(p3 - p2),
|
||||||
|
n = vector_axis(v1,v2),
|
||||||
|
ang = vector_angle(v1,v2),
|
||||||
|
path = (is_num(dist1) && is_undef(dist2) && is_undef(side))? (
|
||||||
|
// dist1 & optional angle
|
||||||
|
assert(dist1 > 0)
|
||||||
|
let(angle = default(angle,(180-ang)/2))
|
||||||
|
assert(is_num(angle))
|
||||||
|
assert(angle > 0 && angle < 180)
|
||||||
|
let(
|
||||||
|
pta = p2 + dist1*v1,
|
||||||
|
a3 = 180 - angle - ang
|
||||||
|
) assert(a3>0, "Angle too extreme.")
|
||||||
|
let(
|
||||||
|
side = sin(angle) * dist1/sin(a3),
|
||||||
|
ptb = p2 + side*v2
|
||||||
|
) [pta, ptb]
|
||||||
|
) : (is_undef(dist1) && is_num(dist2) && is_undef(side))? (
|
||||||
|
// dist2 & optional angle
|
||||||
|
assert(dist2 > 0)
|
||||||
|
let(angle = default(angle,(180-ang)/2))
|
||||||
|
assert(is_num(angle))
|
||||||
|
assert(angle > 0 && angle < 180)
|
||||||
|
let(
|
||||||
|
ptb = p2 + dist2*v2,
|
||||||
|
a3 = 180 - angle - ang
|
||||||
|
) assert(a3>0, "Angle too extreme.")
|
||||||
|
let(
|
||||||
|
side = sin(angle) * dist2/sin(a3),
|
||||||
|
pta = p2 + side*v1
|
||||||
|
) [pta, ptb]
|
||||||
|
) : (is_undef(dist1) && is_undef(dist2) && is_num(side))? (
|
||||||
|
// side & optional angle
|
||||||
|
assert(side > 0)
|
||||||
|
let(angle = default(angle,(180-ang)/2))
|
||||||
|
assert(is_num(angle))
|
||||||
|
assert(angle > 0 && angle < 180)
|
||||||
|
let(
|
||||||
|
a3 = 180 - angle - ang
|
||||||
|
) assert(a3>0, "Angle too extreme.")
|
||||||
|
let(
|
||||||
|
dist1 = sin(a3) * side/sin(ang),
|
||||||
|
dist2 = sin(angle) * side/sin(ang),
|
||||||
|
pta = p2 + dist1*v1,
|
||||||
|
ptb = p2 + dist2*v2
|
||||||
|
) [pta, ptb]
|
||||||
|
) : (is_num(dist1) && is_num(dist2) && is_undef(side) && is_undef(side))? (
|
||||||
|
// dist1 & dist2
|
||||||
|
assert(dist1 > 0)
|
||||||
|
assert(dist2 > 0)
|
||||||
|
let(
|
||||||
|
pta = p2 + dist1*v1,
|
||||||
|
ptb = p2 + dist2*v2
|
||||||
|
) [pta, ptb]
|
||||||
|
) : (
|
||||||
|
assert(false,"Bad arguments.")
|
||||||
|
)
|
||||||
|
) path;
|
||||||
|
|
||||||
|
|
||||||
|
function _corner_roundover_path(p1, p2, p3, r, d) =
|
||||||
|
let(
|
||||||
|
r = get_radius(r=r,d=d,dflt=undef),
|
||||||
|
res = circle_2tangents(p1, p2, p3, r=r, tangents=true),
|
||||||
|
cp = res[0],
|
||||||
|
n = res[1],
|
||||||
|
tp1 = res[2],
|
||||||
|
ang = res[4]+res[5],
|
||||||
|
steps = floor(segs(r)*ang/360+0.5),
|
||||||
|
step = ang / steps,
|
||||||
|
path = [for (i=[0:1:steps]) move(cp, p=rot(a=-i*step, v=n, p=tp1-cp))]
|
||||||
|
) path;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: path3d_spiral()
|
// Function: path3d_spiral()
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a 3D spiral path.
|
// Returns a 3D spiral path.
|
||||||
|
@ -15,7 +15,7 @@ done
|
|||||||
if [[ "$FILES" != "" ]]; then
|
if [[ "$FILES" != "" ]]; then
|
||||||
PREVIEW_LIBS="$FILES"
|
PREVIEW_LIBS="$FILES"
|
||||||
else
|
else
|
||||||
PREVIEW_LIBS="Transforms Distributors Shapes2d Shapes3d Paths FractalTree"
|
PREVIEW_LIBS="Shapes2d Shapes3d Transforms Distributors Mutators Paths FractalTree"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dir="$(basename $PWD)"
|
dir="$(basename $PWD)"
|
||||||
|
@ -1206,6 +1206,8 @@ module octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, align_tip,
|
|||||||
// w2 = The X axis width of the back end of the trapezoid.
|
// w2 = The X axis width of the back end of the trapezoid.
|
||||||
// angle = If given in place of `h`, `w1`, or `w2`, then the missing value is calculated such that the right side has that angle away from the Y axis.
|
// angle = If given in place of `h`, `w1`, or `w2`, then the missing value is calculated such that the right side has that angle away from the Y axis.
|
||||||
// shift = Scalar value to shift the back of the trapezoid along the X axis by. Default: 0
|
// shift = Scalar value to shift the back of the trapezoid along the X axis by. Default: 0
|
||||||
|
// rounding = The rounding radius for the corners. If given as a list of four numbers, gives individual radii for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no rounding)
|
||||||
|
// chamfer = The Length of the chamfer faces at the corners. If given as a list of four numbers, gives individual chamfers for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no chamfer)
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
// 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`
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
// Examples(2D):
|
// Examples(2D):
|
||||||
@ -1217,42 +1219,68 @@ module octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, align_tip,
|
|||||||
// trapezoid(h=20, w2=10, angle=30);
|
// trapezoid(h=20, w2=10, angle=30);
|
||||||
// trapezoid(h=20, w2=30, angle=-30);
|
// trapezoid(h=20, w2=30, angle=-30);
|
||||||
// trapezoid(w1=30, w2=10, angle=30);
|
// trapezoid(w1=30, w2=10, angle=30);
|
||||||
|
// Example(2D): Chamferred Trapezoid
|
||||||
|
// trapezoid(h=30, w1=60, w2=40, chamfer=5);
|
||||||
|
// Example(2D): Rounded Trapezoid
|
||||||
|
// trapezoid(h=30, w1=60, w2=40, rounding=5);
|
||||||
|
// Example(2D): Mixed Chamfering and Rounding
|
||||||
|
// trapezoid(h=30, w1=60, w2=40, rounding=[5,0,10,0],chamfer=[0,8,0,15],$fa=1,$fs=1);
|
||||||
// Example(2D): Called as Function
|
// Example(2D): Called as Function
|
||||||
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20));
|
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20));
|
||||||
function trapezoid(h, w1, w2, angle, shift=0, anchor=CENTER, spin=0) =
|
function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENTER, spin=0) =
|
||||||
assert(is_undef(h) || is_finite(h))
|
assert(is_undef(h) || is_finite(h))
|
||||||
assert(is_undef(w1) || is_finite(w1))
|
assert(is_undef(w1) || is_finite(w1))
|
||||||
assert(is_undef(w2) || is_finite(w2))
|
assert(is_undef(w2) || is_finite(w2))
|
||||||
assert(is_undef(angle) || is_finite(angle))
|
assert(is_undef(angle) || is_finite(angle))
|
||||||
assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.")
|
assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.")
|
||||||
assert(is_finite(shift))
|
assert(is_finite(shift))
|
||||||
|
assert(is_finite(chamfer) || is_vector(chamfer,4))
|
||||||
|
assert(is_finite(rounding) || is_vector(rounding,4))
|
||||||
let(
|
let(
|
||||||
|
simple = chamfer==0 && rounding==0,
|
||||||
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)),
|
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)),
|
||||||
w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift),
|
w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift),
|
||||||
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift),
|
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift)
|
||||||
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2+shift,h/2], [w2/2+shift,h/2]]
|
|
||||||
)
|
)
|
||||||
assert(w1>=0 && w2>=0 && h>0, "Degenerate trapezoid geometry.")
|
assert(w1>=0 && w2>=0 && h>0, "Degenerate trapezoid geometry.")
|
||||||
reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, p=path);
|
assert(w1+w2>0, "Degenerate trapezoid geometry.")
|
||||||
|
let(
|
||||||
|
base_path = [
|
||||||
|
[w2/2+shift,h/2],
|
||||||
|
[-w2/2+shift,h/2],
|
||||||
|
[-w1/2,-h/2],
|
||||||
|
[w1/2,-h/2],
|
||||||
|
],
|
||||||
|
cpath = simple? base_path :
|
||||||
|
path_chamfer_and_rounding(
|
||||||
|
base_path, closed=true,
|
||||||
|
chamfer=chamfer,
|
||||||
|
rounding=rounding
|
||||||
|
),
|
||||||
|
path = reverse(cpath)
|
||||||
|
) simple?
|
||||||
|
reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path) :
|
||||||
|
reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module trapezoid(h, w1, w2, angle, shift=0, anchor=CENTER, spin=0) {
|
module trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENTER, spin=0) {
|
||||||
assert(is_undef(h) || is_finite(h));
|
path = trapezoid(h=h, w1=w1, w2=w2, angle=angle, shift=shift, chamfer=chamfer, rounding=rounding);
|
||||||
assert(is_undef(w1) || is_finite(w1));
|
|
||||||
assert(is_undef(w2) || is_finite(w2));
|
|
||||||
assert(is_undef(angle) || is_finite(angle));
|
|
||||||
assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.");
|
|
||||||
assert(is_finite(shift));
|
|
||||||
union() {
|
union() {
|
||||||
|
simple = chamfer==0 && rounding==0;
|
||||||
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle));
|
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle));
|
||||||
w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift);
|
w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift);
|
||||||
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift);
|
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift);
|
||||||
assert(w1>=0 && w2>=0 && h>0, "Degenerate trapezoid geometry.");
|
if (simple) {
|
||||||
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2+shift,h/2], [w2/2+shift,h/2]];
|
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) {
|
||||||
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) {
|
polygon(path);
|
||||||
polygon(path);
|
children();
|
||||||
children();
|
}
|
||||||
|
} else {
|
||||||
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
273
tutorials/Mutators.md
Normal file
273
tutorials/Mutators.md
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
# Mutators Tutorial
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
|
||||||
|
## 3D Space Halving
|
||||||
|
Sometimes you want to take a 3D shape like a sphere, and cut it in half.
|
||||||
|
The BOSL2 library provides a number of ways to do this:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
left_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
right_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
front_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
back_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
bottom_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
top_half() sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the `half_of()` module if you want to split space in a way not aligned with an axis:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
half_of([-1,0,-1]) sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
The plane of dissection can be shifted along the axis of any of these operators:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
left_half(x=20) sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
back_half(y=-20) sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
bottom_half(z=20) sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
half_of([-1,0,-1], cp=[20,0,20]) sphere(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, these operators can be applied to objects that fit in a cube 1000 on a side. If you need
|
||||||
|
to apply these halving operators to objects larger than this, you can give the size in the `s=`
|
||||||
|
argument:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
bottom_half(s=2000) sphere(d=1500);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2D Plane Halving
|
||||||
|
To cut 2D shapes in half, you will need to add the `planar=true` argument:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
left_half(planar=true) circle(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
right_half(planar=true) circle(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
front_half(planar=true) circle(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
back_half(planar=true) circle(d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chained Mutators
|
||||||
|
If you have a set of shapes that you want to do pair-wise hulling of, you can use `chain_hull()`:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
chain_hull() {
|
||||||
|
cube(5, center=true);
|
||||||
|
translate([30, 0, 0]) sphere(d=15);
|
||||||
|
translate([60, 30, 0]) cylinder(d=10, h=20);
|
||||||
|
translate([60, 60, 0]) cube([10,1,20], center=false);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extrusion Mutators
|
||||||
|
The OpenSCAD `linear_extrude()` module can take a 2D shape and extrude it vertically in a line:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
linear_extrude(height=30) zrot(45) square(40,center=true);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `rotate_extrude()` module can take a 2D shape and rotate it around the Z axis.
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
linear_extrude(height=30) left(30) zrot(45) square(40,center=true);
|
||||||
|
```
|
||||||
|
|
||||||
|
In a similar manner, the BOSL2 `cylindrical_extrude()` module can take a 2d shape and extrude it
|
||||||
|
out radially from the center of a cylinder:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
cylindrical_extrude(or=40, ir=35)
|
||||||
|
text(text="Hello World!", size=10, halign="center", valign="center");
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Offset Mutators
|
||||||
|
|
||||||
|
### Minkowski Difference
|
||||||
|
Openscad provides the `minkowski()` module to trace a shape over the entire surface of another shape:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
minkowski() {
|
||||||
|
union() {
|
||||||
|
cube([100,33,33], center=true);
|
||||||
|
cube([33,100,33], center=true);
|
||||||
|
cube([33,33,100], center=true);
|
||||||
|
}
|
||||||
|
sphere(r=8);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
However, it doesn't provide the inverse of this operation; to remove a shape from the entire surface
|
||||||
|
of another object. For this, the BOSL2 library provides the `minkowski_difference()` module:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
minkowski_difference() {
|
||||||
|
union() {
|
||||||
|
cube([100,33,33], center=true);
|
||||||
|
cube([33,100,33], center=true);
|
||||||
|
cube([33,33,100], center=true);
|
||||||
|
}
|
||||||
|
sphere(r=8);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To perform a `minkowski_difference()` on 2D shapes, you need to supply the `planar=true` argument:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
minkowski_difference(planar=true) {
|
||||||
|
union() {
|
||||||
|
square([100,33], center=true);
|
||||||
|
square([33,100], center=true);
|
||||||
|
}
|
||||||
|
circle(r=8);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Round2d
|
||||||
|
The `round2d()` module lets you take a 2D shape and round inside and outside corners. The inner concave corners are rounded to the radius `ir=`, while the outer convex corners are rounded to the radius `or=`:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
round2d(or=8) star(6, step=2, d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
round2d(ir=12) star(6, step=2, d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
round2d(or=8,ir=12) star(6, step=2, d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use `r=` to effectively set both `ir=` and `or=` to the same value:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
round2d(r=8) star(6, step=2, d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shell2d
|
||||||
|
With the `shell2d()` module, you can take an arbitrary shape, and get the shell outline of it.
|
||||||
|
With a positive thickness, the shell is offset outwards from the original shape:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=5) star(5,step=2,d=100);
|
||||||
|
color("blue") stroke(star(5,step=2,d=100),closed=true);
|
||||||
|
```
|
||||||
|
|
||||||
|
With a negative thickness, the shell if inset from the original shape:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5) star(5,step=2,d=100);
|
||||||
|
color("blue") stroke(star(5,step=2,d=100),closed=true);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can give a pair of thickness values if you want it both inset and outset from the original shape:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=[-5,5]) star(5,step=2,d=100);
|
||||||
|
color("blue") stroke(star(5,step=2,d=100),closed=true);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add rounding to the outside by passing a radius to the `or=` argument.
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,or=5) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to pass different radii for the convex and concave corners of the outside, you can pass them as `or=[CONVEX,CONCAVE]`:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,or=[5,10]) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
A radius of 0 can be used to specify no rounding:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,or=[5,0]) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add rounding to the inside by passing a radius to the `ir=` argument.
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,ir=5) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to pass different radii for the convex and concave corners of the inside, you can pass them as `ir=[CONVEX,CONCAVE]`:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,ir=[8,3]) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use `or=` and `ir=` together to get nice combined rounding effects:
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,or=[7,2],ir=[7,2]) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
```openscad-2D
|
||||||
|
shell2d(thickness=-5,or=[5,0],ir=[5,0]) star(5,step=2,d=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Round3d
|
||||||
|
### Offset3d
|
||||||
|
(To be Written)
|
||||||
|
|
||||||
|
|
||||||
|
## Color Manipulators
|
||||||
|
The built-in OpenSCAD `color()` module can let you set the RGB color of an object, but it's often
|
||||||
|
easier to select colors using other color schemes. You can use the HSL or Hue-Saturation-Lightness
|
||||||
|
color scheme with the `HSL()` module:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
for (h=[0:0.1:1], s=[0:0.1:1], l=[0:0.1:1]) {
|
||||||
|
translate(100*[h,s,l]) {
|
||||||
|
HSL(h*360,1-s,l) cube(10,center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the HSV or Hue-Saturation-Value color scheme with the `HSV()` module:
|
||||||
|
|
||||||
|
```openscad
|
||||||
|
for (h=[0:0.1:1], s=[0:0.1:1], v=[0:0.1:1]) {
|
||||||
|
translate(100*[h,s,v]) {
|
||||||
|
HSV(h*360,1-s,v) cube(10,center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,491];
|
BOSL_VERSION = [2,0,498];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
Loading…
x
Reference in New Issue
Block a user