diff --git a/README.md b/README.md index 882fef7..48afb79 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ For purposes of the BOSL2 library, the following terms apply: ## Common Arguments: -Args | What it is -------- | ---------------------------------------- -fillet | Radius of rounding for interior or exterior edges. -chamfer | Size of chamfers/bevels for interior or exterior edges. -orient | Axis a part should be oriented along. Given as an XYZ triplet of rotation angles. It is recommended that you use the `ORIENT_` constants from `constants.scad`. Default is usually `ORIENT_Z` for vertical orientation. -anchor | Side of the object that should be anchored to the origin. Given as a vector towards the side of the part to align with the origin. It is recommended that you use the directional constants from `constants.scad`. Default is usually `CENTER` for centered. +Args | What it is +-------- | ---------------------------------------- +rounding | Radius of rounding for interior or exterior edges. +chamfer | Size of chamfers/bevels for interior or exterior edges. +orient | Axis a part should be oriented along. Given as an XYZ triplet of rotation angles. It is recommended that you use the `ORIENT_` constants from `constants.scad`. Default is usually `ORIENT_Z` for vertical orientation. +anchor | Side of the object that should be anchored to the origin. Given as a vector towards the side of the part to align with the origin. It is recommended that you use the directional constants from `constants.scad`. Default is usually `CENTER` for centered. ## Examples @@ -85,6 +85,7 @@ The library files are as follows: - [`vectors.scad`](https://github.com/revarbat/BOSL2/wiki/vectors.scad): Vector math functions. - [`matrices.scad`](https://github.com/revarbat/BOSL2/wiki/matrices.scad): Matrix math and affine transformation functions. - [`coords.scad`](https://github.com/revarbat/BOSL2/wiki/coords.scad): Coordinate system conversions and point transformations. + - [`geometry.scad`](https://github.com/revarbat/BOSL2/wiki/geometry.scad): Functions to calculate various geometry. - [`quaternions.scad`](https://github.com/revarbat/BOSL2/wiki/quaternions.scad): Functions to work with quaternion rotations. - [`convex_hull.scad`](https://github.com/revarbat/BOSL2/wiki/convex_hull.scad): Functions to generate 2D and 3D hulls of points. - [`triangulation.scad`](https://github.com/revarbat/BOSL2/wiki/triangulation.scad): Functions to triangulate `polyhedron()` faces. diff --git a/attachments.scad b/attachments.scad index 5af3881..1911d1b 100644 --- a/attachments.scad +++ b/attachments.scad @@ -106,6 +106,7 @@ function find_anchor(anchor, h, size, size2=undef, shift=[0,0], extra_anchors=[] two_d? sidevec : anchor==CENTER? UP : norm([anchor.x,anchor.y]) < EPSILON? anchor : + norm(size)+norm(size2) < EPSILON? anchor : abs(anchor.z) < EPSILON? sidevec : anchor.z>0? (UP+sidevec)/2 : (DOWN+sidevec)/2 @@ -162,6 +163,7 @@ function _str_char_split(s,delim,n=0,acc=[],word="") = // `$parent_orient` is set to the parent object's `orient` value. // `$parent_anchor` is set to the parent object's `anchor` value. // `$parent_anchors` is set to the parent object's list of non-standard extra anchors. +// `$parent_2d` is set to the parent object's `two_d` value. // // Example: // #cylinder(d=5, h=10); @@ -248,14 +250,14 @@ module orient_and_anchor( // Attaches children to a parent object at an anchor point and orientation. // Arguments: // name = The name of the parent anchor point to attach to. -// to = The name of the child anchor point. -// overlap = Amount to sink child into the parent. -// norot = If true, don't rotate children when attaching to the anchor point. +// to = Optional name of the child anchor point. If given, orients the child such that the named anchors align together rotationally. +// overlap = Amount to sink child into the parent. Equivalent to `down(X)` after the attach. +// norot = If true, don't rotate children when attaching to the anchor point. Only translate to the anchor point. // Example: // spheroid(d=20) { -// attach(TOP) down(1.5) cyl(l=11.5, d1=10, d2=5, anchor=BOTTOM); +// attach(TOP) down(1.5) cyl(l=11.5, d1=10, d2=5, anchor=BOTTOM); // attach(RIGHT, BOTTOM) down(1.5) cyl(l=11.5, d1=10, d2=5); -// attach(FRONT) down(1.5) cyl(l=11.5, d1=10, d2=5, anchor=BOTTOM); +// attach(FRONT, BOTTOM, overlap=1.5) cyl(l=11.5, d1=10, d2=5); // } module attach(name, to=undef, overlap=undef, norot=false) { @@ -296,6 +298,8 @@ module tags(tags) // recolor(c) ... // Description: // Sets the color for children that can use the $color special variable. +// Arguments: +// c = Color name or RGBA vector. // Example: // recolor("red") cyl(l=20, d=10); module recolor(c) @@ -308,7 +312,13 @@ module recolor(c) // Module: hide() // Usage: // hide(tags) ... -// Description: Hides all children with the given tags. +// Description: +// Hides all children with the given tags. +// Example: +// hide("A") cube(50, anchor=CENTER, $tags="Main") { +// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A"); +// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B"); +// } module hide(tags="") { $tags_hidden = tags==""? [] : _str_char_split(tags, " "); @@ -319,7 +329,13 @@ module hide(tags="") // Module: show() // Usage: // show(tags) ... -// Description: Shows only children with the given tags. +// Description: +// Shows only children with the given tags. +// Example: +// show("A B") cube(50, anchor=CENTER, $tags="Main") { +// attach(LEFT, BOTTOM) cylinder(d=30, l=30, $tags="A"); +// attach(RIGHT, BOTTOM) cylinder(d=30, l=30, $tags="B"); +// } module show(tags="") { $tags_shown = tags==""? [] : _str_char_split(tags, " "); @@ -343,6 +359,12 @@ module show(tags="") // neg = String containing space delimited set of tag names of children to difference away. // pos = String containing space delimited set of tag names of children to be differenced away from. // keep = String containing space delimited set of tag names of children to keep whole. +// Example: +// diff("neg", "pos", keep="axle") +// sphere(d=100, $tags="pos") { +// attach(CENTER) xcyl(d=40, h=120, $tags="axle"); +// attach(CENTER) cube([40,120,100], anchor=CENTER, $tags="neg"); +// } module diff(neg, pos=undef, keep=undef) { difference() { @@ -382,6 +404,12 @@ module diff(neg, pos=undef, keep=undef) // a = String containing space delimited set of tag names of children. // b = String containing space delimited set of tag names of children. // keep = String containing space delimited set of tag names of children to keep whole. +// Example: +// intersect("wheel", "mask", keep="axle") +// sphere(d=100, $tags="wheel") { +// attach(CENTER) cube([40,100,100], anchor=CENTER, $tags="mask"); +// attach(CENTER) xcyl(d=40, h=100, $tags="axle"); +// } module intersect(a, b=undef, keep=undef) { intersection() { diff --git a/examples/attachments.scad b/examples/attachments.scad index 8a3c1f3..f208b20 100644 --- a/examples/attachments.scad +++ b/examples/attachments.scad @@ -2,7 +2,7 @@ include $fn=32; -cuboid([60,40,40], fillet=5, edges=EDGES_Z_ALL, anchor=BOTTOM) { +cuboid([60,40,40], rounding=5, edges=EDGES_Z_ALL, anchor=BOTTOM) { attach(TOP, BOTTOM) rounded_prismoid([60,40],[20,20], h=50, r1=5, r2=10) { attach(TOP) cylinder(d=20, h=30) { attach(TOP) cylinder(d1=50, d2=30, h=12); diff --git a/shapes.scad b/shapes.scad index 4233f7e..67521c7 100644 --- a/shapes.scad +++ b/shapes.scad @@ -1108,520 +1108,6 @@ module onion(cap_h=undef, r=undef, d=undef, maxang=45, h=undef, orient=ORIENT_Z, } -// Module: narrowing_strut() -// -// Description: -// Makes a rectangular strut with the top side narrowing in a triangle. -// The shape created may be likened to an extruded home plate from baseball. -// This is useful for constructing parts that minimize the need to support -// overhangs. -// -// Usage: -// narrowing_strut(w, l, wall, [ang], [orient], [anchor]); -// -// Arguments: -// w = Width (thickness) of the strut. -// l = Length of the strut. -// wall = height of rectangular portion of the strut. -// ang = angle that the trianglar side will converge at. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `FRONT`. -// -// Example: -// narrowing_strut(w=10, l=100, wall=5, ang=30); -module narrowing_strut(w=10, l=100, wall=5, ang=30, orient=ORIENT_Y, anchor=FRONT) -{ - h = wall + w/2/tan(ang); - size = [w, h, l]; - orient_and_anchor(size, orient, anchor, chain=true) { - fwd(h/2) { - linear_extrude(height=l, center=true, slices=2) { - back(wall/2) square([w, wall], center=true); - back(wall-0.001) { - yscale(1/tan(ang)) { - difference() { - zrot(45) square(w/sqrt(2), center=true); - fwd(w/2) square(w, center=true); - } - } - } - } - } - children(); - } -} - - -// Module: thinning_wall() -// -// Description: -// Makes a rectangular wall which thins to a smaller width in the center, -// with angled supports to prevent critical overhangs. -// -// Usage: -// thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [anchor]); -// -// Arguments: -// h = height of wall. -// l = length of wall. If given as a vector of two numbers, specifies bottom and top lengths, respectively. -// thick = thickness of wall. -// ang = maximum overhang angle of diagonal brace. -// strut = the width of the diagonal brace. -// wall = the thickness of the thinned portion of the wall. -// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// -// Example: Typical Shape -// thinning_wall(h=50, l=80, thick=4); -// Example: Trapezoidal -// thinning_wall(h=50, l=[80,50], thick=4); -module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Z, anchor=CENTER) -{ - l1 = (l[0] == undef)? l : l[0]; - l2 = (l[1] == undef)? l : l[1]; - - trap_ang = atan2((l2-l1)/2, h); - corr1 = 1 + sin(trap_ang); - corr2 = 1 - sin(trap_ang); - - z1 = h/2; - z2 = max(0.1, z1 - strut); - z3 = max(0.05, z2 - (thick-wall)/2*sin(90-ang)/sin(ang)); - - x1 = l2/2; - x2 = max(0.1, x1 - strut*corr1); - x3 = max(0.05, x2 - (thick-wall)/2*sin(90-ang)/sin(ang)*corr1); - x4 = l1/2; - x5 = max(0.1, x4 - strut*corr2); - x6 = max(0.05, x5 - (thick-wall)/2*sin(90-ang)/sin(ang)*corr2); - - y1 = thick/2; - y2 = y1 - min(z2-z3, x2-x3) * sin(ang); - - size = [l1, thick, h]; - orient_and_anchor(size, orient, anchor, size2=[l2,thick], chain=true) { - polyhedron( - points=[ - [-x4, -y1, -z1], - [ x4, -y1, -z1], - [ x1, -y1, z1], - [-x1, -y1, z1], - - [-x5, -y1, -z2], - [ x5, -y1, -z2], - [ x2, -y1, z2], - [-x2, -y1, z2], - - [-x6, -y2, -z3], - [ x6, -y2, -z3], - [ x3, -y2, z3], - [-x3, -y2, z3], - - [-x4, y1, -z1], - [ x4, y1, -z1], - [ x1, y1, z1], - [-x1, y1, z1], - - [-x5, y1, -z2], - [ x5, y1, -z2], - [ x2, y1, z2], - [-x2, y1, z2], - - [-x6, y2, -z3], - [ x6, y2, -z3], - [ x3, y2, z3], - [-x3, y2, z3], - ], - faces=[ - [ 4, 5, 1], - [ 5, 6, 2], - [ 6, 7, 3], - [ 7, 4, 0], - - [ 4, 1, 0], - [ 5, 2, 1], - [ 6, 3, 2], - [ 7, 0, 3], - - [ 8, 9, 5], - [ 9, 10, 6], - [10, 11, 7], - [11, 8, 4], - - [ 8, 5, 4], - [ 9, 6, 5], - [10, 7, 6], - [11, 4, 7], - - [11, 10, 9], - [20, 21, 22], - - [11, 9, 8], - [20, 22, 23], - - [16, 17, 21], - [17, 18, 22], - [18, 19, 23], - [19, 16, 20], - - [16, 21, 20], - [17, 22, 21], - [18, 23, 22], - [19, 20, 23], - - [12, 13, 17], - [13, 14, 18], - [14, 15, 19], - [15, 12, 16], - - [12, 17, 16], - [13, 18, 17], - [14, 19, 18], - [15, 16, 19], - - [ 0, 1, 13], - [ 1, 2, 14], - [ 2, 3, 15], - [ 3, 0, 12], - - [ 0, 13, 12], - [ 1, 14, 13], - [ 2, 15, 14], - [ 3, 12, 15], - ], - convexity=6 - ); - children(); - } -} - - -// Module: braced_thinning_wall() -// -// Description: -// Makes a rectangular wall with cross-bracing, which thins to a smaller width in the center, -// with angled supports to prevent critical overhangs. -// -// Usage: -// braced_thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [anchor]); -// -// Arguments: -// h = height of wall. -// l = length of wall. -// thick = thickness of wall. -// ang = maximum overhang angle of diagonal brace. -// strut = the width of the diagonal brace. -// wall = the thickness of the thinned portion of the wall. -// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// -// Example: Typical Shape -// braced_thinning_wall(h=50, l=100, thick=5); -module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) -{ - dang = atan((h-2*strut)/(l-2*strut)); - dlen = (h-2*strut)/sin(dang); - size = [l, thick, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { - union() { - xrot_copies([0, 180]) { - down(h/2) narrowing_strut(w=thick, l=l, wall=strut, ang=ang); - fwd(l/2) xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang); - intersection() { - cube(size=[thick, l, h], center=true); - xrot_copies([-dang,dang]) { - zspread(strut/2) { - scale([1,1,1.5]) yrot(45) { - cube(size=[thick/sqrt(2), dlen, thick/sqrt(2)], center=true); - } - } - cube(size=[thick, dlen, strut/2], center=true); - } - } - } - cube(size=[wall, l-0.1, h-0.1], center=true); - } - children(); - } -} - - - -// Module: thinning_triangle() -// -// Description: -// Makes a triangular wall with thick edges, which thins to a smaller width in -// the center, with angled supports to prevent critical overhangs. -// -// Usage: -// thinning_triangle(h, l, thick, [ang], [strut], [wall], [diagonly], [orient], [anchor|center]); -// -// Arguments: -// h = height of wall. -// l = length of wall. -// thick = thickness of wall. -// ang = maximum overhang angle of diagonal brace. -// strut = the width of the diagonal brace. -// wall = the thickness of the thinned portion of the wall. -// diagonly = boolean, which denotes only the diagonal side (hypotenuse) should be thick. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// center = If true, centers shape. If false, overrides `anchor` with `UP+BACK`. -// -// Example: Centered -// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=true); -// Example: All Braces -// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=false); -// Example: Diagonal Brace Only -// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, diagonly=true, center=false); -module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly=false, center=undef, orient=ORIENT_Y, anchor=CENTER) -{ - dang = atan(h/l); - dlen = h/sin(dang); - size = [thick, h, l]; - orient_and_anchor(size, orient, anchor, center=center, noncentered=BOTTOM+FRONT, orig_orient=ORIENT_Y, chain=true) { - difference() { - union() { - if (!diagonly) { - translate([0, 0, -h/2]) - narrowing_strut(w=thick, l=l, wall=strut, ang=ang); - translate([0, -l/2, 0]) - xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang); - } - intersection() { - cube(size=[thick, l, h], center=true); - xrot(-dang) yrot(180) { - narrowing_strut(w=thick, l=dlen*1.2, wall=strut, ang=ang); - } - } - cube(size=[wall, l-0.1, h-0.1], center=true); - } - xrot(-dang) { - translate([0, 0, h/2]) { - cube(size=[thick+0.1, l*2, h], center=true); - } - } - } - children(); - } -} - - -// Module: sparse_strut() -// -// Description: -// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce -// the need for support material in 3D printing. -// -// Usage: -// sparse_strut(h, l, thick, [strut], [maxang], [max_bridge], [orient], [anchor]) -// -// Arguments: -// h = height of strut wall. -// l = length of strut wall. -// thick = thickness of strut wall. -// maxang = maximum overhang angle of cross-braces. -// max_bridge = maximum bridging distance between cross-braces. -// strut = the width of the cross-braces. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// -// Example: Typical Shape -// sparse_strut(h=40, l=100, thick=3); -// Example: Thinner Strut -// sparse_strut(h=40, l=100, thick=3, strut=2); -// Example: Larger maxang -// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45); -// Example: Longer max_bridge -// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45, max_bridge=30); -module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, orient=ORIENT_Y, anchor=CENTER) -{ - zoff = h/2 - strut/2; - yoff = l/2 - strut/2; - - maxhyp = 1.5 * (max_bridge+strut)/2 / sin(maxang); - maxz = 2 * maxhyp * cos(maxang); - - zreps = ceil(2*zoff/maxz); - zstep = 2*zoff / zreps; - - hyp = zstep/2 / cos(maxang); - maxy = min(2 * hyp * sin(maxang), max_bridge+strut); - - yreps = ceil(2*yoff/maxy); - ystep = 2*yoff / yreps; - - ang = atan(ystep/zstep); - len = zstep / cos(ang); - - size = [thick, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { - union() { - zspread(zoff*2) - cube(size=[thick, l, strut], center=true); - yspread(yoff*2) - cube(size=[thick, strut, h], center=true); - yspread(ystep, n=yreps) { - zspread(zstep, n=zreps) { - xrot( ang) cube(size=[thick, strut, len], center=true); - xrot(-ang) cube(size=[thick, strut, len], center=true); - } - } - } - children(); - } -} - - -// Module: sparse_strut3d() -// -// Usage: -// sparse_strut3d(h, w, l, [thick], [maxang], [max_bridge], [strut], [orient], [anchor]); -// -// Description: -// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce the -// need for support material in 3D printing. -// -// Arguments: -// h = Z size of strut. -// w = X size of strut. -// l = Y size of strut. -// thick = thickness of strut walls. -// maxang = maximum overhang angle of cross-braces. -// max_bridge = maximum bridging distance between cross-braces. -// strut = the width of the cross-braces. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// -// Example: Typical Shape -// sparse_strut3d(h=30, w=30, l=100); -// Example: Thinner strut -// sparse_strut3d(h=30, w=30, l=100, strut=2); -// Example: Larger maxang -// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50); -// Example: Smaller max_bridge -// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50, max_bridge=20); -module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge=30, orient=ORIENT_Y, anchor=CENTER) -{ - - xoff = w - thick; - yoff = l - thick; - zoff = h - thick; - - xreps = ceil(xoff/yoff); - yreps = ceil(yoff/xoff); - zreps = ceil(zoff/min(xoff, yoff)); - - xstep = xoff / xreps; - ystep = yoff / yreps; - zstep = zoff / zreps; - - cross_ang = atan2(xstep, ystep); - cross_len = hypot(xstep, ystep); - - supp_ang = min(maxang, min(atan2(max_bridge, zstep), atan2(cross_len/2, zstep))); - supp_reps = floor(cross_len/2/(zstep*sin(supp_ang))); - supp_step = cross_len/2/supp_reps; - - size = [w, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { - intersection() { - union() { - ybridge = (l - (yreps+1) * strut) / yreps; - xspread(xoff) sparse_strut(h=h, l=l, thick=thick, maxang=maxang, strut=strut, max_bridge=ybridge/ceil(ybridge/max_bridge)); - yspread(yoff) zrot(90) sparse_strut(h=h, l=w, thick=thick, maxang=maxang, strut=strut, max_bridge=max_bridge); - for(zs = [0:zreps-1]) { - for(xs = [0:xreps-1]) { - for(ys = [0:yreps-1]) { - translate([(xs+0.5)*xstep-xoff/2, (ys+0.5)*ystep-yoff/2, (zs+0.5)*zstep-zoff/2]) { - zflip_copy(offset=-(zstep-strut)/2) { - xflip_copy() { - zrot(cross_ang) { - down(strut/2) { - cube([strut, cross_len, strut], center=true); - } - if (zreps>1) { - back(cross_len/2) { - zrot(-cross_ang) { - down(strut) cube([strut, strut, zstep+strut], anchor=BOTTOM); - } - } - } - for (soff = [0 : supp_reps-1] ) { - yflip_copy() { - back(soff*supp_step) { - skew_xy(ya=supp_ang) { - cube([strut, strut, zstep], anchor=BOTTOM); - } - } - } - } - } - } - } - } - } - } - } - } - cube([w,l,h], center=true); - } - children(); - } -} - - -// Module: corrugated_wall() -// -// Description: -// Makes a corrugated wall which relieves contraction stress while still -// providing support strength. Designed with 3D printing in mind. -// -// Usage: -// corrugated_wall(h, l, thick, [strut], [wall], [orient], [anchor]); -// -// Arguments: -// h = height of strut wall. -// l = length of strut wall. -// thick = thickness of strut wall. -// strut = the width of the cross-braces. -// wall = thickness of corrugations. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. -// -// Example: Typical Shape -// corrugated_wall(h=50, l=100); -// Example: Wider Strut -// corrugated_wall(h=50, l=100, strut=8); -// Example: Thicker Wall -// corrugated_wall(h=50, l=100, strut=8, wall=3); -module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) -{ - amplitude = (thick - wall) / 2; - period = min(15, thick * 2); - steps = quantup(segs(thick/2),4); - step = period/steps; - il = l - 2*strut + 2*step; - size = [thick, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { - union() { - linear_extrude(height=h-2*strut+0.1, slices=2, convexity=ceil(2*il/period), center=true) { - polygon( - points=concat( - [for (y=[-il/2:step:il/2]) [amplitude*sin(y/period*360)-wall/2, y] ], - [for (y=[il/2:-step:-il/2]) [amplitude*sin(y/period*360)+wall/2, y] ] - ) - ); - } - difference() { - cube([thick, l, h], center=true); - cube([thick+0.5, l-2*strut, h-2*strut], center=true); - } - } - children(); - } -} - // Section: Miscellaneous diff --git a/transforms.scad b/transforms.scad index 1dfdd03..2342672 100644 --- a/transforms.scad +++ b/transforms.scad @@ -459,7 +459,7 @@ module zflip(cp=[0,0,0]) translate(cp) mirror([0,0,1]) translate(-cp) children() // Skews children on the X-Y plane, keeping constant in Z. // // Usage: -// skew_xy([xa], [ya]) ... +// skew_xy([xa], [ya], [planar]) ... // // Arguments: // xa = skew angle towards the X direction. diff --git a/walls.scad b/walls.scad new file mode 100644 index 0000000..5977c6b --- /dev/null +++ b/walls.scad @@ -0,0 +1,561 @@ +////////////////////////////////////////////////////////////////////// +// LibFile: walls.scad +// Various wall constructions. +// To use, add the following lines to the beginning of your file: +// ``` +// include +// include +// ``` +////////////////////////////////////////////////////////////////////// + +/* +BSD 2-Clause License + +Copyright (c) 2017-2019, Revar Desmera +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + + +// Section: Walls + + +// Module: narrowing_strut() +// +// Description: +// Makes a rectangular strut with the top side narrowing in a triangle. +// The shape created may be likened to an extruded home plate from baseball. +// This is useful for constructing parts that minimize the need to support +// overhangs. +// +// Usage: +// narrowing_strut(w, l, wall, [ang], [orient], [anchor]); +// +// Arguments: +// w = Width (thickness) of the strut. +// l = Length of the strut. +// wall = height of rectangular portion of the strut. +// ang = angle that the trianglar side will converge at. +// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `FRONT`. +// +// Example: +// narrowing_strut(w=10, l=100, wall=5, ang=30); +module narrowing_strut(w=10, l=100, wall=5, ang=30, orient=ORIENT_Y, anchor=FRONT) +{ + h = wall + w/2/tan(ang); + size = [w, h, l]; + orient_and_anchor(size, orient, anchor, chain=true) { + fwd(h/2) { + linear_extrude(height=l, center=true, slices=2) { + back(wall/2) square([w, wall], center=true); + back(wall-0.001) { + yscale(1/tan(ang)) { + difference() { + zrot(45) square(w/sqrt(2), center=true); + fwd(w/2) square(w, center=true); + } + } + } + } + } + children(); + } +} + + +// Module: thinning_wall() +// +// Description: +// Makes a rectangular wall which thins to a smaller width in the center, +// with angled supports to prevent critical overhangs. +// +// Usage: +// thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [anchor]); +// +// Arguments: +// h = height of wall. +// l = length of wall. If given as a vector of two numbers, specifies bottom and top lengths, respectively. +// thick = thickness of wall. +// ang = maximum overhang angle of diagonal brace. +// strut = the width of the diagonal brace. +// wall = the thickness of the thinned portion of the wall. +// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// +// Example: Typical Shape +// thinning_wall(h=50, l=80, thick=4); +// Example: Trapezoidal +// thinning_wall(h=50, l=[80,50], thick=4); +module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Z, anchor=CENTER) +{ + l1 = (l[0] == undef)? l : l[0]; + l2 = (l[1] == undef)? l : l[1]; + + trap_ang = atan2((l2-l1)/2, h); + corr1 = 1 + sin(trap_ang); + corr2 = 1 - sin(trap_ang); + + z1 = h/2; + z2 = max(0.1, z1 - strut); + z3 = max(0.05, z2 - (thick-wall)/2*sin(90-ang)/sin(ang)); + + x1 = l2/2; + x2 = max(0.1, x1 - strut*corr1); + x3 = max(0.05, x2 - (thick-wall)/2*sin(90-ang)/sin(ang)*corr1); + x4 = l1/2; + x5 = max(0.1, x4 - strut*corr2); + x6 = max(0.05, x5 - (thick-wall)/2*sin(90-ang)/sin(ang)*corr2); + + y1 = thick/2; + y2 = y1 - min(z2-z3, x2-x3) * sin(ang); + + size = [l1, thick, h]; + orient_and_anchor(size, orient, anchor, size2=[l2,thick], chain=true) { + polyhedron( + points=[ + [-x4, -y1, -z1], + [ x4, -y1, -z1], + [ x1, -y1, z1], + [-x1, -y1, z1], + + [-x5, -y1, -z2], + [ x5, -y1, -z2], + [ x2, -y1, z2], + [-x2, -y1, z2], + + [-x6, -y2, -z3], + [ x6, -y2, -z3], + [ x3, -y2, z3], + [-x3, -y2, z3], + + [-x4, y1, -z1], + [ x4, y1, -z1], + [ x1, y1, z1], + [-x1, y1, z1], + + [-x5, y1, -z2], + [ x5, y1, -z2], + [ x2, y1, z2], + [-x2, y1, z2], + + [-x6, y2, -z3], + [ x6, y2, -z3], + [ x3, y2, z3], + [-x3, y2, z3], + ], + faces=[ + [ 4, 5, 1], + [ 5, 6, 2], + [ 6, 7, 3], + [ 7, 4, 0], + + [ 4, 1, 0], + [ 5, 2, 1], + [ 6, 3, 2], + [ 7, 0, 3], + + [ 8, 9, 5], + [ 9, 10, 6], + [10, 11, 7], + [11, 8, 4], + + [ 8, 5, 4], + [ 9, 6, 5], + [10, 7, 6], + [11, 4, 7], + + [11, 10, 9], + [20, 21, 22], + + [11, 9, 8], + [20, 22, 23], + + [16, 17, 21], + [17, 18, 22], + [18, 19, 23], + [19, 16, 20], + + [16, 21, 20], + [17, 22, 21], + [18, 23, 22], + [19, 20, 23], + + [12, 13, 17], + [13, 14, 18], + [14, 15, 19], + [15, 12, 16], + + [12, 17, 16], + [13, 18, 17], + [14, 19, 18], + [15, 16, 19], + + [ 0, 1, 13], + [ 1, 2, 14], + [ 2, 3, 15], + [ 3, 0, 12], + + [ 0, 13, 12], + [ 1, 14, 13], + [ 2, 15, 14], + [ 3, 12, 15], + ], + convexity=6 + ); + children(); + } +} + + +// Module: braced_thinning_wall() +// +// Description: +// Makes a rectangular wall with cross-bracing, which thins to a smaller width in the center, +// with angled supports to prevent critical overhangs. +// +// Usage: +// braced_thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [anchor]); +// +// Arguments: +// h = height of wall. +// l = length of wall. +// thick = thickness of wall. +// ang = maximum overhang angle of diagonal brace. +// strut = the width of the diagonal brace. +// wall = the thickness of the thinned portion of the wall. +// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// +// Example: Typical Shape +// braced_thinning_wall(h=50, l=100, thick=5); +module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) +{ + dang = atan((h-2*strut)/(l-2*strut)); + dlen = (h-2*strut)/sin(dang); + size = [l, thick, h]; + orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + union() { + xrot_copies([0, 180]) { + down(h/2) narrowing_strut(w=thick, l=l, wall=strut, ang=ang); + fwd(l/2) xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang); + intersection() { + cube(size=[thick, l, h], center=true); + xrot_copies([-dang,dang]) { + zspread(strut/2) { + scale([1,1,1.5]) yrot(45) { + cube(size=[thick/sqrt(2), dlen, thick/sqrt(2)], center=true); + } + } + cube(size=[thick, dlen, strut/2], center=true); + } + } + } + cube(size=[wall, l-0.1, h-0.1], center=true); + } + children(); + } +} + + + +// Module: thinning_triangle() +// +// Description: +// Makes a triangular wall with thick edges, which thins to a smaller width in +// the center, with angled supports to prevent critical overhangs. +// +// Usage: +// thinning_triangle(h, l, thick, [ang], [strut], [wall], [diagonly], [orient], [anchor|center]); +// +// Arguments: +// h = height of wall. +// l = length of wall. +// thick = thickness of wall. +// ang = maximum overhang angle of diagonal brace. +// strut = the width of the diagonal brace. +// wall = the thickness of the thinned portion of the wall. +// diagonly = boolean, which denotes only the diagonal side (hypotenuse) should be thick. +// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// center = If true, centers shape. If false, overrides `anchor` with `UP+BACK`. +// +// Example: Centered +// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=true); +// Example: All Braces +// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=false); +// Example: Diagonal Brace Only +// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, diagonly=true, center=false); +module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly=false, center=undef, orient=ORIENT_Y, anchor=CENTER) +{ + dang = atan(h/l); + dlen = h/sin(dang); + size = [thick, h, l]; + orient_and_anchor(size, orient, anchor, center=center, noncentered=BOTTOM+FRONT, orig_orient=ORIENT_Y, chain=true) { + difference() { + union() { + if (!diagonly) { + translate([0, 0, -h/2]) + narrowing_strut(w=thick, l=l, wall=strut, ang=ang); + translate([0, -l/2, 0]) + xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang); + } + intersection() { + cube(size=[thick, l, h], center=true); + xrot(-dang) yrot(180) { + narrowing_strut(w=thick, l=dlen*1.2, wall=strut, ang=ang); + } + } + cube(size=[wall, l-0.1, h-0.1], center=true); + } + xrot(-dang) { + translate([0, 0, h/2]) { + cube(size=[thick+0.1, l*2, h], center=true); + } + } + } + children(); + } +} + + +// Module: sparse_strut() +// +// Description: +// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce +// the need for support material in 3D printing. +// +// Usage: +// sparse_strut(h, l, thick, [strut], [maxang], [max_bridge], [orient], [anchor]) +// +// Arguments: +// h = height of strut wall. +// l = length of strut wall. +// thick = thickness of strut wall. +// maxang = maximum overhang angle of cross-braces. +// max_bridge = maximum bridging distance between cross-braces. +// strut = the width of the cross-braces. +// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// +// Example: Typical Shape +// sparse_strut(h=40, l=100, thick=3); +// Example: Thinner Strut +// sparse_strut(h=40, l=100, thick=3, strut=2); +// Example: Larger maxang +// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45); +// Example: Longer max_bridge +// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45, max_bridge=30); +module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, orient=ORIENT_Y, anchor=CENTER) +{ + zoff = h/2 - strut/2; + yoff = l/2 - strut; + + maxhyp = 1.5 * (max_bridge+strut)/2 / sin(maxang); + maxz = 2 * maxhyp * cos(maxang); + + zreps = ceil(2*zoff/maxz); + zstep = 2*zoff / zreps; + + hyp = zstep/2 / cos(maxang); + maxy = min(2 * hyp * sin(maxang), max_bridge+strut); + + yreps = ceil(2*yoff/maxy); + ystep = 2*yoff / yreps; + + ang = atan(ystep/zstep); + len = zstep / cos(ang); + + size = [thick, l, h]; + orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + yrot(90) + linear_extrude(height=thick, convexity=4*yreps, center=true) { + difference() { + square([h, l], center=true); + square([h-2*strut, l-2*strut], center=true); + } + yspread(ystep, n=yreps) { + xspread(zstep, n=zreps) { + skew_xy(planar=true, ya=-ang) square([h-1.99*strut, strut], center=true); + skew_xy(planar=true, ya= ang) square([h-1.99*strut, strut], center=true); + } + } + } + children(); + } +} + + +// Module: sparse_strut3d() +// +// Usage: +// sparse_strut3d(h, w, l, [thick], [maxang], [max_bridge], [strut], [orient], [anchor]); +// +// Description: +// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce the +// need for support material in 3D printing. +// +// Arguments: +// h = Z size of strut. +// w = X size of strut. +// l = Y size of strut. +// thick = thickness of strut walls. +// maxang = maximum overhang angle of cross-braces. +// max_bridge = maximum bridging distance between cross-braces. +// strut = the width of the cross-braces. +// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// +// Example: Typical Shape +// sparse_strut3d(h=30, w=30, l=100); +// Example: Thinner strut +// sparse_strut3d(h=30, w=30, l=100, strut=2); +// Example: Larger maxang +// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50); +// Example: Smaller max_bridge +// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50, max_bridge=20); +module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge=30, orient=ORIENT_Y, anchor=CENTER) +{ + + xoff = w - thick; + yoff = l - thick; + zoff = h - thick; + + xreps = ceil(xoff/yoff); + yreps = ceil(yoff/xoff); + zreps = ceil(zoff/min(xoff, yoff)); + + xstep = xoff / xreps; + ystep = yoff / yreps; + zstep = zoff / zreps; + + cross_ang = atan2(xstep, ystep); + cross_len = hypot(xstep, ystep); + + supp_ang = min(maxang, min(atan2(max_bridge, zstep), atan2(cross_len/2, zstep))); + supp_reps = floor(cross_len/2/(zstep*sin(supp_ang))); + supp_step = cross_len/2/supp_reps; + + size = [w, l, h]; + orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + intersection() { + union() { + ybridge = (l - (yreps+1) * strut) / yreps; + xspread(xoff) sparse_strut(h=h, l=l, thick=thick, maxang=maxang, strut=strut, max_bridge=ybridge/ceil(ybridge/max_bridge)); + yspread(yoff) zrot(90) sparse_strut(h=h, l=w, thick=thick, maxang=maxang, strut=strut, max_bridge=max_bridge); + for(zs = [0:zreps-1]) { + for(xs = [0:xreps-1]) { + for(ys = [0:yreps-1]) { + translate([(xs+0.5)*xstep-xoff/2, (ys+0.5)*ystep-yoff/2, (zs+0.5)*zstep-zoff/2]) { + zflip_copy(offset=-(zstep-strut)/2) { + xflip_copy() { + zrot(cross_ang) { + down(strut/2) { + cube([strut, cross_len, strut], center=true); + } + if (zreps>1) { + back(cross_len/2) { + zrot(-cross_ang) { + down(strut) cube([strut, strut, zstep+strut], anchor=BOTTOM); + } + } + } + for (soff = [0 : supp_reps-1] ) { + yflip_copy() { + back(soff*supp_step) { + skew_xy(ya=supp_ang) { + cube([strut, strut, zstep], anchor=BOTTOM); + } + } + } + } + } + } + } + } + } + } + } + } + cube([w,l,h], center=true); + } + children(); + } +} + + +// Module: corrugated_wall() +// +// Description: +// Makes a corrugated wall which relieves contraction stress while still +// providing support strength. Designed with 3D printing in mind. +// +// Usage: +// corrugated_wall(h, l, thick, [strut], [wall], [orient], [anchor]); +// +// Arguments: +// h = height of strut wall. +// l = length of strut wall. +// thick = thickness of strut wall. +// strut = the width of the cross-braces. +// wall = thickness of corrugations. +// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. +// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// +// Example: Typical Shape +// corrugated_wall(h=50, l=100); +// Example: Wider Strut +// corrugated_wall(h=50, l=100, strut=8); +// Example: Thicker Wall +// corrugated_wall(h=50, l=100, strut=8, wall=3); +module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) +{ + amplitude = (thick - wall) / 2; + period = min(15, thick * 2); + steps = quantup(segs(thick/2),4); + step = period/steps; + il = l - 2*strut + 2*step; + size = [thick, l, h]; + orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + union() { + linear_extrude(height=h-2*strut+0.1, slices=2, convexity=ceil(2*il/period), center=true) { + polygon( + points=concat( + [for (y=[-il/2:step:il/2]) [amplitude*sin(y/period*360)-wall/2, y] ], + [for (y=[il/2:-step:-il/2]) [amplitude*sin(y/period*360)+wall/2, y] ] + ) + ); + } + difference() { + cube([thick, l, h], center=true); + cube([thick+0.5, l-2*strut, h-2*strut], center=true); + } + } + children(); + } +} + + + +// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap