Merge pull request #537 from revarbat/revarbat_dev

Attachments bugfixes and tutorial updates
This commit is contained in:
Revar Desmera 2021-05-20 01:38:53 -07:00 committed by GitHub
commit 9819599a29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 243 additions and 12 deletions

View file

@ -1057,11 +1057,12 @@ module attach(from, to, overlap, norot=false)
$attach_to = to;
$attach_anchor = anch;
$attach_norot = norot;
olap = two_d? [0,-overlap,0] : [0,0,-overlap];
if (norot || (norm(anch[2]-UP)<1e-9 && anch[3]==0)) {
translate(anch[1]) translate([0,0,-overlap]) children();
translate(anch[1]) translate(olap) children();
} else {
fromvec = two_d? BACK : UP;
translate(anch[1]) rot(anch[3],from=fromvec,to=anch[2]) translate([0,0,-overlap]) children();
translate(anch[1]) rot(anch[3],from=fromvec,to=anch[2]) translate(olap) children();
}
}
}
@ -1223,8 +1224,18 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
// Topics: Attachments
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask()
// Description:
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be `diff()`ed away.
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be
// `diff()`ed away. The mask shape should be vertically oriented (Z-aligned) with the back-right
// quadrant (X+Y+) shaped to be diffed away from the edge of parent attachable shape. For a more
// step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Figure: A Typical Edge Rounding Mask
// module roundit(l,r) difference() {
// translate([-1,-1,-l/2])
// cube([r+1,r+1,l]);
// translate([r,r])
// cylinder(h=l+1,r=r,center=true, $fn=quantup(segs(r),4));
// }
// roundit(l=30,r=10);
// Arguments:
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.

View file

