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_to = to;
$attach_anchor = anch; $attach_anchor = anch;
$attach_norot = norot; $attach_norot = norot;
olap = two_d? [0,-overlap,0] : [0,0,-overlap];
if (norot || (norm(anch[2]-UP)<1e-9 && anch[3]==0)) { 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 { } else {
fromvec = two_d? BACK : UP; 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 // Topics: Attachments
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask() // See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask()
// Description: // Description:
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be `diff()`ed away. // Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]]. // `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: // Arguments:
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges. // 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. // 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 A `center=false` argument can mean `anchor=[-1,-1,-1]` for a cube, or `anchor=BOTTOM` for a
cylinder. 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 ## Spin
Attachable shapes also can be spun in place as you create them. You can do this by passing in 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]); 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 ## Orientation
Another way to specify a rotation for an attachable shape, is to pass a 3D vector via the 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); cylinder(h=100, r1=50, r2=20, orient=UP+RIGHT);
``` ```
You can *not* use `orient=` with 2D shapes.
## Mixing Anchoring, Spin, and Orientation ## Mixing Anchoring, Spin, and Orientation
When giving `anchor=`, `spin=`, and `orient=`, they are applied anchoring first, spin second, When giving `anchor=`, `spin=`, and `orient=`, they are applied anchoring first, spin second,
then orient last. For example, here's a cube: 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); 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. 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. 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. 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); 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 By default, `attach()` places the child exactly flush with the surface of the parent. Sometimes
join the parts. If you need the child to have no overlap, or a different overlap, you can use it's useful to have the child overlap the parent by insetting a bit. You can do this with the
the `overlap=` argument: `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 ```openscad
cube(50,center=true) 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 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); 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 ## Anchor Arrows
One way that is useful to show the position and orientation of an anchorpoint is by attaching One way that is useful to show the position and orientation of an anchorpoint is by attaching
an anchor arrow to that anchor. an anchor arrow to that anchor.
@ -259,6 +321,7 @@ cylinder(h=100, d=100, center=true)
show_anchors(s=30); show_anchors(s=30);
``` ```
## Tagged Operations ## Tagged Operations
BOSL2 introduces the concept of tags. Tags are names that can be given to attachables, so that 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. you can refer to them when performing `diff()`, `intersect()`, and `hulling()` operations.
@ -372,12 +435,169 @@ cube(50, center=true, $tags="hull") {
``` ```
## Masking Children ## 3D Masking Attachments
TBW 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 ## 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 ## Making Attachables