Merge pull request #350 from revarbat/revarbat_dev

Revarbat dev
This commit is contained in:
Revar Desmera 2020-12-30 00:40:12 -08:00 committed by GitHub
commit 69e8cdc845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 598 additions and 129 deletions

View File

@ -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);
}
}
}
} }

View File

@ -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.

View File

@ -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)"

View File

@ -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
View 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);
}
}
```

View File

@ -8,7 +8,7 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,491]; BOSL_VERSION = [2,0,498];
// Section: BOSL Library Version Functions // Section: BOSL Library Version Functions