Added taper= to textured_revolution()

This commit is contained in:
Garth Minette 2022-07-20 22:49:53 -07:00
parent 7e5543de78
commit f999a8af67

159
skin.scad
View file

@ -2133,12 +2133,13 @@ function associate_vertices(polygons, split, curpoly=0) =
// "vnf_hex_grid" = `inset` = A hexagonal grid of thin lines. // "vnf_hex_grid" = `inset` = A hexagonal grid of thin lines.
// "vnf_pyramids" = none = Like "pyramids", but slower and more consistent in triangulation. // "vnf_pyramids" = none = Like "pyramids", but slower and more consistent in triangulation.
// "vnf_trunc_pyramids" = `inset` = Like "trunc_pyramids", but slower and more consistent in triangulation. // "vnf_trunc_pyramids" = `inset` = Like "trunc_pyramids", but slower and more consistent in triangulation.
// "vnf_trunc_ribs" = `inset`, `gap` = Like "trunc_ribs", but slower and more adjustable.
// Arguments: // Arguments:
// tex = The name of the texture to get. // tex = The name of the texture to get.
// --- // ---
// n = The general number of vertices to use to refine the resolution of the texture. // n = The general number of vertices to use to refine the resolution of the texture.
// inset = The amount to inset part of a VNF tile texture. Generally between 0 and 0.5. // inset = The amount to inset part of a VNF tile texture. Generally between 0 and 0.5.
// gap = The gap between some parts of a VNF tile. (ie: gap between bricks, etc.) // gap = The gap between logically distinct parts of a VNF tile. (ie: gap between bricks, gap between truncated ribs, etc.)
// roughness = The amount of roughness used on the surface of some heightfield textures. Generally between 0 and 0.5. // roughness = The amount of roughness used on the surface of some heightfield textures. Generally between 0 and 0.5.
// See Also: textured_revolution(), textured_cylinder(), textured_linear_sweep(), heightfield(), cylindrical_heightfield(), texture() // See Also: textured_revolution(), textured_cylinder(), textured_linear_sweep(), heightfield(), cylindrical_heightfield(), texture()
// Example(3D): "ribs" texture. // Example(3D): "ribs" texture.
@ -2153,6 +2154,12 @@ function associate_vertices(polygons, split, curpoly=0) =
// rect(50), tex, h=40, tscale=3, // rect(50), tex, h=40, tscale=3,
// tex_size=[10,10], style="concave" // tex_size=[10,10], style="concave"
// ); // );
// Example(3D): "vnf_trunc_ribs" texture. Slower, but more controllable.
// tex = texture("vnf_trunc_ribs", gap=0.25, inset=0.333);
// textured_linear_sweep(
// rect(50), tex, h=40, tscale=3,
// tex_size=[10,10]
// );
// Example(3D): "wave_ribs" texture. // Example(3D): "wave_ribs" texture.
// tex = texture("wave_ribs"); // tex = texture("wave_ribs");
// textured_linear_sweep( // textured_linear_sweep(
@ -2273,6 +2280,26 @@ function texture(tex, n, inset, gap, roughness) =
each repeat(1,n/4), each repeat(1,n/4),
each lerpn(1,0,n/4,endpoint=false), each lerpn(1,0,n/4,endpoint=false),
]] : ]] :
tex=="vnf_trunc_ribs"?
let(
inset = default(inset,1/2),
gap = default(gap,1/4)
)
assert(inset >= 0)
assert(gap >= 0)
assert(gap+inset > 0)
assert(gap+inset <= 1)
[
[
each move([0.5,0.5], p=path3d(rect([1-gap,1]),0)),
each move([0.5,0.5], p=path3d(rect([1-gap-inset,1]),1)),
each path3d(square(1)),
], [
[1,2,6], [1,6,5], [0,4,3], [3,4,7],
if (gap+inset < 1-EPSILON) each [[4,5,6], [4,6,7]],
if (gap > EPSILON) each [[1,9,10], [1,10,2], [0,3,8], [3,11,8]],
]
] :
tex=="wave_ribs"? tex=="wave_ribs"?
let( let(
n = max(6,default(n,8)) n = max(6,default(n,8))
@ -2871,11 +2898,11 @@ function _find_vnf_tile_edge_path(vnf, val) =
// Function&Module: textured_revolution() // Function&Module: textured_revolution()
// Usage: As Function // Usage: As Function
// vnf = textured_revolution(region, texture, tex_size, [tscale=], ...); // vnf = textured_revolution(shape, texture, tex_size, [tscale=], ...);
// vnf = textured_revolution(region, texture, counts=, [tscale=], ...); // vnf = textured_revolution(shape, texture, counts=, [tscale=], ...);
// Usage: As Module // Usage: As Module
// textured_revolution(region, texture, tex_size, [tscale=], ...) [ATTACHMENTS]; // textured_revolution(shape, texture, tex_size, [tscale=], ...) [ATTACHMENTS];
// textured_revolution(region, texture, counts=, [tscale=], ...) [ATTACHMENTS]; // textured_revolution(shape, texture, counts=, [tscale=], ...) [ATTACHMENTS];
// Topics: Sweep, Extrusion, Textures, Knurling // Topics: Sweep, Extrusion, Textures, Knurling
// Description: // Description:
// Given a 2D region or path, fully in the X+ half-plane, revolves that shape around the Z axis (after rotating its Y+ to Z+). // Given a 2D region or path, fully in the X+ half-plane, revolves that shape around the Z axis (after rotating its Y+ to Z+).
@ -2898,6 +2925,7 @@ function _find_vnf_tile_edge_path(vnf, val) =
// rot = If true, rotates the texture 90º. // rot = If true, rotates the texture 90º.
// shift = [X,Y] amount to translate the top, relative to the bottom. Default: [0,0] // shift = [X,Y] amount to translate the top, relative to the bottom. Default: [0,0]
// closed = If false, and shape is given as a path, then the revolved path will be sealed to the axis of rotation with untextured caps. Default: `true` // closed = If false, and shape is given as a path, then the revolved path will be sealed to the axis of rotation with untextured caps. Default: `true`
// taper = If given, and `closed=false`, tapers the texture height to zero over the first and last given percentage of the path. Default: `undef` (no taper)
// angle = The number of degrees counter-clockwise from X+ to revolve around the Z axis. Default: `360` // angle = The number of degrees counter-clockwise from X+ to revolve around the Z axis. Default: `360`
// style = The triangulation style used. See {{vnf_vertex_array()}} for valid styles. Used only with heightfield type textures. Default: `"min_edge"` // style = The triangulation style used. See {{vnf_vertex_array()}} for valid styles. Used only with heightfield type textures. Default: `"min_edge"`
// counts = If given instead of tex_size, gives the tile repetition counts for textures over the surface length and height. // counts = If given instead of tex_size, gives the tile repetition counts for textures over the surface length and height.
@ -2953,8 +2981,8 @@ function _find_vnf_tile_edge_path(vnf, val) =
function textured_revolution( function textured_revolution(
shape, texture, tex_size, tscale=1, shape, texture, tex_size, tscale=1,
inset=false, rot=false, inset=false, rot=false, shift=[0,0],
shift=[0,0], closed=true, angle=360, taper, closed=true, angle=360,
style="min_edge", counts, samples style="min_edge", counts, samples
) = ) =
assert(angle>0 && angle<=360) assert(angle>0 && angle<=360)
@ -2964,6 +2992,7 @@ function textured_revolution(
assert(counts==undef || is_vector(counts,2)) assert(counts==undef || is_vector(counts,2))
assert(tex_size==undef || is_vector(tex_size,2)) assert(tex_size==undef || is_vector(tex_size,2))
assert(is_bool(rot) || in_list(rot,[0,90,180,270])) assert(is_bool(rot) || in_list(rot,[0,90,180,270]))
assert(is_undef(taper) || (is_finite(taper) && taper>=0 && taper<50))
let( let(
regions = !is_path(shape,2)? region_parts(shape) : regions = !is_path(shape,2)? region_parts(shape) :
shape[0].y <= last(shape).y? [[reverse(shape)]] : shape[0].y <= last(shape).y? [[reverse(shape)]] :
@ -3037,6 +3066,8 @@ function textured_revolution(
is_vector(tex_size,2) is_vector(tex_size,2)
? max(1,round(angle/360*circumf/tex_size.x)) ? max(1,round(angle/360*circumf/tex_size.x))
: ceil(6*angle/360*circumf/h), : ceil(6*angle/360*circumf/h),
taper_lup = is_undef(taper)? [[-1,1],[2,1]] :
[[-1,0], [0,0], [taper/100+EPSILON,1], [1-taper/100-EPSILON,1], [1,0], [2,0]],
full_vnf = vnf_join([ full_vnf = vnf_join([
for (rgn = regions) let( for (rgn = regions) let(
rgn_wall_vnf = vnf_join([ rgn_wall_vnf = vnf_join([
@ -3060,13 +3091,9 @@ function textured_revolution(
part = (j + (1-vert.y)) * samples, part = (j + (1-vert.y)) * samples,
u = floor(part), u = floor(part),
uu = part - u, uu = part - u,
tscale =
closed? tscale :
!closed && j==0 && approx(vert.y,1)? 0 :
!closed && j==counts_y-1 && approx(vert.y,0)? 0 :
tscale,
base = lerp(select(bases,u), select(bases,u+1), uu), base = lerp(select(bases,u), select(bases,u+1), uu),
norm = unit(lerp(select(norms,u), select(norms,u+1), uu)), norm = unit(lerp(select(norms,u), select(norms,u+1), uu)),
tscale = tscale * lookup(part/samples/counts_y, taper_lup),
texh = (vert.z - inset) * tscale * (base.x / maxx), texh = (vert.z - inset) * tscale * (base.x / maxx),
xyz = base - norm * texh xyz = base - norm * texh
) zrot(vert.x*angle/counts_x, p=xyz) ) zrot(vert.x*angle/counts_x, p=xyz)
@ -3090,13 +3117,9 @@ function textured_revolution(
part = (i + (ti/texcnt.y)) * samples, part = (i + (ti/texcnt.y)) * samples,
u = floor(part), u = floor(part),
uu = part - u, uu = part - u,
tscale =
closed? tscale :
!closed && i==0 && ti==0? 0 :
!closed && i==counts_y && ti==0? 0 :
tscale,
base = lerp(bases[u], select(bases,u+1), uu), base = lerp(bases[u], select(bases,u+1), uu),
norm = unit(lerp(norms[u], select(norms,u+1), uu)), norm = unit(lerp(norms[u], select(norms,u+1), uu)),
tscale = tscale * lookup(part/samples/counts_y, taper_lup),
texh = (texture[ti][tj] - inset) * tscale * (base.x / maxx), texh = (texture[ti][tj] - inset) * tscale * (base.x / maxx),
xyz = base - norm * texh xyz = base - norm * texh
) xyz ) xyz
@ -3131,13 +3154,9 @@ function textured_revolution(
part = (j + vert.y) * samples, part = (j + vert.y) * samples,
u = floor(part), u = floor(part),
uu = part - u, uu = part - u,
tscale =
closed? tscale :
!closed && j==0 && approx(vert.y,0)? 0 :
!closed && j==counts_y-1 && approx(vert.y,1)? 0 :
tscale,
base = lerp(select(bases,u), select(bases,u+1), uu), base = lerp(select(bases,u), select(bases,u+1), uu),
norm = unit(lerp(select(norms,u), select(norms,u+1), uu)), norm = unit(lerp(select(norms,u), select(norms,u+1), uu)),
tscale = tscale * lookup(part/samples/counts_y, taper_lup),
texh = (vert.z - inset) * tscale * (base.x / maxx), texh = (vert.z - inset) * tscale * (base.x / maxx),
xyz = base - norm * texh xyz = base - norm * texh
) xyz ) xyz
@ -3151,13 +3170,9 @@ function textured_revolution(
part = (i + (ti/texcnt.y)) * samples, part = (i + (ti/texcnt.y)) * samples,
u = floor(part), u = floor(part),
uu = part - u, uu = part - u,
tscale =
closed? tscale :
!closed && i==0 && ti==0? 0 :
!closed && i==counts_y && ti==0? 0 :
tscale,
base = lerp(bases[u], select(bases,u+1), uu), base = lerp(bases[u], select(bases,u+1), uu),
norm = unit(lerp(norms[u], select(norms,u+1), uu)), norm = unit(lerp(norms[u], select(norms,u+1), uu)),
tscale = tscale * lookup(part/samples/counts_y, taper_lup),
texh = (texture[ti][0] - inset) * tscale * (base.x / maxx), texh = (texture[ti][0] - inset) * tscale * (base.x / maxx),
xyz = base - norm * texh xyz = base - norm * texh
) xyz ) xyz
@ -3172,37 +3187,50 @@ function textured_revolution(
vnf2 = vnf_from_region(cap_rgn, xrot(90), reverse=false), vnf2 = vnf_from_region(cap_rgn, xrot(90), reverse=false),
vnf3 = vnf_from_region(cap_rgn, rot([90,0,angle]), reverse=true) vnf3 = vnf_from_region(cap_rgn, rot([90,0,angle]), reverse=true)
) vnf_join([vnf2, vnf3]), ) vnf_join([vnf2, vnf3]),
topcap_vnf = closed? EMPTY_VNF : allcaps_vnf = closed? EMPTY_VNF :
let( let(
pt = last(rgn[0]), plen = path_length(rgn[0], closed=closed),
top_rgn = [ counts_y = is_vector(counts,2)? counts.y :
for (path = rgn) let( is_vector(tex_size,2)? max(1,round(plen/tex_size.y)) : 6,
obases = resample_path(rgn[0], n=counts_y * samples + (closed?0:1), closed=closed),
onorms = path_normals(obases, closed=closed),
rbases = closed? close_path(obases) : obases,
rnorms = closed? close_path(onorms) : onorms,
bases = xrot(90, p=path3d(rbases)),
norms = xrot(90, p=path3d(rnorms)),
caps_vnf = vnf_join([
for (j = [-1,0]) let(
base = select(bases,j),
norm = unit(select(norms,j)),
ppath = [ ppath = [
for (j = [0:1:counts_x-1], vert = tpath) let( for (vert = tpath) let(
u = (j + vert.x) / counts_x uang = vert.x / counts_x,
) tscale = tscale * lookup([0,1][j+1], taper_lup),
polar_to_xy(pt.x, angle*u) texh = (vert.y - inset) * tscale * (base.x / maxx),
], xyz = base - norm * texh
path = closed? ppath : concat(ppath, [[0,0]]) ) zrot(angle*uang, p=xyz)
) deduplicate(path, closed=closed) ],
] pplen = len(ppath),
) vnf_from_region(top_rgn, up(pt.y), reverse=true), zed = j<0? max(column(ppath,2)) :
botcap_vnf = closed? EMPTY_VNF : min(column(ppath,2)),
let( slice_vnf = [
pt = rgn[0][0], [
bot_rgn = [ each ppath,
for (path = rgn) let( [0, 0, zed],
ppath = [ ], [
for (j = [0:1:counts_x-1], vert = bpath) let( for (i = [0:1:pplen-2])
u = (j + vert.x) / counts_x j<0? [pplen, i, (i+1)%pplen] :
) [pplen, (i+1)%pplen, i]
polar_to_xy(pt.x, angle*u) ]
], ],
path = closed? ppath : concat(ppath, [[0,0]]) cap_vnf = vnf_join([
) deduplicate(path, closed=closed) for (i = [0:1:counts_x-1])
] zrot(i*angle/counts_x, p=slice_vnf)
) vnf_from_region(bot_rgn, up(pt.y), reverse=false) ])
) vnf_join([walls_vnf, endcap_vnf, botcap_vnf, topcap_vnf]) ) cap_vnf
])
) caps_vnf
) vnf_join([walls_vnf, endcap_vnf, allcaps_vnf])
]), ]),
skmat = down(-miny) * skew(sxz=shift.x/h, syz=shift.y/h) * up(-miny) skmat = down(-miny) * skew(sxz=shift.x/h, syz=shift.y/h) * up(-miny)
) apply(skmat, full_vnf); ) apply(skmat, full_vnf);
@ -3211,7 +3239,7 @@ function textured_revolution(
module textured_revolution( module textured_revolution(
shape, texture, tex_size, tscale=1, shape, texture, tex_size, tscale=1,
inset=false, rot=false, shift=[0,0], inset=false, rot=false, shift=[0,0],
closed=true, angle=360, taper, closed=true, angle=360,
style="min_edge", atype="surface", style="min_edge", atype="surface",
convexity=10, counts, samples, convexity=10, counts, samples,
anchor=CENTER, spin=0, orient=UP anchor=CENTER, spin=0, orient=UP
@ -3220,7 +3248,7 @@ module textured_revolution(
vnf = textured_revolution( vnf = textured_revolution(
shape, texture, tex_size=tex_size, shape, texture, tex_size=tex_size,
tscale=tscale, inset=inset, rot=rot, tscale=tscale, inset=inset, rot=rot,
closed=closed, style=style, taper=taper, closed=closed, style=style,
shift=shift, angle=angle, shift=shift, angle=angle,
samples=samples, counts=counts samples=samples, counts=counts
); );
@ -3269,6 +3297,7 @@ module textured_revolution(
// caps = (function only) If true, create endcaps for the extruded shape. Default: `true` // caps = (function only) If true, create endcaps for the extruded shape. Default: `true`
// shift = [X,Y] amount to translate the top, relative to the bottom. Default: [0,0] // shift = [X,Y] amount to translate the top, relative to the bottom. Default: [0,0]
// style = The triangulation style used. See {{vnf_vertex_array()}} for valid styles. Default: `"min_edge"` // style = The triangulation style used. See {{vnf_vertex_array()}} for valid styles. Default: `"min_edge"`
// taper = If given, tapers the texture height to zero over the given percentage of the top and bottom of the cylinder face. Default: `undef` (no taper)
// counts = If given instead of tex_size, gives the tile repetition counts for textures over the surface length and height. // counts = If given instead of tex_size, gives the tile repetition counts for textures over the surface length and height.
// chamfer = If given, chamfers the top and bottom of the cylinder by the given size. If given a negative size, creates a chamfer that juts *outward* from the cylinder. // chamfer = If given, chamfers the top and bottom of the cylinder by the given size. If given a negative size, creates a chamfer that juts *outward* from the cylinder.
// chamfer1 = If given, chamfers the bottom of the cylinder by the given size. If given a negative size, creates a chamfer that juts *outward* from the cylinder. // chamfer1 = If given, chamfers the bottom of the cylinder by the given size. If given a negative size, creates a chamfer that juts *outward* from the cylinder.
@ -3287,11 +3316,17 @@ module textured_revolution(
// textured_cylinder(h=40, r1=20, r2=15, texture="trunc_pyramids", tex_size=[5,5], chamfer=5, style="convex"); // textured_cylinder(h=40, r1=20, r2=15, texture="trunc_pyramids", tex_size=[5,5], chamfer=5, style="convex");
// textured_cylinder(h=40, r1=20, r2=15, texture="vnf_dots", tex_size=[5,5], rounding=9, samples=6); // textured_cylinder(h=40, r1=20, r2=15, texture="vnf_dots", tex_size=[5,5], rounding=9, samples=6);
// textured_cylinder(h=50, r1=25, r2=20, shift=[0,10], texture="bricks", rounding1=-10, tex_size=[10,10], tscale=0.5, style="concave"); // textured_cylinder(h=50, r1=25, r2=20, shift=[0,10], texture="bricks", rounding1=-10, tex_size=[10,10], tscale=0.5, style="concave");
// Example: No Texture Taper
// textured_cylinder(d1=25, d2=20, h=30, rounding=5, texture="trunc_ribs", tex_size=[5,1]);
// Example: Taper Texure at Extreme Ends
// textured_cylinder(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%
// textured_cylinder(d1=25, d2=20, h=30, rounding=5, texture="trunc_ribs", taper=10, tex_size=[5,1]);
function textured_cylinder( function textured_cylinder(
h, r, texture, tex_size=[1,1], counts, h, r, texture, tex_size=[1,1], counts,
tscale=1, inset=false, rot=false, tscale=1, inset=false, rot=false,
caps=true, style="min_edge", caps=true, style="min_edge", taper,
shift=[0,0], l, r1, r2, d, d1, d2, shift=[0,0], l, r1, r2, d, d1, d2,
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
rounding, rounding1, rounding2, rounding, rounding1, rounding2,
@ -3324,7 +3359,7 @@ function textured_cylinder(
reverse(path), texture, closed=false, reverse(path), texture, closed=false,
tex_size=tex_size, counts=counts, tex_size=tex_size, counts=counts,
tscale=tscale, inset=inset, rot=rot, tscale=tscale, inset=inset, rot=rot,
style=style, shift=shift, style=style, shift=shift, taper=taper,
samples=samples samples=samples
) )
) vnf; ) vnf;
@ -3333,7 +3368,7 @@ function textured_cylinder(
module textured_cylinder( module textured_cylinder(
h, r, texture, tex_size=[1,1], h, r, texture, tex_size=[1,1],
counts, tscale=1, inset=false, rot=false, counts, tscale=1, inset=false, rot=false,
style="min_edge", shift=[0,0], style="min_edge", shift=[0,0], taper,
l, r1, r2, d, d1, d2, l, r1, r2, d, d1, d2,
chamfer, chamfer1, chamfer2, chamfer, chamfer1, chamfer2,
rounding, rounding1, rounding2, rounding, rounding1, rounding2,
@ -3351,7 +3386,7 @@ module textured_cylinder(
texture=texture, h=h, r1=r1, r2=r2, texture=texture, h=h, r1=r1, r2=r2,
tscale=tscale, inset=inset, rot=rot, tscale=tscale, inset=inset, rot=rot,
counts=counts, tex_size=tex_size, counts=counts, tex_size=tex_size,
caps=true, style=style, caps=true, style=style, taper=taper,
shift=shift, samples=samples, shift=shift, samples=samples,
chamfer1=chamf1, chamfer2=chamf2, chamfer1=chamf1, chamfer2=chamf2,
rounding1=round1, rounding2=round2 rounding1=round1, rounding2=round2