@ -91,6 +91,23 @@ overrides the `anchor=` argument. A `center=true` argument is the same as `anch
A `center=false` argument can mean `anchor=[-1,-1,-1]` for a cube, or `anchor=BOTTOM` for a
cylinder.
Many 2D shapes provided by BOSL2 are also anchorable. Due to technical limitations of OpenSCAD,
however, `square()` and `circle()` are *not*. BOSL2 provides `rect()` and `oval()` as attachable
and anchorable equivalents. You can only anchor on the XY plane, of course, but you can use the
same `FRONT`, `BACK`, `LEFT`, `RIGHT`, and `CENTER` anchor constants.
```openscad-2D
rect([40,30], anchor=BACK+LEFT);
```
```openscad-2D
oval(d=50, anchor=FRONT);
```
```openscad-2D
hexagon(d=50, anchor=BACK);
```
## Spin
Attachable shapes also can be spun in place as you create them. You can do this by passing in
@ -107,6 +124,17 @@ vector, like [Xang,Yang,Zang]:
cube([20,20,40], center=true, spin=[10,20,30]);
```
You can also apply spin to 2D shapes from BOSL2. Again, you should use `rect()` and `oval()`
instead of `square()` and `circle()`:
```openscad-2D
rect([40,30], spin=30);
```
```openscad-2D
oval(d=[40,30], spin=30);
```
## Orientation
Another way to specify a rotation for an attachable shape, is to pass a 3D vector via the
@ -117,6 +145,9 @@ For example, you can make a cone that is tilted up and to the right like this:
cylinder(h=100, r1=50, r2=20, orient=UP+RIGHT);
```
You can *not* use `orient=` with 2D shapes.
## Mixing Anchoring, Spin, and Orientation
When giving `anchor=`, `spin=`, and `orient=`, they are applied anchoring first, spin second,
then orient last. For example, here's a cube:
@ -150,8 +181,14 @@ However, since spin is applied *after* anchoring, it can actually have a signifi
cylinder(d=50, l=40, anchor=FWD, spin=-30);
```
For 2D shapes, you can mix `anchor=` with `spin=`, but not with `orient=`.
## Attaching Children
```openscad-2D
rect([40,30], anchor=BACK+LEFT, spin=30);
```
## Attaching 3D Children
The reason attachables are called that, is because they can be attached to each other.
You can do that by making one attachable shape be a child of another attachable shape.
By default, the child of an attachable is attached to the center of the parent shape.
@ -178,13 +215,21 @@ cube(50,center=true)
attach(TOP,TOP) cylinder(d1=50,d2=20,l=20);
```
By default, `attach()` causes the child to overlap the parent by 0.01, to let CGAL correctly
join the parts. If you need the child to have no overlap, or a different overlap, you can use
the `overlap=` argument:
By default, `attach()` places the child exactly flush with the surface of the parent. Sometimes
it's useful to have the child overlap the parent by insetting a bit. You can do this with the
`overlap=` argument to `attach()`. A positive value will inset the child into the parent, and
a negative value will outset out from the parent:
```openscad
cube(50,center=true)
attach(TOP,TOP,overlap=0) cylinder(d1=50,d2=20,l=20);
attach(TOP,overlap=10)
cylinder(d=20,l=20);
```
```openscad
cube(50,center=true)
attach(TOP,overlap=-20)
cylinder(d=20,l=20);
```
If you want to position the child at the parent's anchorpoint, without re-orienting, you can
@ -217,6 +262,23 @@ cube(50, center=true)
position([TOP,RIGHT,FRONT]) cylinder(d1=50,d2=20,l=20);
```
## Attaching 2D Children
You can use attachments in 2D as well, but only in the XY plane. Also, the built-in `square()`
and `circle()` 2D modules do not support attachments. Instead, you should use the `rect()` and
`oval()` modules:
```openscad-2D
rect(50,center=true)
attach(RIGHT,FRONT)
trapezoid(w1=30,w2=0,h=30);
```
```openscad-2D
oval(d=50)
attach(BACK,FRONT,overlap=5)
trapezoid(w1=30,w2=0,h=30);
```
## Anchor Arrows
One way that is useful to show the position and orientation of an anchorpoint is by attaching
an anchor arrow to that anchor.
@ -259,6 +321,7 @@ cylinder(h=100, d=100, center=true)
show_anchors(s=30);
```
## 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.
@ -372,12 +435,169 @@ cube(50, center=true, $tags="hull") {
```
## Masking Children
TBW
## 3D Masking Attachments
To make it easier to mask away shapes from various edges of an attachable parent shape, there
are a few specialized alternatives to the `attach()` and `position()` modules.
### `edge_mask()`
If you have a 3D mask shape that you want to difference away from various edges, you can use
the `edge_mask()` module. This module will take a vertically oriented shape, and will rotate
and move it such that the BACK, RIGHT (X+,Y+) side of the shape will be aligned with the given
edges. The shape will be tagged as a "mask" so that you can use `diff("mask")`. For example,
here's a shape for rounding an edge:
```openscad
module round_edge(l,r) difference() {
translate([-1,-1,-l/2])
cube([r+1,r+1,l]);
translate([r,r])
cylinder(h=l+1,r=r,center=true, $fn=quantup(segs(r),4));
}
round_edge(l=30, r=19);
```
You can use that mask to round various edges of a cube:
```openscad
module round_edge(l,r) difference() {
translate([-1,-1,-l/2])
cube([r+1,r+1,l]);
translate([r,r])
cylinder(h=l+1,r=r,center=true, $fn=quantup(segs(r),4));
}
diff("mask")
cube([50,60,70],center=true)
edge_mask([TOP,"Z"],except=[BACK,TOP+LEFT])
round_edge(l=71,r=10);
```
### `corner_mask()`
If you have a 3D mask shape that you want to difference away from various corners, you can use
the `corner_mask()` module. This module will take a shape and rotate and move it such that the
BACK RIGHT TOP (X+,Y+,Z+) side of the shape will be aligned with the given corner. The shape
will be tagged as a "mask" so that you can use `diff("mask")`. For example, here's a shape for
rounding a corner:
```openscad
module round_corner(r) difference() {
translate(-[1,1,1])
cube(r+1);
translate([r,r,r])
sphere(r=r, style="aligned", $fn=quantup(segs(r),4));
}
round_corner(r=10);
```
You can use that mask to round various corners of a cube:
```openscad
module round_corner(r) difference() {
translate(-[1,1,1])
cube(r+1);
translate([r,r,r])
sphere(r=r, style="aligned", $fn=quantup(segs(r),4));
}
diff("mask")
cube([50,60,70],center=true)
corner_mask([TOP,FRONT],LEFT+FRONT+TOP)
round_corner(r=10);
```
### Mix and Match Masks
You can use `edge_mask()` and `corner_mask()` together as well:
```openscad
module round_corner(r) difference() {
translate(-[1,1,1])
cube(r+1);
translate([r,r,r])
sphere(r=r, style="aligned", $fn=quantup(segs(r),4));
}
module round_edge(l,r) difference() {
translate([-1,-1,-l/2])
cube([r+1,r+1,l]);
translate([r,r])
cylinder(h=l+1,r=r,center=true, $fn=quantup(segs(r),4));
}
diff("mask")
cube([50,60,70],center=true) {
edge_mask("ALL") round_edge(l=71,r=10);
corner_mask("ALL") round_corner(r=10);
}
```
## 2D Profile Mask Attachments
While 3D mask shapes give you a great deal of control, you need to make sure they are correctly
sized, and you need to provide separate mask shapes for corners and edges. Often, a single 2D
profile could be used to describe the edge mask shape (via `linear_extrude()`), and the corner
mask shape (via `rotate_extrude()`). This is where `edge_profile()`, `corner_profile()`, and
`face_profile()` come in.
### `edge_profile()`
Using the `edge_profile()` module, you can provide a 2D profile shape and it will be linearly
extruded to a mask of the apropriate length for each given edge. The resultant mask will be
tagged with "mask" so that you can difference it away with `diff("mask")`. The 2D profile is
assumed to be oriented with the BACK, RIGHT (X+,Y+) quadrant as the "cutter edge" that gets
re-oriented towards the edges of the parent shape. A typical mask profile for chamfering an
edge may look like:
```openscad
mask2d_roundover(10);
```
Using that mask profile, you can mask the edges of a cube like:
```openscad
diff("mask")
cube([50,60,70],center=true)
edge_profile("ALL")
mask2d_roundover(10);
```
### `corner_profile()`
You can use the same profile to make a rounded corner mask as well:
```openscad
diff("mask")
cube([50,60,70],center=true)
corner_profile("ALL", r=10)
mask2d_roundover(10);
```
### `face_profile()`
As a simple shortcut to apply a profile mask to all edges and corners of a face, you can use the
`face_profile()` module:
```openscad
diff("mask")
cube([50,60,70],center=true)
face_profile(TOP, r=10)
mask2d_roundover(10);
```
## Coloring Attachables
TBW
Usually, when coloring a shape with the `color()` module, the parent color overrides the colors of
all children. This is often not what you want:
```openscad
color("red") spheroid(d=3) {
attach(CENTER,BOT) color("white") cyl(h=10, d=1) {
attach(TOP,BOT) color("green") cyl(h=5, d1=3, d2=0);
}
}
```
If you use the `recolor()` module, however, the child's color overrides the color of the parent.
This is probably easier to understand by example:
```openscad
recolor("red") spheroid(d=3) {
attach(CENTER,BOT) recolor("white") cyl(h=10, d=1) {
attach(TOP,BOT) recolor("green") cyl(h=5, d1=3, d2=0);
}
}
```
## Making Attachables