Add angle definition to prismoid

This commit is contained in:
Adrian Mariano 2023-03-24 19:50:52 -04:00
parent 3b130c0356
commit af53674c4e
2 changed files with 152 additions and 127 deletions

View file

@ -914,6 +914,30 @@ module right_triangle(size=[1,1], center, anchor, spin=0) {
// trapezoid(h=30, w1=100, ang=[66,44],rounding=-5, atype="perim",flip=true) show_anchors(); // trapezoid(h=30, w1=100, ang=[66,44],rounding=-5, atype="perim",flip=true) show_anchors();
// 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_dims(h,w1,w2,shift,ang) =
let(
h = is_def(h)? h
: num_defined([w1,w2,each ang])==4 ? (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1])
: undef
)
is_undef(h) ? [h]
:
let(
x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]),
x2 = is_undef(ang[1]) || ang[1]==90 ? 0 : h/tan(ang[1]),
w1 = is_def(w1)? w1
: is_def(w2) && is_def(ang[0]) ? w2 + x1 + x2
: undef,
w2 = is_def(w2)? w2
: is_def(w1) && is_def(ang[0]) ? w1 - x1 - x2
: undef,
shift = first_defined([shift,(x1-x2)/2])
)
[h,w1,w2,shift];
function trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0,atype="box", _return_override, angle) = function trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0,atype="box", _return_override, angle) =
assert(is_undef(angle), "The angle parameter has been replaced by ang, which specifies trapezoid interior angle") assert(is_undef(angle), "The angle parameter has been replaced by ang, which specifies trapezoid interior angle")
assert(is_undef(h) || is_finite(h)) assert(is_undef(h) || is_finite(h))
@ -927,17 +951,15 @@ function trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anc
assert(is_finite(rounding) || is_vector(rounding,4)) assert(is_finite(rounding) || is_vector(rounding,4))
let( let(
ang = force_list(ang,2), ang = force_list(ang,2),
angOK = ang==[undef,undef] || (all_positive(ang) && ang[0]<180 && ang[1]<180) angOK = len(ang)==2 && (ang==[undef,undef] || (all_positive(ang) && ang[0]<180 && ang[1]<180))
) )
assert(angOK, "trapezoid angles must be strictly between 0 and 180") assert(angOK, "trapezoid angles must be scalar or 2-vector, strictly between 0 and 180")
let( let(
simple = chamfer==0 && rounding==0, h_w1_w2_shift = _trapezoid_dims(h,w1,w2,shift,ang),
h = is_def(h)? h : (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1]), h = h_w1_w2_shift[0],
x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]), w1 = h_w1_w2_shift[1],
x2 = is_undef(ang[1]) || ang[1]==90 ? 0 : h/tan(ang[1]), w2 = h_w1_w2_shift[2],
w1 = is_def(w1)? w1 : w2 + x1 + x2, shift = h_w1_w2_shift[3],
w2 = is_def(w2)? w2 : w1 - x1 - x2,
shift = first_defined([shift,(x1-x2)/2]),
chamfer = force_list(chamfer,4), chamfer = force_list(chamfer,4),
rounding = force_list(rounding,4) rounding = force_list(rounding,4)
) )
@ -1018,16 +1040,16 @@ function trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anc
module trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0, atype="box", angle) { module trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0, atype="box", angle) {
path_over = trapezoid(h=h, w1=w1, w2=w2, ang=ang, shift=shift, chamfer=chamfer, rounding=rounding, flip=flip, angle=angle,atype=atype,_return_override=true); path_over = trapezoid(h=h, w1=w1, w2=w2, ang=ang, shift=shift, chamfer=chamfer, rounding=rounding,
flip=flip, angle=angle,atype=atype,_return_override=true);
path=path_over[0]; path=path_over[0];
override = path_over[1]; override = path_over[1];
ang = force_list(ang,2); ang = force_list(ang,2);
h = is_def(h)? h : (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1]); h_w1_w2_shift = _trapezoid_dims(h,w1,w2,shift,ang);
x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]); h = h_w1_w2_shift[0];
x2 = is_undef(ang[1]) || ang[1]==90 ? 0 : h/tan(ang[1]); w1 = h_w1_w2_shift[1];
w1 = is_def(w1)? w1 : w2 + x1 + x2; w2 = h_w1_w2_shift[2];
w2 = is_def(w2)? w2 : w1 - x1 - x2; shift = h_w1_w2_shift[3];
shift = first_defined([shift,(x1-x2)/2]);
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, override=override) { attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, override=override) {
polygon(path); polygon(path);
children(); children();

View file

@ -565,30 +565,32 @@ function cuboid(
// Function&Module: prismoid() // Function&Module: prismoid()
// //
// Usage: Typical Prismoids // Usage:
// prismoid(size1, size2, h|l, [shift], ...) [ATTACHMENTS]; // prismoid(size1, size2, [h|l|height|length], [shift], [xang=], [yang=], ...) [ATTACHMENTS];
// Usage: Chamfered Prismoids // Usage: Chamfered and/or Rounded Prismoids
// prismoid(size1, size2, h|l, [chamfer=], ...) [ATTACHMENTS]; // prismoid(size1, size2, h|l|height|length, [chamfer=], [rounding=]...) [ATTACHMENTS];
// prismoid(size1, size2, h|l, [chamfer1=], [chamfer2=], ...) [ATTACHMENTS]; // prismoid(size1, size2, h|l|height|length, [chamfer1=], [chamfer2=], [rounding1=], [rounding2=], ...) [ATTACHMENTS];
// Usage: Rounded Prismoids
// prismoid(size1, size2, h|l, [rounding=], ...) [ATTACHMENTS];
// prismoid(size1, size2, h|l, [rounding1=], [rounding2=], ...) [ATTACHMENTS];
// Usage: As Function // Usage: As Function
// vnf = prismoid(size1, size2, h|l, [shift], [rounding], [chamfer]); // vnf = prismoid(...);
// vnf = prismoid(size1, size2, h|l, [shift], [rounding1], [rounding2], [chamfer1], [chamfer2]);
//
// Description: // Description:
// Creates a rectangular prismoid shape with optional roundovers and chamfering. // Creates a rectangular prismoid shape with optional roundovers and chamfering.
// You can only round or chamfer the vertical(ish) edges. For those edges, you can // You can only round or chamfer the vertical(ish) edges. For those edges, you can
// specify rounding and/or chamferring per-edge, and for top and bottom separately. // specify rounding and/or chamferring per-edge, and for top and bottom separately.
// If you want to round the bottom or top edges see {{rounded_prism()}}. // If you want to round the bottom or top edges see {{rounded_prism()}}.
// // .
// Specification of the prismoid is similar to specification for {{trapezoid()}}. You can specify the dimensions of the
// bottom and top and its height to get a symmetric prismoid. You can use the shift argument to shift the top face around.
// You can also specify base angles either in the X direction, Y direction or both. In order to avoid overspecification,
// you may need to specify a parameter such as size2 as a list of two values, one of which is undef. For example,
// specifying `size2=[100,undef]` sets the size in the X direction but allows the size in the Y direction to be computed based on yang.
// Arguments: // Arguments:
// size1 = [width, length] of the bottom end of the prism. // size1 = [width, length] of the bottom end of the prism.
// size2 = [width, length] of the top end of the prism. // size2 = [width, length] of the top end of the prism.
// h/l = Height of the prism. // h/l/height/length = Height of the prism.
// shift = [X,Y] amount to shift the center of the top end with respect to the center of the bottom end. // shift = [X,Y] amount to shift the center of the top end with respect to the center of the bottom end.
// --- // ---
// xang = base angle in the X direction. Can be a scalar or list of two values, one of which may be undef
// yang = base angle in the Y direction. Can be a scalar or list of two values, one of which may be undef
// rounding = The roundover radius for the vertical-ish edges of the prismoid. 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) // rounding = The roundover radius for the vertical-ish edges of the prismoid. 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)
// rounding1 = The roundover radius for the bottom of the vertical-ish edges of the prismoid. 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-]. // rounding1 = The roundover radius for the bottom of the vertical-ish edges of the prismoid. 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-].
// rounding2 = The roundover radius for the top of the vertical-ish edges of the prismoid. 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-]. // rounding2 = The roundover radius for the top of the vertical-ish edges of the prismoid. 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-].
@ -599,14 +601,14 @@ function cuboid(
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP` // orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// //
// See Also: cuboid(), rounded_prism() // See Also: cuboid(), rounded_prism(), trapezoid()
// //
// Example: Truncated Pyramid
// prismoid(size1=[35,50], size2=[20,30], h=20);
// Example: Rectangular Pyramid // Example: Rectangular Pyramid
// prismoid([40,40], [0,0], h=20); // prismoid([40,40], [0,0], h=20);
// Example: Prism // Example: Prism
// prismoid(size1=[40,40], size2=[0,40], h=20); // prismoid(size1=[40,40], size2=[0,40], h=20);
// Example: Truncated Pyramid
// prismoid(size1=[35,50], size2=[20,30], h=20);
// Example: Wedge // Example: Wedge
// prismoid(size1=[60,35], size2=[30,0], h=30); // prismoid(size1=[60,35], size2=[30,0], h=30);
// Example: Truncated Tetrahedron // Example: Truncated Tetrahedron
@ -617,9 +619,19 @@ function cuboid(
// prismoid(size1=[30,60], size2=[0,60], shift=[-15,0], h=30); // prismoid(size1=[30,60], size2=[0,60], shift=[-15,0], h=30);
// Example(FlatSpin,VPD=160,VPT=[0,0,10]): Shifting/Skewing // Example(FlatSpin,VPD=160,VPT=[0,0,10]): Shifting/Skewing
// prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]); // prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]);
// Example: Specifying bottom, height and angle
// prismoid(size1=[100,75], h=30, xang=50, yang=70);
// Example: Specifying top, height and angle, with asymmetric angles
// prismoid(size2=[100,75], h=30, xang=[50,60], yang=[70,40]);
// Example: Specifying top, bottom and angle for X and using that to define height. Note that giving yang here would likely give a conflicting height calculation, which is not allowed.
// prismoid(size1=[100,75], size2=[75,35], xang=50);
// Example: The same as the previous example but we give a shift in Y. Note that shift.x must be undef because you cannot give combine an angle with a shift, so a shift.x value would conflict with xang being defined.
// prismoid(size1=[100,75], size2=[75,35], xang=50, shift=[undef,20]);
// Example: The X dimensions defined by the base length, angle and height; the Y dimensions defined by the top length, angle, and height.
// prismoid(size1=[100,undef], size2=[undef,75], h=30, xang=[20,90], yang=30);
// Example: Rounding // Example: Rounding
// prismoid(100, 80, rounding=10, h=30); // prismoid(100, 80, rounding=10, h=30);
// Example: Outer Chamfer Only // Example: Chamfers
// prismoid(100, 80, chamfer=5, h=30); // prismoid(100, 80, chamfer=5, h=30);
// Example: Gradiant Rounding // Example: Gradiant Rounding
// prismoid(100, 80, rounding1=10, rounding2=0, h=30); // prismoid(100, 80, rounding1=10, rounding2=0, h=30);
@ -644,46 +656,25 @@ function cuboid(
// show_anchors(); // show_anchors();
module prismoid( module prismoid(
size1, size2, h, shift=[0,0], size1=undef, size2=undef, h, shift=[undef,undef],
xang, yang,
rounding=0, rounding1, rounding2, rounding=0, rounding1, rounding2,
chamfer=0, chamfer1, chamfer2, chamfer=0, chamfer1, chamfer2,
l, height, length, center, l, height, length, center,
anchor, spin=0, orient=UP anchor, spin=0, orient=UP
) { )
checks = {
assert(is_num(size1) || is_vector(size1,2)) vnf_s1_s2_shift = prismoid(
assert(is_num(size2) || is_vector(size2,2))
assert(is_num(h) || is_num(l))
assert(is_vector(shift,2))
assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.")
assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.")
assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.")
assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.")
assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.")
assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.");
eps = pow(2,-14);
size1 = is_num(size1)? [size1,size1] : size1;
size2 = is_num(size2)? [size2,size2] : size2;
checks2 =
assert(all_nonnegative(size1))
assert(all_nonnegative(size2))
assert(size1.x + size2.x > 0)
assert(size1.y + size2.y > 0);
s1 = [max(size1.x, eps), max(size1.y, eps)];
s2 = [max(size2.x, eps), max(size2.y, eps)];
rounding1 = default(rounding1, rounding);
rounding2 = default(rounding2, rounding);
chamfer1 = default(chamfer1, chamfer);
chamfer2 = default(chamfer2, chamfer);
anchor = get_anchor(anchor, center, BOT, BOT);
vnf = prismoid(
size1=size1, size2=size2, h=h, shift=shift, size1=size1, size2=size2, h=h, shift=shift,
xang=xang, yang=yang,
rounding=rounding, chamfer=chamfer,
rounding1=rounding1, rounding2=rounding2, rounding1=rounding1, rounding2=rounding2,
chamfer1=chamfer1, chamfer2=chamfer2, chamfer1=chamfer1, chamfer2=chamfer2,
l=l, center=CENTER l=l, height=height, length=length, center=CENTER, _return_dim=true
); );
attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) { anchor = get_anchor(anchor, center, BOT, BOT);
vnf_polyhedron(vnf, convexity=4); attachable(anchor,spin,orient, size=vnf_s1_s2_shift[1], size2=vnf_s1_s2_shift[2], shift=vnf_s1_s2_shift[3]) {
vnf_polyhedron(vnf_s1_s2_shift[0], convexity=4);
children(); children();
} }
} }
@ -693,78 +684,90 @@ function prismoid(
rounding=0, rounding1, rounding2, rounding=0, rounding1, rounding2,
chamfer=0, chamfer1, chamfer2, chamfer=0, chamfer1, chamfer2,
l, height, length, center, l, height, length, center,
anchor=DOWN, spin=0, orient=UP anchor=DOWN, spin=0, orient=UP, xang, yang,
_return_dim=false
) = ) =
assert(is_vector(size1,2)) assert(is_undef(shift) || is_num(shift) || len(shift)==2, "shift must be a number or list of length 2")
assert(is_vector(size2,2)) assert(is_undef(size1) || is_num(size1) || len(size1)==2, "size1 must be a number or list of length 2")
assert(is_num(h) || is_num(l)) assert(is_undef(size2) || is_num(size2) || len(size2)==2, "size2 must be a number or list of length 2")
assert(is_vector(shift,2)) let(
assert( xang = force_list(xang,2),
(is_num(rounding) && rounding>=0) || yang = force_list(yang,2),
(is_vector(rounding,4) && all_nonnegative(rounding)), yangOK = len(yang)==2 && (yang==[undef,undef] || (all_positive(yang) && yang[0]<180 && yang[1]<180)),
"Bad rounding argument." xangOK = len(xang)==2 && (xang==[undef,undef] || (all_positive(xang) && xang[0]<180 && xang[1]<180)),
size1=force_list(size1,2),
size2=force_list(size2,2),
h=first_defined([l,h,length,height]),
shift = force_list(shift,2),
fff=echo(size1=size1,size2=size2)
) )
assert( assert(xangOK, "prismoid angles must be scalar or 2-vector, strictly between 0 and 180")
is_undef(rounding1) || (is_num(rounding1) && rounding1>=0) || assert(yangOK, "prismoid angles must be scalar or 2-vector, strictly between 0 and 180")
(is_vector(rounding1,4) && all_nonnegative(rounding1)), assert(xang==[undef,undef] || shift.x==undef, "Cannot specify xang and a shift.x value together")
"Bad rounding1 argument." assert(yang==[undef,undef] || shift.y==undef, "Cannot specify yang and a shift.y value together")
assert(all_positive([h]) || is_undef(h), "h must be a positive value")
let(
hx = _trapezoid_dims(h,size1.x,size2.x,shift.x,xang)[0],
hy = _trapezoid_dims(h,size1.y,size2.y,shift.y,yang)[0]
,eerr=echo(hx=hx,hy=hy,xang=xang,yang=yang)
) )
assert( assert(num_defined([hx,hy])>0, "Height not given and specification does not determine prismoid height")
is_undef(rounding2) || (is_num(rounding2) && rounding2>=0) || assert(hx==undef || hy==undef || approx(hx,hy),
(is_vector(rounding2,4) && all_nonnegative(rounding2)), str("X and Y angle specifications give rise to conflicting height values ",hx," and ",hy))
"Bad rounding2 argument." let(
) h = first_defined([hx,hy]),
assert( x_h_w1_w2_shift = _trapezoid_dims(h,size1.x,size2.x,shift.x,xang),
(is_num(chamfer) && chamfer>=0) || y_h_w1_w2_shift = _trapezoid_dims(h,size1.y,size2.y,shift.y,yang)
(is_vector(chamfer,4) && all_nonnegative(chamfer)),
"Bad chamfer argument."
)
assert(
is_undef(chamfer1) || (is_num(chamfer1) && chamfer1>=0) ||
(is_vector(chamfer1,4) && all_nonnegative(chamfer1)),
"Bad chamfer1 argument."
)
assert(
is_undef(chamfer2) || (is_num(chamfer2) && chamfer2>=0) ||
(is_vector(chamfer2,4) && all_nonnegative(chamfer2)),
"Bad chamfer2 argument."
) )
let( let(
eps = pow(2,-14), s1 = [x_h_w1_w2_shift[1], y_h_w1_w2_shift[1]],
h = one_defined([h,l,length,height],"h,l,length,height",dflt=1), s2 = [x_h_w1_w2_shift[2], y_h_w1_w2_shift[2]],
shiftby = point3d(point2d(shift)), shift = [x_h_w1_w2_shift[3], y_h_w1_w2_shift[3]]
s1 = [max(size1.x, eps), max(size1.y, eps)], )
s2 = [max(size2.x, eps), max(size2.y, eps)], assert(is_vector(s1,2), "Insufficient information to define prismoid")
assert(is_vector(s2,2), "Insufficient information to define prismoid")
assert(all_nonnegative(concat(s1,s2)),"Degenerate prismoid geometry")
assert(s1.x+s2.x>0 && s1.y+s2.y>0, "Degenerate prismoid geometry")
assert(is_num(rounding) || is_vector(rounding,4), "rounding must be a number or 4-vector")
assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "rounding1 must be a number or 4-vector")
assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "rounding2 must be a number or 4-vector")
assert(is_num(chamfer) || is_vector(chamfer,4), "chamfer must be a number or 4-vector")
assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "chamfer1 must be a number or 4-vector")
assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "chamfer2 must be a number or 4-vector")
let(
chamfer1=force_list(default(chamfer1,chamfer),4),
chamfer2=force_list(default(chamfer2,chamfer),4),
rounding1=force_list(default(rounding1,rounding),4),
rounding2=force_list(default(rounding2,rounding),4)
)
assert(all_nonnegative(chamfer1), "chamfer/chamfer1 must be non-negative")
assert(all_nonnegative(chamfer2), "chamfer/chamfer2 must be non-negative")
assert(all_nonnegative(rounding1), "rounding/rounding1 must be non-negative")
assert(all_nonnegative(rounding2), "rounding/rounding2 must be non-negative")
assert(all_zero(v_mul(rounding1,chamfer1),0),
"rounding1 and chamfer1 (possibly inherited from rounding and chamfer) cannot both be nonzero at the same corner")
assert(all_zero(v_mul(rounding2,chamfer2),0),
"rounding2 and chamfer2 (possibly inherited from rounding and chamfer) cannot both be nonzero at the same corner")
let(
ffda=echo(s1=s1,s2=s2,h=h,shift=shift),
rounding1 = default(rounding1, rounding), rounding1 = default(rounding1, rounding),
rounding2 = default(rounding2, rounding), rounding2 = default(rounding2, rounding),
chamfer1 = default(chamfer1, chamfer), chamfer1 = default(chamfer1, chamfer),
chamfer2 = default(chamfer2, chamfer), chamfer2 = default(chamfer2, chamfer),
anchor = get_anchor(anchor, center, BOT, BOT), anchor = get_anchor(anchor, center, BOT, BOT),
vnf = (rounding1==0 && rounding2==0 && chamfer1==0 && chamfer2==0)? ( path1 = rect(s1, rounding=rounding1, chamfer=chamfer1, anchor=CTR),
let( path2 = rect(s2, rounding=rounding2, chamfer=chamfer2, anchor=CTR),
corners = [[1,1],[1,-1],[-1,-1],[-1,1]] * 0.5, points = [
points = [
for (p=corners) point3d(v_mul(s2,p), +h/2) + shiftby,
for (p=corners) point3d(v_mul(s1,p), -h/2)
],
faces=[
[0,1,2], [0,2,3], [0,4,5], [0,5,1],
[1,5,6], [1,6,2], [2,6,7], [2,7,3],
[3,7,4], [3,4,0], [4,7,6], [4,6,5],
]
) [points, faces]
) : (
let(
path1 = rect(size1, rounding=rounding1, chamfer=chamfer1, anchor=CTR),
path2 = rect(size2, rounding=rounding2, chamfer=chamfer2, anchor=CTR),
points = [
each path3d(path1, -h/2), each path3d(path1, -h/2),
each path3d(move(shiftby, p=path2), +h/2), each path3d(move(shift, path2), +h/2),
], ],
faces = hull(points) faces = hull(points),
) [points, faces] vnf = [points, faces]
) )
) reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf); _return_dim ? [reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf),point3d(s1,h),s2,shift]
: reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf);
// Function&Module: octahedron() // Function&Module: octahedron()
@ -1009,7 +1012,7 @@ module rect_tube(
assert(is_undef(ichamfer) || is_num(ichamfer) || (is_list(ichamfer) && len(ichamfer)==4), "ichamfer must be a number or 4-vector") assert(is_undef(ichamfer) || is_num(ichamfer) || (is_list(ichamfer) && len(ichamfer)==4), "ichamfer must be a number or 4-vector")
assert(is_undef(ichamfer1) || is_num(ichamfer1) || (is_list(ichamfer1) && len(ichamfer1)==4), "ichamfer1 must be a number or 4-vector") assert(is_undef(ichamfer1) || is_num(ichamfer1) || (is_list(ichamfer1) && len(ichamfer1)==4), "ichamfer1 must be a number or 4-vector")
assert(is_undef(ichamfer2) || is_num(ichamfer2) || (is_list(ichamfer2) && len(ichamfer2)==4), "ichamfer2 must be a number or 4-vector"); assert(is_undef(ichamfer2) || is_num(ichamfer2) || (is_list(ichamfer2) && len(ichamfer2)==4), "ichamfer2 must be a number or 4-vector");
chamfer1=force_list( is_def(chamfer1)?chamfer1 : default(chamfer1,chamfer),4); chamfer1=force_list(default(chamfer1,chamfer),4);
chamfer2=force_list(default(chamfer2,chamfer),4); chamfer2=force_list(default(chamfer2,chamfer),4);
rounding1=force_list(default(rounding1,rounding),4); rounding1=force_list(default(rounding1,rounding),4);
rounding2=force_list(default(rounding2,rounding),4); rounding2=force_list(default(rounding2,rounding),4);