diff --git a/shapes3d.scad b/shapes3d.scad index d4214bb..58f3b0f 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2771,6 +2771,7 @@ module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, anchor=CENTER, spin=0, // heightfield(data, [size], [bottom], [maxz], [xrange], [yrange], [style], [convexity], ...) [ATTACHMENTS]; // Usage: As Function // vnf = heightfield(data, [size], [bottom], [maxz], [xrange], [yrange], [style], ...); +// Topics: Textures, Heightfield // Description: // Given a regular rectangular 2D grid of scalar values, or a function literal, generates a 3D // surface where the height at any given point is the scalar value for that position. @@ -2787,6 +2788,7 @@ module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, anchor=CENTER, spin=0, // 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. See [spin](attachments.scad#subsection-spin). Default: `0` // orient = Vector to rotate top towards. See [orient](attachments.scad#subsection-orient). Default: `UP` +// See Also: heightfield(), cylindrical_heightfield(), textured_revolution(), textured_cylinder(), textured_linear_sweep() // Example: // heightfield(size=[100,100], bottom=-20, data=[ // for (y=[-180:4:180]) [ @@ -2895,6 +2897,7 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04 // vnf = cylindrical_heightfield(data, l, r|d=, [base=], [transpose=], [aspect=]); // Usage: As Module // cylindrical_heightfield(data, l, r|d=, [base=], [transpose=], [aspect=]) [ATTACHMENTS]; +// Topics: Extrusion, Textures, Knurling, Heightfield // Description: // Given a regular rectangular 2D grid of scalar values, or a function literal of signature (x,y), generates // a cylindrical 3D surface where the height at any given point above the radius `r=`, is the scalar value @@ -2904,7 +2907,11 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04 // l = The length of the cylinder to wrap around. // r = The radius of the cylinder to wrap around. // --- +// r1 = The radius of the bottom of the cylinder to wrap around. +// r2 = The radius of the top of the cylinder to wrap around. // d = The diameter of the cylinder to wrap around. +// d1 = The diameter of the bottom of the cylinder to wrap around. +// d2 = The diameter of the top of the cylinder to wrap around. // base = The radius for the bottom of the heightfield object to create. Any heights smaller than this will be truncated to very slightly above this height. Default: -20 // transpose = If true, swaps the radial and length axes of the data. Default: false // aspect = The aspect ratio of the generated heightfield at the surface of the cylinder. Default: 1 @@ -2916,6 +2923,7 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04 // 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. See [spin](attachments.scad#subsection-spin). Default: `0` // orient = Vector to rotate top towards. See [orient](attachments.scad#subsection-orient). Default: `UP` +// See Also: heightfield(), cylindrical_heightfield(), textured_revolution(), textured_cylinder(), textured_linear_sweep() // Example(VPD=400;VPR=[55,0,150]): // cylindrical_heightfield(l=100, r=30, base=5, data=[ // for (y=[-180:4:180]) [ @@ -2923,6 +2931,13 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04 // 5*cos(5*norm([x,y]))+5 // ] // ]); +// Example(VPD=400;VPR=[55,0,150]): +// cylindrical_heightfield(l=100, r1=60, r2=30, base=5, data=[ +// for (y=[-180:4:180]) [ +// for(x=[-180:4:180]) +// 5*cos(5*norm([x,y]))+5 +// ] +// ]); // Example(VPD=400;VPR=[55,0,150]): Heightfield by Function // fn = function (x,y) 5*sin(x*360)*cos(y*360)+5; // cylindrical_heightfield(l=100, r=30, data=fn); @@ -2935,18 +2950,20 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04 function cylindrical_heightfield( data, l, r, base=1, transpose=false, aspect=1, - style="min_edge", + style="min_edge", maxh=99, xrange=[-1:0.01:1], yrange=[-1:0.01:1], - maxh=99, d, h, height, + r1, r2, d, d1, d2, h, height, anchor=CTR, spin=0, orient=UP ) = let( l = first_defined([l, h, height]), - r = get_radius(r=r, d=d) + r1 = get_radius(r1=r1, r=r, d1=d1, d=d), + r2 = get_radius(r1=r2, r=r, d1=d2, d=d) ) assert(is_finite(l) && l>0, "Must supply one of l=, h=, or height= as a finite positive number.") - assert(is_finite(r) && r>0, "Must supply one of r=, or d= as a finite positive number.") + assert(is_finite(r1) && r1>0, "Must supply one of r=, r1=, d=, or d1= as a finite positive number.") + assert(is_finite(r2) && r2>0, "Must supply one of r=, r2=, d=, or d2= as a finite positive number.") assert(is_finite(base) && base>0, "Must supply base= as a finite positive number.") assert(is_matrix(data)||is_function(data), "data= must be a function literal, or contain a 2D array of numbers.") let( @@ -2960,17 +2977,21 @@ function cylindrical_heightfield( ylen = len(yvals), stepy = l / (ylen-1), stepx = stepy * aspect, - circ = 2 * PI * r, + maxr = max(r1,r2), + circ = 2 * PI * maxr, astep = 360 / circ * stepx, arc = astep * xlen, - bsteps = round(segs(r-base) * arc / 360), + bsteps = round(segs(maxr-base) * arc / 360), bstep = arc / bsteps ) - assert(stepx*xlen <= circ, str("heightfield (",xlen," x ",ylen,") needs a radius of at least ",r*stepx*xlen/circ)) + assert(stepx*xlen <= circ, str("heightfield (",xlen," x ",ylen,") needs a radius of at least ",maxr*stepx*xlen/circ)) let( verts = [ - for (yi = idx(yvals)) let( z = yi * stepy - l/2 ) [ - cylindrical_to_xyz(r-base, 0, z), + for (yi = idx(yvals)) let( + z = yi * stepy - l/2, + rr = lerp(r1, r2, yi/(ylen-1)) + ) [ + cylindrical_to_xyz(rr-base, 0, z), for (xi = idx(xvals)) let( a = xi*astep ) let( rad = transpose? ( @@ -2980,14 +3001,14 @@ function cylindrical_heightfield( ), rad2 = constrain(rad, 0.01-base, maxh) ) - cylindrical_to_xyz(r+rad2, a, z), - cylindrical_to_xyz(r-base, arc, z), + cylindrical_to_xyz(rr+rad2, a, z), + cylindrical_to_xyz(rr-base, arc, z), for (b = [1:1:bsteps-1]) let( a = arc-b*bstep ) - cylindrical_to_xyz(r-base, a, l/2*(z>0?1:-1)), + cylindrical_to_xyz((z>0?r2:r1)-base, a, l/2*(z>0?1:-1)), ] ], vnf = vnf_vertex_array(verts, caps=true, col_wrap=true, reverse=true, style=style) - ) reorient(anchor,spin,orient, r=r, l=l, p=vnf); + ) reorient(anchor,spin,orient, r1=r1, r2=r2, l=l, p=vnf); module cylindrical_heightfield( @@ -2995,18 +3016,19 @@ module cylindrical_heightfield( transpose=false, aspect=1, style="min_edge", convexity=10, xrange=[-1:0.01:1], yrange=[-1:0.01:1], - maxh=99, d, h, height, + maxh=99, r1, r2, d, d1, d2, h, height, anchor=CTR, spin=0, orient=UP ) { l = first_defined([l, h, height]); - r = get_radius(r=r, d=d); + r1 = get_radius(r1=r1, r=r, d1=d1, d=d); + r2 = get_radius(r1=r2, r=r, d1=d2, d=d); vnf = cylindrical_heightfield( - data, l=l, r=r, base=base, + data, l=l, r1=r1, r2=r2, base=base, xrange=xrange, yrange=yrange, maxh=maxh, transpose=transpose, aspect=aspect, style=style ); - attachable(anchor,spin,orient, r=r, l=l) { + attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) { vnf_polyhedron(vnf, convexity=convexity); children(); } diff --git a/skin.scad b/skin.scad index 84b1f57..8bd06db 100644 --- a/skin.scad +++ b/skin.scad @@ -2161,7 +2161,7 @@ function _get_texture(tex,n,m) = // centroid_top = The centroid of the top of the shape, oriented UP. // centroid = The centroid of the center of the shape, oriented UP. // centroid_bot = The centroid of the bottom of the shape, oriented DOWN. -// See Also: textured_revolution(), textured_cylinder() +// See Also: textured_revolution(), textured_cylinder(), textured_linear_sweep(), heightfield(), cylindrical_heightfield() // Example: "ribs" texture. // path = glued_circles(r=15, spread=40, tangent=45); // textured_linear_sweep(path, h=40, "ribs", tex_size=[3,5]); @@ -2349,7 +2349,7 @@ module textured_linear_sweep( // "waves" = A raised sine-wave patten, oriented vertically. // "dots" = Raised small round bumps. // "cones" = Raised conical spikes. -// See Also: textured_linear_sweep(), textured_cylinder() +// See Also: textured_revolution(), textured_cylinder(), textured_linear_sweep(), heightfield(), cylindrical_heightfield() // Example: // include // bezpath = [ @@ -2494,7 +2494,7 @@ module textured_revolution( // "waves" = A raised sine-wave patten, oriented vertically. // "dots" = Raised small round bumps. // "cones" = Raised conical spikes. -// See Also: textured_linear_sweep(), textured_revolution() +// See Also: textured_revolution(), textured_cylinder(), textured_linear_sweep(), heightfield(), cylindrical_heightfield() // Examples: // textured_cylinder(h=40, r=20, texture="diamonds", tex_size=[5,5]); // textured_cylinder(h=40, r1=20, r2=15, texture="pyramids", tex_size=[5,5], style="convex");