From 9b99e5aa1b66e1dab1b66e23ee7389709dc71452 Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Tue, 20 Apr 2021 18:58:07 -0700 Subject: [PATCH] Added a bunch to attachables tutorial. --- tutorials/Attachments.md | 348 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 342 insertions(+), 6 deletions(-) diff --git a/tutorials/Attachments.md b/tutorials/Attachments.md index 7cf26b5..87638e0 100644 --- a/tutorials/Attachments.md +++ b/tutorials/Attachments.md @@ -219,23 +219,359 @@ cube(50, center=true) ## Tagged Operations +BOSL2 introduces the concept of tags. Tags are names that can be given to attachables, so that +you can refer to them when performing `diff()`, `intersect()`, and `hulling()` operations. + +### `diff(neg, , )` +The `diff()` operator is used to difference away all shapes marked with the tag(s) given to +`neg=`, from shapes marked with the tag(s) given to `pos=`. Anything marked with a tag given +to `keep=` will be unioned onto the result. If no `pos=` argument is given, then everything +marked with a tag given to `neg=` will be differenced from all shapes *not* marked with that +tag. + +For example, to difference away a child cylinder from the middle of a parent cube, you can +do this: + +```openscad +diff("hole") +cube(100, center=true) + cylinder(h=101, d=50, center=true, $tags="hole"); +``` + +If you give both the `neg=` and `pos=` arguments to `diff()`, then the shapes marked by tags +given to `neg=` will be differenced away from the shapes marked with tags given to `pos=`. +Everything else will be unioned to the result. + +```openscad +diff("hole", "post") +cube(100, center=true) + attach([RIGHT,TOP]) { + cylinder(d=95, h=5, $tags="post"); + cylinder(d=50, h=11, anchor=CTR, $tags="hole"); + } +``` + +The `keep=` argument takes tags for shapes that you want to keep in the output. + +```openscad +diff("dish", keep="antenna") +cube(100, center=true) + attach([FRONT,TOP], overlap=33) { + cylinder(h=33.1, d1=0, d2=95, $tags="dish"); + cylinder(h=33.1, d=10, $tags="antenna"); + } +``` + +If you need to mark multiple children with a tag, you can use the `tags()` module. + +```openscad +diff("hole") +cube(100, center=true) + attach([FRONT,TOP], overlap=20) + tags("hole") { + cylinder(h=20.1, d1=0, d2=95); + down(10) cylinder(h=30, d=30); + } +``` + +The parent object can be differenced away from other shapes. Tags are inherited by children, +though, so you will need to set the tags of the children as well as the parent. + +```openscad +diff("hole") +cube([20,11,45], center=true, $tags="hole") + cube([40,10,90], center=true, $tags="body"); +``` + +### `intersect(a, , )` + +To perform an intersection of attachables, you can use the `intersect()` module. If given one +argument to `a=`, the parent and all children *not* tagged with that will be intersected by +everything that *is* tagged with it. + +```openscad +intersect("bounds") +cube(100, center=true) + cylinder(h=100, d1=120, d2=95, center=true, $fn=72, $tags="bounds"); +``` + +If given both the `a=` and `b=` arguments, then shapes marked with tags given to `a=` will be +intersected with shapes marked with tags given to `b=`, then unioned with all other shapes. + +```openscad +intersect("pole", "cap") +cube(100, center=true) + attach([TOP,RIGHT]) { + cube([40,40,80],center=true, $tags="pole"); + sphere(d=40*sqrt(2), $tags="cap"); + } +``` + +If the `keep=` argument is given, anything marked with tags passed to it will be unioned with +the result of the union: + +```openscad +intersect("bounds", keep="pole") +cube(100, center=true) { + cylinder(h=100, d1=120, d2=95, center=true, $fn=72, $tags="bounds"); + zrot(45) xcyl(h=140, d=20, $fn=36, $tags="pole"); +} +``` + +### `hulling(a)` +You can use the `hulling()` module to hull shapes marked with a given tag together, before +unioning the result with every other shape. + +```openscad +hulling("hull") +cube(50, center=true, $tags="hull") { + cyl(h=100, d=20); + xcyl(h=100, d=20, $tags="pole"); +} +``` ## Masking Children -edge_mask() -corner_mask() - -face_profile() -edge_profile() -corner_profile() +TBW ## Coloring Attachables +TBW ## Making Attachables +To make a shape attachable, you just need to wrap it with an `attachable()` module with a +basic description of the shape's geometry. By default, the shape is expected to be centered +at the origin. The `attachable()` module expects exactly two children. The first will be +the shape to make attachable, and the second will be `children()`, literally. + +### Prismoidal/Cuboidal Attachables +To make a cuboidal or prismoidal shape attachable, you use the `size`, `size2`, and `offset` +arguments of `attachable()`. + +In the most basic form, where the shape in fully cuboid, with top and bottom of the same size, +and directly over one another, you can just use `size=`. + +```openscad +module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) { + attachable(anchor,spin,orient, size=[s*3,s,s]) { + union() { + xcopies(2*s) cube(s, center=true); + xcyl(h=2*s, d=s/4); + } + children(); + } +} +cubic_barbell(100); +``` + +When the shape is prismoidal, where the top is a different size from the bottom, you can use +the `size2=` argument as well. + +```openscad +module prismoidal(size=[100,100,100], scale=0.5, anchor=CENTER, spin=0, orient=UP) { + attachable(anchor,spin,orient, size=size, size2=[size.x, size.y]*scale) { + hull() { + up(size.z/2-0.005) + linear_extrude(height=0.01, center=true) + square([size.x,size.y]*scale, center=true); + down(size.z/2-0.005) + linear_extrude(height=0.01, center=true) + square([size.x,size.y], center=true); + } + children(); + } +} +prismoidal([100,60,30], scale=0.5); +``` + +When the top of the prismoid can be shifted away from directly above the bottom, you can use +the `shift=` argument. + +```openscad +module prismoidal(size=[100,100,100], scale=0.5, shift=[0,0], anchor=CENTER, spin=0, orient=UP) { + attachable(anchor,spin,orient, size=size, size2=[size.x, size.y]*scale, shift=shift) { + hull() { + translate([shift.x, shift.y, size.z/2-0.005]) + linear_extrude(height=0.01, center=true) + square([size.x,size.y]*scale, center=true); + down(size.z/2-0.005) + linear_extrude(height=0.01, center=true) + square([size.x,size.y], center=true); + } + children(); + } +} +prismoidal([100,60,30], scale=0.5, shift=[-30,20]); +``` + +In the case that the prismoid is not oriented vertically, you can use the `axis=` argument. + +```openscad +module yprismoidal( + size=[100,100,100], scale=0.5, shift=[0,0], + anchor=CENTER, spin=0, orient=UP +) { + attachable( + anchor, spin, orient, + size=size, size2=point2d(size)*scale, + shift=shift, axis=BACK + ) { + xrot(-90) hull() { + translate([shift.x, shift.y, size.z/2-0.005]) + linear_extrude(height=0.01, center=true) + square([size.x,size.y]*scale, center=true); + down(size.z/2-0.005) + linear_extrude(height=0.01, center=true) + square([size.x,size.y], center=true); + } + children(); + } +} +yprismoidal([100,60,30], scale=1.5, shift=[20,20]); +``` + + +### Cylindrical Attachables +To make a cylindrical shape attachable, you use the `l`, and `r`/`d`, args of `attachable()`. + +```openscad +module twistar(l,r,d, anchor=CENTER, spin=0, orient=UP) { + r = get_radius(r=r,d=d,dflt=1); + attachable(anchor,spin,orient, r=r, l=l) { + linear_extrude(height=l, twist=90, slices=20, center=true, convexity=4) + star(n=20, r=r, ir=r*0.9); + children(); + } +} +twistar(l=100, r=40); +``` + +If the cylinder is elipsoidal in shape, you can pass the inequal X/Y sizes as a 2-item vector +to the `r=` or `d=` argument. + +```openscad +module ovalstar(l,rx,ry, anchor=CENTER, spin=0, orient=UP) { + attachable(anchor,spin,orient, r=[rx,ry], l=l) { + linear_extrude(height=l, center=true, convexity=4) + scale([1,ry/rx,1]) + star(n=20, r=rx, ir=rx*0.9); + children(); + } +} +ovalstar(l=100, rx=50, ry=30); +``` + +For cylindrical shapes that arent oriented vertically, use the `axis=` argument. + +```openscad +module ytwistar(l,r,d, anchor=CENTER, spin=0, orient=UP) { + r = get_radius(r=r,d=d,dflt=1); + attachable(anchor,spin,orient, r=r, l=l) { + xrot(-90) + linear_extrude(height=l, twist=90, slices=20, center=true, convexity=4) + star(n=20, r=r, ir=r*0.9); + children(); + } +} +ytwistar(l=100, r=40); +``` + +### Conical Attachables +To make a conical shape attachable, you use the `l`, `r1`/`d1`, and `r2`/`d2`, args of +`attachable()`. + +```openscad +module twistar(l, r,r1,r2, d,d1,d2, anchor=CENTER, spin=0, orient=UP) { + 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); + attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) { + linear_extrude(height=l, twist=90, scale=r2/r1, slices=20, center=true, convexity=4) + star(n=20, r=r1, ir=r1*0.9); + children(); + } +} +twistar(l=100, r1=40, r2=20); +``` + +If the cone is elipsoidal in shape, you can pass the inequal X/Y sizes as a 2-item vectors +to the `r1=`/`r2=` or `d1=`/`d2=` arguments. + +```openscad +module ovalish(l,rx1,ry1,rx2,ry2, anchor=CENTER, spin=0, orient=UP) { + attachable(anchor,spin,orient, r1=[rx1,ry1], r2=[rx2,ry2], l=l) { + hull() { + up(l/2-0.005) + linear_extrude(height=0.01, center=true) + scale([1,ry2/rx2,1]) + oval([rx2,ry2]); + down(l/2-0.005) + linear_extrude(height=0.01, center=true) + scale([1,ry1/rx1,1]) + oval([rx1,ry1]); + } + children(); + } +} +ovalish(l=100, rx1=40, ry1=30, rx2=30, ry2=40); +``` + +For conical shapes that are not oriented vertically, use the `axis=` argument. + +```openscad +module ytwistar(l, r,r1,r2, d,d1,d2, anchor=CENTER, spin=0, orient=UP) { + 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); + attachable(anchor,spin,orient, r1=r1, r2=r2, l=l, axis=BACK) { + xrot(-90) + linear_extrude(height=l, twist=90, scale=r2/r1, slices=20, center=true, convexity=4) + star(n=20, r=r1, ir=r1*0.9); + children(); + } +} +ytwistar(l=100, r1=40, r2=20); +``` + +### Spherical Attachables +To make a spherical shape attachable, you use the `r`/`d` args of `attachable()`. + +```openscad +module spikeball(r, d, anchor=CENTER, spin=0, orient=UP) { + r = get_radius(r=r,d=d,dflt=1); + attachable(anchor,spin,orient, r=r*1.1) { + union() { + ovoid_spread(r=r, n=512, cone_ang=180) cylinder(r1=r/10, r2=0, h=r/10); + sphere(r=r); + } + children(); + } +} +spikeball(r=50); +``` + +If the shape is more of an ovoid, you can pass a 3-item vector of sizes to `r=` or `d=`. + +```openscad +module spikeball(r, d, scale, anchor=CENTER, spin=0, orient=UP) { + r = get_radius(r=r,d=d,dflt=1); + attachable(anchor,spin,orient, r=r*1.1*scale) { + union() { + ovoid_spread(r=r, n=512, scale=scale, cone_ang=180) cylinder(r1=r/10, r2=0, h=r/10); + scale(scale) sphere(r=r); + } + children(); + } +} +spikeball(r=50, scale=[0.75,1,1.5]); +``` + +### VNF Attachables +If the shape just doesn't fit into any of the above categories, and you constructed it as a +[VNF](vnf.scad), you can use the VNF itself to describe the geometry. +TBW ## Making Named Anchors +TBW