Hid textured_*() functions/modules. Integrated textures into cyl(), linear_sweep(), and rotate_sweep()

This commit is contained in:
Revar Desmera 2022-08-20 23:31:50 -07:00
parent f96826d9ac
commit 60a565381a
3 changed files with 728 additions and 429 deletions

View file

@ -52,6 +52,7 @@ use <builtins.scad>
// Example: Called as Function // Example: Called as Function
// vnf = cube([20,40,50]); // vnf = cube([20,40,50]);
// vnf_polyhedron(vnf); // vnf_polyhedron(vnf);
module cube(size=1, center, anchor, spin=0, orient=UP) module cube(size=1, center, anchor, spin=0, orient=UP)
{ {
anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]); anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]);
@ -177,6 +178,7 @@ function cube(size=1, center, anchor, spin=0, orient=UP) =
// cuboid([4,2,1], rounding=2, edges=[FWD+RIGHT,BACK+LEFT]); // cuboid([4,2,1], rounding=2, edges=[FWD+RIGHT,BACK+LEFT]);
// Example: Standard Connectors // Example: Standard Connectors
// cuboid(40) show_anchors(); // cuboid(40) show_anchors();
module cuboid( module cuboid(
size=[1,1,1], size=[1,1,1],
p1, p2, p1, p2,
@ -633,6 +635,7 @@ function cuboid(
// Example(Spin,VPD=160,VPT=[0,0,10]): Standard Connectors // Example(Spin,VPD=160,VPT=[0,0,10]): Standard Connectors
// prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]) // prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5])
// show_anchors(); // show_anchors();
module prismoid( module prismoid(
size1, size2, h, shift=[0,0], size1, size2, h, shift=[0,0],
rounding=0, rounding1, rounding2, rounding=0, rounding1, rounding2,
@ -775,6 +778,7 @@ function prismoid(
// octahedron(size=40); // octahedron(size=40);
// Example: Anchors // Example: Anchors
// octahedron(size=40) show_anchors(); // octahedron(size=40) show_anchors();
module octahedron(size=1, anchor=CENTER, spin=0, orient=UP) { module octahedron(size=1, anchor=CENTER, spin=0, orient=UP) {
vnf = octahedron(size=size); vnf = octahedron(size=size);
attachable(anchor,spin,orient, vnf=vnf, extent=true) { attachable(anchor,spin,orient, vnf=vnf, extent=true) {
@ -900,6 +904,7 @@ function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) =
// rounding1=[5,0,10,0], irounding1=[3,0,8,0], // rounding1=[5,0,10,0], irounding1=[3,0,8,0],
// rounding2=[0,5,0,10], irounding2=[0,3,0,8] // rounding2=[0,5,0,10], irounding2=[0,3,0,8]
// ); // );
module rect_tube( module rect_tube(
h, size, isize, center, shift=[0,0], h, size, isize, center, shift=[0,0],
wall, size1, size2, isize1, isize2, wall, size1, size2, isize1, isize2,
@ -1014,6 +1019,7 @@ function rect_tube(
// wedge([20, 40, 15]); // wedge([20, 40, 15]);
// Example: Standard Connectors // Example: Standard Connectors
// wedge([20, 40, 15]) show_anchors(); // wedge([20, 40, 15]) show_anchors();
module wedge(size=[1, 1, 1], center, anchor, spin=0, orient=UP) module wedge(size=[1, 1, 1], center, anchor, spin=0, orient=UP)
{ {
size = scalar_vec3(size); size = scalar_vec3(size);
@ -1095,6 +1101,7 @@ function wedge(size=[1,1,1], center, anchor, spin=0, orient=UP) =
// cylinder(h=30, d=25) show_anchors(); // cylinder(h=30, d=25) show_anchors();
// cylinder(h=30, d1=25, d2=10) show_anchors(); // cylinder(h=30, d1=25, d2=10) show_anchors();
// } // }
module cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP) module cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
{ {
anchor = get_anchor(anchor, center, BOTTOM, BOTTOM); anchor = get_anchor(anchor, center, BOTTOM, BOTTOM);
@ -1128,13 +1135,7 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// Module: cyl() // Function&Module: cyl()
//
// Description:
// Creates cylinders in various anchorings and orientations, with optional rounding and chamfers.
// You can use `h` and `l` interchangably, and all variants allow specifying size by either `r`|`d`,
// or `r1`|`d1` and `r2`|`d2`. Note: the chamfers and rounding cannot be cumulatively longer than
// the cylinder's length.
// //
// Usage: Normal Cylinders // Usage: Normal Cylinders
// cyl(l|h, r, [center], [circum=], [realign=]) [ATTACHMENTS]; // cyl(l|h, r, [center], [circum=], [realign=]) [ATTACHMENTS];
@ -1154,6 +1155,14 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// cyl(l|h, r|d, rounding2=, ...); // cyl(l|h, r|d, rounding2=, ...);
// cyl(l|h, r|d, rounding1=, rounding2=, ...); // cyl(l|h, r|d, rounding1=, rounding2=, ...);
// //
// Topics: Cylinders, Textures, Rounding, Chamfers
//
// Description:
// Creates cylinders in various anchorings and orientations, with optional rounding and chamfers.
// You can use `h` and `l` interchangably, and all variants allow specifying size by either `r`|`d`,
// or `r1`|`d1` and `r2`|`d2`. Note: the chamfers and rounding cannot be cumulatively longer than
// the cylinder's length.
//
// Arguments: // Arguments:
// l / h = Length of cylinder along oriented axis. Default: 1 // l / h = Length of cylinder along oriented axis. Default: 1
// r = Radius of cylinder. Default: 1 // r = Radius of cylinder. Default: 1
@ -1165,6 +1174,7 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// d1 = Diameter of the negative (X-, Y-, Z-) end of cylinder. // d1 = Diameter of the negative (X-, Y-, Z-) end of cylinder.
// d2 = Diameter of the positive (X+, Y+, Z+) end of cylinder. // d2 = Diameter of the positive (X+, Y+, Z+) end of cylinder.
// circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false` // circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false`
// shift = [X,Y] amount to shift the center of the top end with respect to the center of the bottom end.
// chamfer = The size of the chamfers on the ends of the cylinder. Default: none. // chamfer = The size of the chamfers on the ends of the cylinder. Default: none.
// chamfer1 = The size of the chamfer on the bottom end of the cylinder. Default: none. // chamfer1 = The size of the chamfer on the bottom end of the cylinder. Default: none.
// chamfer2 = The size of the chamfer on the top end of the cylinder. Default: none. // chamfer2 = The size of the chamfer on the top end of the cylinder. Default: none.
@ -1176,10 +1186,20 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// rounding1 = The radius of the rounding on the bottom end of the cylinder. // rounding1 = The radius of the rounding on the bottom end of the cylinder.
// rounding2 = The radius of the rounding on the top end of the cylinder. // rounding2 = The radius of the rounding on the top end of the cylinder.
// realign = If true, rotate the cylinder by half the angle of one face. // realign = If true, rotate the cylinder by half the angle of one face.
// texture = A texture name string, or a rectangular array of scalar height values (0.0 to 1.0), or a VNF tile that defines the texture to apply to vertical surfaces. See {{texture()}} for what named textures are supported.
// tex_size = An optional 2D target size for the textures. Actual texture sizes will be scaled somewhat to evenly fit the available surface. Default: `[5,5]`
// tex_counts = If given instead of tex_size, gives the tile repetition counts for textures over the surface length and height.
// tex_inset = If numeric, lowers the texture into the surface by that amount, before the tex_scale multiplier is applied. If `true`, insets by exactly `1`. Default: `false`
// tex_rot = If true, rotates the texture 90º.
// tex_scale = Scaling multiplier for the texture depth.
// tex_samples = Minimum number of "bend points" to have in VNF texture tiles. Default: 8
// tex_style = {{vnf_vertex_array()}} style used to triangulate heightfield textures. Default: "min_edge"
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// 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: texture(), rotate_sweep()
//
// Example: By Radius // Example: By Radius
// xdistribute(30) { // xdistribute(30) {
// cyl(l=40, r=10); // cyl(l=40, r=10);
@ -1230,6 +1250,156 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// cyl(l=30, d1=25, d2=10) show_anchors(); // cyl(l=30, d1=25, d2=10) show_anchors();
// } // }
// //
// Example: Texturing with heightfield diamonds
// cyl(h=40, r=20, texture="diamonds", tex_size=[5,5]);
//
// Example: Texturing with heightfield pyramids
// cyl(h=40, r1=20, r2=15,
// texture="pyramids", tex_size=[5,5],
// tex_style="convex");
//
// Example: Texturing with heightfield truncated pyramids
// cyl(h=40, r1=20, r2=15, chamfer=5,
// texture="trunc_pyramids",
// tex_size=[5,5], tex_style="convex");
//
// Example: Texturing with VNF tile "vnf_dots"
// cyl(h=40, r1=20, r2=15, rounding=9,
// texture="vnf_dots", tex_size=[5,5],
// samples=6);
//
// Example: Texturing with VNF tile "vnf_bricks"
// cyl(h=50, r1=25, r2=20, shift=[0,10], rounding1=-10,
// texture="vnf_bricks", tex_size=[10,10],
// tex_scale=0.5, tex_style="concave");
//
// Example: No Texture Taper
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", tex_size=[5,1]);
//
// Example: Taper Texure at Extreme Ends
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", taper=0,
// tex_size=[5,1]);
//
// Example: Taper Texture over First and Last 10%
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", taper=10,
// tex_size=[5,1]);
function cyl(
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false,
from_end=false, shift=[0,0],
texture, tex_size=[5,5], tex_counts,
tex_inset=false, tex_rot=false,
tex_scale=1, tex_samples,
tex_taper, tex_style="min_edge",
anchor, spin=0, orient=UP
) =
let(
l = first_defined([l, h, length, height, 1]),
_r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
_r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
sides = segs(max(_r1,_r2)),
sc = circum? 1/cos(180/sides) : 1,
r1 = _r1 * sc,
r2 = _r2 * sc,
phi = atan2(l, r2-r1),
anchor = get_anchor(anchor,center,BOT,CENTER)
)
assert(is_finite(l), "l/h/length/height must be a finite number.")
assert(is_finite(r1), "r/r1/d/d1 must be a finite number.")
assert(is_finite(r2), "r2 or d2 must be a finite number.")
assert(is_vector(shift,2), "shift must be a 2D vector.")
let(
vnf = texture != undef? _textured_cylinder(
l=l, r1=r1, r2=r2,
texture=texture, tex_size=tex_size,
counts=tex_counts, tex_scale=tex_scale,
inset=tex_inset, rot=tex_rot,
style=tex_style, taper=tex_taper,
chamfer=chamfer,
chamfer1=chamfer1,
chamfer2=chamfer2,
rounding=rounding,
rounding1=rounding1,
rounding2=rounding2,
samples=tex_samples
) :
!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])?
cylinder(h=l, r1=r1, r2=r2, center=true, $fn=sides) :
let(
vang = atan2(l, r1-r2)/2,
chang = default(chamfang, 45),
chang1 = 90-first_defined([chamfang1, chamfang, vang]),
chang2 = 90-first_defined([chamfang2, chamfang, 90-vang]),
checks1 =
assert(is_finite(chang) && chang>0 && chang<90, "chamfang must be a number between 0 and 90 (exclusive) if given.")
assert(is_finite(chang1) && chang1>0 && chang1<90, "chamfang1 must be a number between 0 and 90 (exclusive) if given.")
assert(is_finite(chang2) && chang2>0 && chang2<90, "chamfang2 must be a number between 0 and 90 (exclusive) if given.")
undef,
chamf = default(chamfer, 0) * (from_end? 1 : tan(chang1)),
chamf1 = first_defined([chamfer1, chamfer, 0]) * (from_end? 1 : tan(chang1)),
chamf2 = first_defined([chamfer2, chamfer, 0]) * (from_end? 1 : tan(chang2)),
round = default(rounding, 0),
round1 = first_defined([rounding1, rounding, 0]),
round2 = first_defined([rounding2, rounding, 0]),
dy1 = abs(first_defined([chamf1, round1, 0])),
dy2 = abs(first_defined([chamf2, round2, 0])),
checks2 =
assert(is_finite(chamf), "chamfer must be a finite number if given.")
assert(is_finite(chamf1), "chamfer1 must be a finite number if given.")
assert(is_finite(chamf2), "chamfer2 must be a finite number if given.")
assert(is_finite(round), "rounding must be a finite number if given.")
assert(is_finite(round1), "rounding1 must be a finite number if given.")
assert(is_finite(round2), "rounding2 must be a finite number if given.")
assert(chamf <= r1, "chamfer is larger than the r1 radius of the cylinder.")
assert(chamf <= r2, "chamfer is larger than the r2 radius of the cylinder.")
assert(chamf1 <= r1, "chamfer1 is larger than the r1 radius of the cylinder.")
assert(chamf2 <= r2, "chamfer2 is larger than the r2 radius of the cylinder.")
assert(round <= r1, "rounding is larger than the r1 radius of the cylinder.")
assert(round <= r2, "rounding is larger than the r2 radius of the cylinder.")
assert(round1 <= r1, "rounding1 is larger than the r1 radius of the cylinder.")
assert(round2 <= r2, "rounding2 is larger than the r1 radius of the cylinder.")
assert(dy1+dy2 <= l, "Sum of fillets and chamfer sizes must be less than the length of the cylinder.")
undef,
path = [
[0,-l/2],
if (is_finite(chamf1) && !approx(chamf1,0))
let(
p1 = [r1-chamf1/tan(chang1),-l/2],
p2 = lerp([r1,-l/2],[r2,l/2],abs(chamf1)/l)
) each [p1,p2]
else if (is_finite(round1) && !approx(round1,0))
each arc(r=abs(round1), corner=[[(round1>0?0:1e6),-l/2],[r1,-l/2],[r2,l/2]])
else [r1,-l/2],
if (is_finite(chamf2) && !approx(chamf2,0))
let(
p1 = lerp([r2,l/2],[r1,-l/2],abs(chamf2)/l),
p2 = [r2-chamf2/tan(chang2),l/2]
) each [p1,p2]
else if (is_finite(round2) && !approx(round2,0))
each arc(r=abs(round2), corner=[[r1,-l/2],[r2,l/2],[(round2>0?0:1e6),l/2]])
else [r2,l/2],
[0,l/2]
]
) rotate_sweep(path),
skmat = down(l/2) *
skew(sxz=shift.x/l, syz=shift.y/l) *
up(l/2) *
zrot(realign? 180/sides : 0),
ovnf = apply(skmat, vnf)
)
reorient(anchor,spin,orient, r1=r1, r2=r2, l=l, shift=shift, p=ovnf);
module cyl( module cyl(
h, r, center, h, r, center,
l, r1, r2, l, r1, r2,
@ -1237,7 +1407,12 @@ module cyl(
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2, chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2, rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false, circum=false, realign=false,
from_end=false, shift=[0,0],
texture, tex_size=[5,5], tex_counts,
tex_inset=false, tex_rot=false,
tex_scale=1, tex_samples,
tex_taper, tex_style="min_edge",
anchor, spin=0, orient=UP anchor, spin=0, orient=UP
) { ) {
l = first_defined([l, h, 1]); l = first_defined([l, h, 1]);
@ -1245,86 +1420,76 @@ module cyl(
_r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1); _r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
sides = segs(max(_r1,_r2)); sides = segs(max(_r1,_r2));
sc = circum? 1/cos(180/sides) : 1; sc = circum? 1/cos(180/sides) : 1;
r1=_r1*sc; r1 = _r1 * sc;
r2=_r2*sc; r2 = _r2 * sc;
phi = atan2(l, r2-r1); phi = atan2(l, r2-r1);
anchor = get_anchor(anchor,center,BOT,CENTER); anchor = get_anchor(anchor,center,BOT,CENTER);
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) { skmat = down(l/2) * skew(sxz=shift.x/l, syz=shift.y/l) * up(l/2);
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l, shift=shift) {
multmatrix(skmat)
zrot(realign? 180/sides : 0) { zrot(realign? 180/sides : 0) {
if (!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])) { if (texture != undef) {
_textured_cylinder(
l=l, r1=r1, r2=r2,
texture=texture, tex_size=tex_size,
counts=tex_counts, tex_scale=tex_scale,
inset=tex_inset, rot=tex_rot,
style=tex_style, taper=tex_taper,
chamfer=chamfer,
chamfer1=chamfer1,
chamfer2=chamfer2,
rounding=rounding,
rounding1=rounding1,
rounding2=rounding2,
convexity=10, samples=tex_samples
);
} else if (!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])) {
cylinder(h=l, r1=r1, r2=r2, center=true, $fn=sides); cylinder(h=l, r1=r1, r2=r2, center=true, $fn=sides);
} else { } else {
vang = atan2(l, r1-r2)/2; vang = atan2(l, r1-r2)/2;
chang1 = 90-first_defined([chamfang1, chamfang, vang]); chang1 = 90-first_defined([chamfang1, chamfang, vang,]);
chang2 = 90-first_defined([chamfang2, chamfang, 90-vang]); chang2 = 90-first_defined([chamfang2, chamfang, 90-vang]);
cham1 = u_mul(first_defined([chamfer1, chamfer]) , (from_end? 1 : tan(chang1))); chamf = default(chamfer, 0) * (from_end? 1 : tan(chang1));
cham2 = u_mul(first_defined([chamfer2, chamfer]) , (from_end? 1 : tan(chang2))); chamf1 = first_defined([chamfer1, chamfer, 0]) * (from_end? 1 : tan(chang1));
fil1 = first_defined([rounding1, rounding]); chamf2 = first_defined([chamfer2, chamfer, 0]) * (from_end? 1 : tan(chang2));
fil2 = first_defined([rounding2, rounding]); round = default(rounding, 0);
if (chamfer != undef) { round1 = first_defined([rounding1, rounding, 0]);
checks = round2 = first_defined([rounding2, rounding, 0]);
assert(chamfer <= r1, "chamfer is larger than the r1 radius of the cylinder.") dy1 = abs(first_defined([chamf1, round1, 0]));
assert(chamfer <= r2, "chamfer is larger than the r2 radius of the cylinder."); dy2 = abs(first_defined([chamf2, round2, 0]));
} checks =
if (cham1 != undef) { assert(chamf <= r1, "chamfer is larger than the r1 radius of the cylinder.")
check = assert(cham1 <= r1, "chamfer1 is larger than the r1 radius of the cylinder."); assert(chamf <= r2, "chamfer is larger than the r2 radius of the cylinder.")
} assert(chamf1 <= r1, "chamfer1 is larger than the r1 radius of the cylinder.")
if (cham2 != undef) { assert(chamf2 <= r2, "chamfer2 is larger than the r2 radius of the cylinder.")
check = assert(cham2 <= r2, "chamfer2 is larger than the r2 radius of the cylinder."); assert(round <= r1, "rounding is larger than the r1 radius of the cylinder.")
} assert(round <= r2, "rounding is larger than the r2 radius of the cylinder.")
if (rounding != undef) { assert(round1 <= r1, "rounding1 is larger than the r1 radius of the cylinder.")
checks = assert(round2 <= r2, "rounding2 is larger than the r1 radius of the cylinder.")
assert(rounding <= r1, "rounding is larger than the r1 radius of the cylinder.") assert(dy1+dy2 <= l, "Sum of fillets and chamfer sizes must be less than the length of the cylinder.")
assert(rounding <= r2, "rounding is larger than the r2 radius of the cylinder."); undef;
} path = [
if (fil1 != undef) { [0,-l/2],
check = assert(fil1 <= r1, "rounding1 is larger than the r1 radius of the cylinder."); if (is_finite(chamf1) && !approx(chamf1,0))
}
if (fil2 != undef) {
check = assert(fil2 <= r2, "rounding2 is larger than the r1 radius of the cylinder.");
}
dy1 = abs(first_defined([cham1, fil1, 0]));
dy2 = abs(first_defined([cham2, fil2, 0]));
check = assert(dy1+dy2 <= l, "Sum of fillets and chamfer sizes must be less than the length of the cylinder.");
path = concat(
[[0,l/2]],
!is_undef(cham2)? (
let( let(
p1 = [r2-cham2/tan(chang2),l/2], p1 = [r1-chamf1/tan(chang1),-l/2],
p2 = lerp([r2,l/2],[r1,-l/2],abs(cham2)/l) p2 = lerp([r1,-l/2],[r2,l/2],abs(chamf1)/l)
) [p1,p2] ) each [p1,p2]
) : !is_undef(fil2)? ( else if (is_finite(round1) && !approx(round1,0))
each arc(r=abs(round1), corner=[[(round1>0?0:1e6),-l/2],[r1,-l/2],[r2,l/2]])
else [r1,-l/2],
if (is_finite(chamf2) && !approx(chamf2,0))
let( let(
cn = circle_2tangents(abs(fil2), [r2-fil2,l/2], [r2,l/2], [r1,-l/2]), p1 = lerp([r2,l/2],[r1,-l/2],abs(chamf2)/l),
ang = fil2<0? phi : phi-180, p2 = [r2-chamf2/tan(chang2),l/2]
steps = ceil(abs(ang)/360*segs(abs(fil2))), ) each [p1,p2]
step = ang/steps, else if (is_finite(round2) && !approx(round2,0))
pts = [for (i=[0:1:steps]) let(a=90+i*step) cn[0]+abs(fil2)*[cos(a),sin(a)]] each arc(r=abs(round2), corner=[[r1,-l/2],[r2,l/2],[(round2>0?0:1e6),l/2]])
) pts else [r2,l/2],
) : [[r2,l/2]], [0,l/2]
];
!is_undef(cham1)? ( rotate_extrude(convexity=2) polygon(path);
let(
p1 = lerp([r1,-l/2],[r2,l/2],abs(cham1)/l),
p2 = [r1-cham1/tan(chang1),-l/2]
) [p1,p2]
) : !is_undef(fil1)? (
let(
cn = circle_2tangents(abs(fil1), [r1-fil1,-l/2], [r1,-l/2], [r2,l/2]),
ang = fil1<0? 180-phi : -phi,
steps = ceil(abs(ang)/360*segs(abs(fil1))),
step = ang/steps,
pts = [for (i=[0:1:steps]) let(a=(fil1<0?180:0)+(phi-90)+i*step) cn[0]+abs(fil1)*[cos(a),sin(a)]]
) pts
) : [[r1,-l/2]],
[[0,-l/2]]
);
rotate_extrude(convexity=2) {
polygon(path);
}
} }
} }
children(); children();
@ -1378,6 +1543,7 @@ module cyl(
// xcyl(l=35, d=20); // xcyl(l=35, d=20);
// xcyl(l=35, d1=30, d2=10); // xcyl(l=35, d1=30, d2=10);
// } // }
module xcyl( module xcyl(
h, r, d, r1, r2, d1, d2, l, h, r, d, r1, r2, d1, d2, l,
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
@ -1448,6 +1614,7 @@ module xcyl(
// ycyl(l=35, d=20); // ycyl(l=35, d=20);
// ycyl(l=35, d1=30, d2=10); // ycyl(l=35, d1=30, d2=10);
// } // }
module ycyl( module ycyl(
h, r, d, r1, r2, d1, d2, l, h, r, d, r1, r2, d1, d2, l,
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
@ -1519,6 +1686,7 @@ module ycyl(
// zcyl(l=35, d=20); // zcyl(l=35, d=20);
// zcyl(l=35, d1=30, d2=10); // zcyl(l=35, d1=30, d2=10);
// } // }
module zcyl( module zcyl(
h, r, d, r1, r2, d1, d2, l, h, r, d, r1, r2, d1, d2, l,
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
@ -1596,6 +1764,7 @@ module zcyl(
// tube(h=30, or1=40, or2=30, ir1=20, ir2=30); // tube(h=30, or1=40, or2=30, ir1=20, ir2=30);
// Example: Standard Connectors // Example: Standard Connectors
// tube(h=30, or=40, wall=5) show_anchors(); // tube(h=30, or=40, wall=5) show_anchors();
module tube( module tube(
h, or, ir, center, h, or, ir, center,
od, id, wall, od, id, wall,
@ -1673,6 +1842,7 @@ module tube(
// Example: Generating a VNF // Example: Generating a VNF
// vnf = pie_slice(ang=150, l=20, r1=30, r2=50); // vnf = pie_slice(ang=150, l=20, r1=30, r2=50);
// vnf_polyhedron(vnf); // vnf_polyhedron(vnf);
module pie_slice( module pie_slice(
h, r, ang=30, center, h, r, ang=30, center,
r1, r2, d, d1, d2, l, r1, r2, d, d1, d2, l,
@ -1696,7 +1866,6 @@ module pie_slice(
} }
} }
function pie_slice( function pie_slice(
h, r, ang=30, center, h, r, ang=30, center,
r1, r2, d, d1, d2, l, r1, r2, d, d1, d2, l,
@ -1774,6 +1943,7 @@ function pie_slice(
// Example: Called as Function // Example: Called as Function
// vnf = sphere(d=100, style="icosa"); // vnf = sphere(d=100, style="icosa");
// vnf_polyhedron(vnf); // vnf_polyhedron(vnf);
module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) { module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) {
r = get_radius(r=r, d=d, dflt=1); r = get_radius(r=r, d=d, dflt=1);
if (!circum && style=="orig" && is_num(r)) { if (!circum && style=="orig" && is_num(r)) {
@ -1789,7 +1959,6 @@ module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP
} }
} }
function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) = function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) =
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient); spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
@ -1884,6 +2053,7 @@ function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=
// Example: The dual of "icosa" features hexagons and always 12 pentagons: // Example: The dual of "icosa" features hexagons and always 12 pentagons:
// color("green")spheroid(r=10.01, $fn=256); // color("green")spheroid(r=10.01, $fn=256);
// spheroid(r=10, style="icosa", circum=true, $fn=16); // spheroid(r=10, style="icosa", circum=true, $fn=16);
module spheroid(r, style="aligned", d, circum=false, dual=false, anchor=CENTER, spin=0, orient=UP) module spheroid(r, style="aligned", d, circum=false, dual=false, anchor=CENTER, spin=0, orient=UP)
{ {
r = get_radius(r=r, d=d, dflt=1); r = get_radius(r=r, d=d, dflt=1);
@ -2194,6 +2364,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
// vnf_polyhedron(torus(d_min=15, od=60), convexity=4); // vnf_polyhedron(torus(d_min=15, od=60), convexity=4);
// Example: Standard Connectors // Example: Standard Connectors
// torus(od=60, id=30) show_anchors(); // torus(od=60, id=30) show_anchors();
module torus( module torus(
r_maj, r_min, center, r_maj, r_min, center,
d_maj, d_min, d_maj, d_min,
@ -2314,6 +2485,7 @@ function torus(
// Example(Spin,VPD=150,Med): Named Conical Connectors // Example(Spin,VPD=150,Med): Named Conical Connectors
// teardrop(d1=20, d2=30, h=20, cap_h1=11, cap_h2=16) // teardrop(d1=20, d2=30, h=20, cap_h1=11, cap_h2=16)
// show_anchors(std=false); // show_anchors(std=false);
module teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, anchor=CENTER, spin=0, orient=UP) module teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, anchor=CENTER, spin=0, orient=UP)
{ {
r1 = get_radius(r=r, r1=r1, d=d, d1=d1, dflt=1); r1 = get_radius(r=r, r1=r1, d=d, d1=d1, dflt=1);
@ -2432,6 +2604,7 @@ function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, anc
// } // }
// Example: Standard Connectors // Example: Standard Connectors
// onion(d=30, ang=30, cap_h=20) show_anchors(); // onion(d=30, ang=30, cap_h=20) show_anchors();
module onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) module onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP)
{ {
r = get_radius(r=r, d=d, dflt=1); r = get_radius(r=r, d=d, dflt=1);
@ -2527,6 +2700,7 @@ function onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) =
// text3d("Foobar", h=2, anchor=CENTER); // text3d("Foobar", h=2, anchor=CENTER);
// text3d("Foobar", h=2, anchor=str("baseline",CENTER)); // text3d("Foobar", h=2, anchor=str("baseline",CENTER));
// text3d("Foobar", h=2, anchor=str("baseline",BOTTOM+RIGHT)); // text3d("Foobar", h=2, anchor=str("baseline",BOTTOM+RIGHT));
module text3d(text, h=1, size=10, font="Helvetica", halign, valign, spacing=1.0, direction="ltr", language="em", script="latin", anchor="baseline[-1,0,-1]", spin=0, orient=UP) { module text3d(text, h=1, size=10, font="Helvetica", halign, valign, spacing=1.0, direction="ltr", language="em", script="latin", anchor="baseline[-1,0,-1]", spin=0, orient=UP) {
no_children($children); no_children($children);
dummy1 = dummy1 =
@ -2721,6 +2895,7 @@ function _cut_interp(pathcut, path, data) =
// color("red")stroke(path, width=.3); // color("red")stroke(path, width=.3);
// kern = [1,1.2,1,1,.3,-.2,1,0,.8,1,1.1,1]; // kern = [1,1.2,1,1,.3,-.2,1,0,.8,1,1.1,1];
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, kern=kern, normal=UP); // path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, kern=kern, normal=UP);
module path_text(path, text, font, size, thickness, lettersize, offset=0, reverse=false, normal, top, center=false, textmetrics=false, kern=0) module path_text(path, text, font, size, thickness, lettersize, offset=0, reverse=false, normal, top, center=false, textmetrics=false, kern=0)
{ {
no_children($children); no_children($children);
@ -2849,6 +3024,7 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
// position(BOT+FRONT) // position(BOT+FRONT)
// interior_fillet(l=50, r=10, spin=180, orient=RIGHT); // interior_fillet(l=50, r=10, spin=180, orient=RIGHT);
// } // }
module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, anchor=CENTER, spin=0, orient=UP) { module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, anchor=CENTER, spin=0, orient=UP) {
r = get_radius(r=r, d=d, dflt=1); r = get_radius(r=r, d=d, dflt=1);
steps = ceil(segs(r)*(180-ang)/360); steps = ceil(segs(r)*(180-ang)/360);
@ -2923,6 +3099,7 @@ module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, anchor=CENTER, spin=0,
// size=[100,100], bottom=-20, data=fn, // size=[100,100], bottom=-20, data=fn,
// xrange=[-180:2:180], yrange=[-180:2:180] // xrange=[-180:2:180], yrange=[-180:2:180]
// ); // );
module heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04:1], yrange=[-1:0.04:1], style="default", convexity=10, anchor=CENTER, spin=0, orient=UP) module heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04:1], yrange=[-1:0.04:1], style="default", convexity=10, anchor=CENTER, spin=0, orient=UP)
{ {
size = is_num(size)? [size,size] : point2d(size); size = is_num(size)? [size,size] : point2d(size);
@ -3057,6 +3234,7 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04
// l=100, r=30, base=5, data=fn, // l=100, r=30, base=5, data=fn,
// xrange=[-180:2:180], yrange=[-180:2:180] // xrange=[-180:2:180], yrange=[-180:2:180]
// ); // );
function cylindrical_heightfield( function cylindrical_heightfield(
data, l, r, base=1, data, l, r, base=1,
transpose=false, aspect=1, transpose=false, aspect=1,
@ -3176,6 +3354,7 @@ module cylindrical_heightfield(
// Example(2D,Big): Metric vs Imperial // Example(2D,Big): Metric vs Imperial
// ruler(12,width=50,inch=true,labels=true,maxscale=0); // ruler(12,width=50,inch=true,labels=true,maxscale=0);
// fwd(50)ruler(300,width=50,labels=true); // fwd(50)ruler(300,width=50,labels=true);
module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3, maxscale, module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3, maxscale,
colors=["black","white"], alpha=1.0, unit=1, inch=false, anchor=LEFT+BACK+TOP, spin=0, orient=UP) colors=["black","white"], alpha=1.0, unit=1, inch=false, anchor=LEFT+BACK+TOP, spin=0, orient=UP)
{ {

813
skin.scad

File diff suppressed because it is too large Load diff

View file

@ -886,6 +886,11 @@ function _slice_3dpolygons(polys, dir, cuts) =
// 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`
// atype = Select "hull" or "intersect" anchor type. Default: "hull" // atype = Select "hull" or "intersect" anchor type. Default: "hull"
// Anchor Types:
// "hull" = Anchors to the virtual convex hull of the shape.
// "intersect" = Anchors to the surface of the shape.
// Extra Anchors:
// "origin" = Anchor at the origin, oriented UP.
module vnf_polyhedron(vnf, convexity=2, extent=true, cp="centroid", anchor="origin", spin=0, orient=UP, atype="hull") { module vnf_polyhedron(vnf, convexity=2, extent=true, cp="centroid", anchor="origin", spin=0, orient=UP, atype="hull") {
vnf = is_vnf_list(vnf)? vnf_join(vnf) : vnf; vnf = is_vnf_list(vnf)? vnf_join(vnf) : vnf;
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\""); assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");