mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-28 23:39:36 +00:00
tutorials updates and bugfix
This commit is contained in:
parent
76c8f18fd4
commit
c6d2676fb4
3 changed files with 372 additions and 148 deletions
|
@ -735,8 +735,8 @@ function _make_anchor_legal(anchor,geom) =
|
|||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), align(), face_profile(), edge_profile(), corner_profile()
|
||||
// Usage:
|
||||
// PARENT() attach(from, to, [align=], [spin=], [overlap=]) CHILDREN;
|
||||
// PARENT() attach(from, [overlap=], [spin=]) CHILDREN;
|
||||
// PARENT() attach(parent, child, [align=], [spin=], [overlap=]) CHILDREN;
|
||||
// PARENT() attach(parent, [overlap=], [spin=]) CHILDREN;
|
||||
// Description:
|
||||
// Attaches children to a parent object at an anchor point or points, oriented in the anchor direction.
|
||||
// This module differs from {{position()}} and {{align()}} in that it rotates the children to
|
||||
|
@ -744,8 +744,8 @@ function _make_anchor_legal(anchor,geom) =
|
|||
// There are two modes of operation, single argument and double argument.
|
||||
// .
|
||||
// The double argument version is usually easier to use, and it is more powerful because it supports
|
||||
// alignment. You provide an anchor on the parent `from` and an anchor on the child `to`.
|
||||
// This connects the `to` anchor on the child to the `from` anchor on the parent.
|
||||
// alignment. You provide an anchor on the parent `parent` and an anchor on the child `child`.
|
||||
// This connects the `child` anchor on the child to the `parent` anchor on the parent.
|
||||
// They are connected to the parent by pointing their anchor arrows at each other. The most basic case
|
||||
// is `attach(TOP,BOT)` which puts the bottom of the child onto the top of the parent. If you
|
||||
// do `attach(RIGHT,BOT)` this puts the bottom of the child onto the right anchor of the parent.
|
||||
|
@ -767,7 +767,7 @@ function _make_anchor_legal(anchor,geom) =
|
|||
// ignored with the **double argument** version of `attach()`. As noted above, you can give `spin=` to the
|
||||
// child but using the `spin=` parameter to `attach()` is more likely to be useful.
|
||||
// .
|
||||
// For the single parameter version of `attach()` you give only the `from` anchor. The `align` direction
|
||||
// For the single parameter version of `attach()` you give only the `parent` anchor. The `align` direction
|
||||
// is not permitted. In this case the child is placed at the specified parent anchor point
|
||||
// and rotated to the anchor direction. For example, `attach(TOP) cuboid(2);` will place a small
|
||||
// cube **with its center** located at the TOP anchor of the parent, so just half the cube will project
|
||||
|
@ -786,10 +786,10 @@ function _make_anchor_legal(anchor,geom) =
|
|||
// For a step-by-step explanation of
|
||||
// attachments, see the [Attachments Tutorial](Tutorial-Attachments).
|
||||
// Arguments:
|
||||
// from = The parent anchor point to attach to or a list of parent anchor points.
|
||||
// to = Optional name of the child anchor point. If given, orients the child to connect this anchor point to the parent anchor.
|
||||
// parent = The parent anchor point to attach to or a list of parent anchor points.
|
||||
// child = Optional child anchor point. If given, orients the child to connect this anchor point to the parent anchor.
|
||||
// ---
|
||||
// align = If `to` is given you can specify alignment to shift the child to an edge or corner of the parent.
|
||||
// align = If `child` is given you can specify alignment to shift the child to an edge or corner of the parent.
|
||||
// overlap = Amount to sink child into the parent. Equivalent to `down(X)` after the attach. This defaults to the value in `$overlap`, which is `0` by default.
|
||||
// spin = Amount to rotate the parent around the axis of the parent anchor.
|
||||
// Side Effects:
|
||||
|
@ -803,45 +803,57 @@ function _make_anchor_legal(anchor,geom) =
|
|||
// attach(FRONT, BOTTOM, overlap=1.5) cyl(l=11.5, d1=10, d2=5);
|
||||
// }
|
||||
|
||||
module attach(from, to, overlap, align, spin=0, norot)
|
||||
module attach(parent, child, overlap, align, spin=0, norot, from, to)
|
||||
{
|
||||
req_children($children);
|
||||
dummy3=
|
||||
assert(num_defined([to,child])<2, "Cannot combine deprecated 'to' argument with 'child' parameter")
|
||||
assert(num_defined([from,parent])<2, "Cannot combine deprecated 'from' argument with 'parent' parameter");
|
||||
if (is_def(to))
|
||||
echo("The 'to' option to attach() is deprecated and will be removed in the future. Use 'child' instead.");
|
||||
if (is_def(from))
|
||||
echo("The 'from' option to attach(0 is deprecated and will be removed in the future. Use 'parent' instead");
|
||||
if (norot)
|
||||
echo("The 'norot' option to attach() is deprecated and will be removed in the future. Use position() instead.");
|
||||
req_children($children);
|
||||
|
||||
dummy=assert($parent_geom != undef, "No object to attach to!")
|
||||
assert(is_undef(align) || (is_vector(align) && (len(align)==2 || len(align)==3)), "align must be a 2-vector or 3-vector")
|
||||
assert(is_undef(to) || is_string(to) || (is_vector(to) && (len(to)==2 || len(to)==3)), "to must be a named anchor (a string) or a 2-vector or 3-vector")
|
||||
assert(is_undef(align) || !is_string(to), "to is a named anchor. Named anchors are not supported with align=");
|
||||
assert(is_undef(child) || is_string(child) || (is_vector(child) && (len(child)==2 || len(child)==3)), "child must be a named anchor (a string) or a 2-vector or 3-vector")
|
||||
assert(is_undef(align) || !is_string(child), "child is a named anchor. Named anchors are not supported with align=");
|
||||
overlap = (overlap!=undef)? overlap : $overlap;
|
||||
anchors = (is_vector(from)||is_string(from))? [from] : from;
|
||||
anchors = (is_vector(parent)||is_string(parent))? [parent] : parent;
|
||||
two_d = _attach_geom_2d($parent_geom);
|
||||
to = two_d ? _force_anchor_2d(to) : to;
|
||||
parent = one_defined([parent,from],"parent,from");
|
||||
dummy4 = assert(is_string(parent) || is_list(parent), "Invalid parent anchor or anchor list");
|
||||
child = two_d ? _force_anchor_2d(child) : child;
|
||||
align = is_undef(align) ? undef
|
||||
: two_d ? _force_anchor_2d(align) : point3d(align);
|
||||
dummy2=assert(is_undef(align) || is_def(to), "Cannot use 'align' without 'to'");
|
||||
dummy2=assert(is_undef(align) || is_def(child), "Cannot use 'align' without 'child'");
|
||||
for ($idx = idx(anchors)) {
|
||||
dummy2=
|
||||
assert(is_string(anchors[$idx]) || (is_vector(anchors[$idx]) && (len(anchors[$idx])==2 || len(anchors[$idx])==3)),
|
||||
str("from[",$idx,"] is ",anchors[$idx]," but it must be a named anchor (string) or a 2-vector or 3-vector"))
|
||||
str("parent[",$idx,"] is ",anchors[$idx]," but it must be a named anchor (string) or a 2-vector or 3-vector"))
|
||||
assert(is_undef(align) || !is_string(anchors[$idx]),
|
||||
str("from[",$idx,"] is a named anchor (",anchors[$idx],"), but named anchors are not wupported with align="));
|
||||
str("parent[",$idx,"] is a named anchor (",anchors[$idx],"), but named anchors are not wupported with align="));
|
||||
anchr = is_string(anchors[$idx])? anchors[$idx]
|
||||
: two_d?_force_anchor_2d(anchors[$idx])
|
||||
:anchors[$idx];
|
||||
dummy=assert(is_undef(align) || all_zero(v_mul(anchr,align)),
|
||||
str("align (",align,") cannot include component parallel to anchor (",anchr,")"));
|
||||
str("align (",align,") cannot include component parallel to parent anchor (",anchr,")"));
|
||||
anch = _find_anchor(anchr, $parent_geom);
|
||||
pos = is_undef(align) ? anch[1] : _find_anchor(anchr+align, $parent_geom)[1];
|
||||
$attach_to = to;
|
||||
$attach_to = child;
|
||||
$attach_anchor = list_set(anch, 1, pos); ///
|
||||
startdir = anchr==UP || anchr==DOWN ? BACK : UP;
|
||||
enddir = is_undef(to) || to.z==0 ? UP : BACK;
|
||||
enddir = is_undef(child) || child.z==0 ? UP : BACK;
|
||||
anchor_adjustment = is_undef(align)? CTR
|
||||
: two_d ? zrot(spin, rot(to=to,from=-anchr,p=align))
|
||||
: zrot(spin,frame_map(x=to, z=enddir,p=frame_map(x=-anchr, z=startdir, reverse=true, p=align)));
|
||||
: two_d ? zrot(spin, rot(to=child,from=-anchr,p=align))
|
||||
: apply( frame_map(x=child, z=enddir)
|
||||
*frame_map(x=-anchr, z=startdir, reverse=true)
|
||||
*rot(v=parent,-spin), align);
|
||||
|
||||
$anchor_override=all_zero(anchor_adjustment)?undef
|
||||
:to+anchor_adjustment;
|
||||
:child+anchor_adjustment;
|
||||
olap = two_d? [0,-overlap,0] : [0,0,-overlap];
|
||||
anchrvec = two_d? BACK : UP;
|
||||
spinaxis = two_d? UP : anch[2];
|
||||
|
|
|
@ -2935,7 +2935,7 @@ function onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) =
|
|||
// Usage:
|
||||
// text3d(text, [h], [size], [font], [language=], [script=], [direction=], [atype=], [anchor=], [spin=], [orient=]);
|
||||
// Description:
|
||||
// Creates a 3D text block that supports anchoring and attachment to attachable objects. You cannot attach children to text.
|
||||
// Creates a 3D text block that supports anchoring and single-parameter attachment to attachable objects. You cannot attach children to text.
|
||||
// .
|
||||
// Historically fonts were specified by their "body size", the height of the metal body
|
||||
// on which the glyphs were cast. This means the size was an upper bound on the size
|
||||
|
@ -2988,6 +2988,7 @@ module text3d(text, h, size=10, font="Helvetica", spacing=1.0, direction="ltr",
|
|||
h = one_defined([h,height,thickness],"h,height,thickness",dflt=1);
|
||||
assert(is_undef(atype) || in_list(atype,["ycenter","baseline"]), "atype must be \"ycenter\" or \"baseline\"");
|
||||
assert(is_bool(center));
|
||||
assert(is_undef($attach_to),"text3d() does not support parent-child anchor attachment with two parameters");
|
||||
atype = default(atype, center?"ycenter":"baseline");
|
||||
anchor = default(anchor, center?CENTER:LEFT);
|
||||
geom = attach_geom(size=[size,size,h]);
|
||||
|
|
|
@ -389,7 +389,7 @@ square(10)
|
|||
|
||||
When positioning an object near an edge or corner you may wish to
|
||||
orient the object relative to some face other than the TOP face that
|
||||
meets at that edge or corner. You can always apply a `rotation()` to
|
||||
meets at that edge or corner. You can always apply `rot()` to
|
||||
change the orientation of the child object, but in order to do this,
|
||||
you need to figure out the correct rotation. The `orient()` module provides a
|
||||
mechanism for re-orienting the child() that eases this burden:
|
||||
|
@ -594,7 +594,8 @@ cyl(h=20,d=10,$fn=128)
|
|||
|
||||
Attachables get their name from their ability to be attached to each
|
||||
other. Unlike with positioning, attaching changes the orientation of
|
||||
the child object. When you attach an object, it appears on the parent
|
||||
the child object. Think of it like sticking two objects together:
|
||||
when you attach an object, it appears on the parent
|
||||
relative to the local coordinate system of the parent at the anchor point. To understand
|
||||
what this means, imagine the perspective of an ant walking on a
|
||||
sphere. The meaning of UP varies depending on where on the sphere the
|
||||
|
@ -683,137 +684,54 @@ cylinder(h=100, d=100, center=true)
|
|||
show_anchors(s=30);
|
||||
```
|
||||
|
||||
## Basic Attachment
|
||||
## Parent-Child Anchor Attachment (Double Argument Attachment)
|
||||
|
||||
The simplest form of attachment is to attach using the `attach()`
|
||||
module with a single argument, which specifies the anchor on the parent
|
||||
where the child will attach. This will attach the bottom of the child
|
||||
to the given anchor point on the parent. The child appears on the parent with its
|
||||
Z direction aligned parallel to the parent's anchor direction, and
|
||||
its Y direction pointing in the zero spin direction for the
|
||||
parent anchor. The anchor direction of the child does not affect the result in this
|
||||
case.
|
||||
The `attach()` module has two different modes of operation,
|
||||
parent-child anchor attachment and parent anchor attachment. These
|
||||
are also called double argument attachment and single argument
|
||||
attachment. The parent-child anchor attachment, with two arguments,
|
||||
is usually easier to use and is more powerful because it supports
|
||||
alignment. When you use parent-child anchor attachment you give a
|
||||
parent anchor and a child anchor. Imagine pointing the anchor arrows
|
||||
on the two objects directly at each other and pushing them together in
|
||||
the direction of the arrows until they touch. In many of the examples
|
||||
below we show first the two objects with their anchor arrows and then
|
||||
the result of the attach operation using those anchors.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(RIGHT)cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(RIGHT+TOP)cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
In the second example, the child object points diagonally away
|
||||
from the cube. If you want the child at at edge of the parent it's
|
||||
likely that this result will not be what you want. To get a different
|
||||
result, use `position()` with `orient()`, if needed.
|
||||
|
||||
If you give an anchor point to the child object it moves the child
|
||||
around (in the attached coordinate system). Or alternatively you can
|
||||
think that it moves the object first, and then it gets attached.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(RIGHT)cylinder(d1=30,d2=15,h=25,anchor=FRONT);
|
||||
```
|
||||
|
||||
In the above example we anchor the child to its FRONT and then attach
|
||||
it to the RIGHT. An ambiguity exists regarding the spin of the
|
||||
parent's coordinate system. How is this resolved? The small flags
|
||||
on the anchor arrows show the position of zero spin by pointing
|
||||
towards the local Y+ direction, which is also the BACK direction of the child. For the above
|
||||
cube, the arrow looks like this:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(RIGHT)anchor_arrow(30);
|
||||
```
|
||||
|
||||
The red flag points up, which explains why the attached cylinder
|
||||
appeared above the anchor point. The CENTER anchor generally has a
|
||||
direction that points upward, so an attached object will keep its
|
||||
orientation if attached to the CENTER of a parent.
|
||||
|
||||
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, which may be helpful
|
||||
when doing differences.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(TOP,overlap=10)
|
||||
cylinder(d=20,h=20);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(TOP,overlap=-20)
|
||||
cylinder(d=20,h=20);
|
||||
```
|
||||
|
||||
As with `position()`, you can still apply your own translations and
|
||||
other transformations even after attaching an object. However, the
|
||||
order of operations now matters. If you apply a translation outside
|
||||
of the anchor then it acts in the parent's global coordinate system, so the
|
||||
child moves up in this example:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
up(13)
|
||||
attach(RIGHT)
|
||||
cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
On the other hand, if you put the translation between the attach and
|
||||
the object in your code, then it will act in the local coordinate system of
|
||||
the parent at the parent's anchor, so in the example below it moves to the right.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(RIGHT)
|
||||
up(13)
|
||||
cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
|
||||
## Attachment With Parent and Child Anchors
|
||||
|
||||
The `attach()` module can also take a second argument, the child anchor.
|
||||
In this case, the attachment behavior
|
||||
is quite different. The objects are still attached with their anchor
|
||||
points aligned, but the child is reoriented so that its anchor
|
||||
direction is the opposite of the parent anchor direction. It's like
|
||||
you assemble the parts by pushing them together in the direction of
|
||||
their anchor arrows. Two examples appear below, where first we show
|
||||
two objects with their anchors and then we show the result of
|
||||
attaching with those anchors.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,anchor=BOT) attach(TOP) anchor_arrow(30);
|
||||
right(60)cylinder(d1=30,d2=15,h=25) attach(TOP) anchor_arrow(30);
|
||||
cube(50,anchor=BOT) attach(TOP,BOT) anchor_arrow(30);
|
||||
right(60)cylinder(d1=30,d2=15,h=25) attach(BOT,BOT) anchor_arrow(30);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,anchor=BOT)
|
||||
attach(TOP,TOP) cylinder(d1=30,d2=15,h=25);
|
||||
attach(TOP,BOT) cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
This example produces the same result as using `align()`, but if the
|
||||
parent anchor is not horizontal, then the child is reoriented:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
prismoid([50,50],[35,35],h=50,anchor=BOT) attach(RIGHT,BOT) anchor_arrow(30);
|
||||
right(60)cylinder(d1=30,d2=15,h=25) attach(BOT,BOT) anchor_arrow(30);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true) attach(RIGHT) anchor_arrow(30);
|
||||
right(80)cylinder(d1=30,d2=15,h=25) attach(LEFT) anchor_arrow(30);
|
||||
prismoid([50,50],[35,35],h=50,anchor=BOT)
|
||||
attach(RIGHT,BOT) ylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
In this case we attach the curved side of the cone to a cube by lining
|
||||
up the anchor arrows:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true) attach(RIGHT,BOT) anchor_arrow(30);
|
||||
right(80)cylinder(d1=30,d2=15,h=25) attach(LEFT,BOT) anchor_arrow(30);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
|
@ -822,10 +740,154 @@ cube(50,center=true)
|
|||
attach(RIGHT,LEFT) cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
Note that when you attach with two anchors like this, the attachment
|
||||
operation **overrides any anchor or orientation specified in the
|
||||
child**. That means the child's `anchor=` and `orient=` options are
|
||||
ignored.
|
||||
Note that this form of attachent overrides any anchor or orientation
|
||||
specified in the child: **with parent-child anchor attachment the
|
||||
`anchor=` and `orient=` parameters to the child are ignored.**
|
||||
|
||||
When you specify attachment using a pair of anchors, the attached
|
||||
child can spin around the parent anchor while still being attached.
|
||||
As noted earlier, this ambiguity is resolved by anchors having a
|
||||
defined spin which specifies where the Y+ axis is located.
|
||||
The way that BOSL2 positions objects can be understood by viewing the
|
||||
anchor arrows as shown above, or you can remember these rules:
|
||||
1. When attaching to the TOP or BOTTOM the FRONT of the child points to the front if possible; otherwise the TOP of the child points BACK.
|
||||
2. When attaching to other faces, if possible the child's UP anchor will point UP; otherwise, the BACK of the child points up (so the FRONT is pointed down).
|
||||
To show how this works we use this prismoid where the blue arrow is
|
||||
pointing to the front and the green arrow points up. Also note that
|
||||
the front left edge is the only right angle.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
If we attach this to the TOP by the LEFT side then we get the result
|
||||
below. Notice how the green UP arrow is pointing back.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30) attach(TOP,LEFT)
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
If we attach to the RIGHT using the same LEFT side anchor on the
|
||||
prismoid then we get the result below. Note that the green UP anchor
|
||||
is pointing (approximately) UP, in accordance with rule 2 from above.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30) attach(TOP,LEFT)
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
The green UP arrow can always be arranged to point up unless we attach
|
||||
either the top or bottom to one of the cube's vertical faces. Here we
|
||||
attach the bottom so you can still see both arrows. The blue FRONT
|
||||
arrow on the object is pointing down, as expected based on rule 2.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30) attach(RIGHT,BOT)
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
What do you do if the direction the child appears is not the direction
|
||||
you need? To address this issue `attach()` provides a `spin=`
|
||||
parameter which spins the attached child around the axis defined by
|
||||
the joined anchor vectors. Here is the last example with a rotation
|
||||
applied to bring the front anchor back to the front:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30) attach(RIGHT,BOT,spin=-90)
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
Be aware that specifying `spin=` to `attach()` is not equivalent to
|
||||
using the `spin=` argument to the child. Unlike `orient=` and
|
||||
`anchor=`, which are ignored, the child `spin=` argument is still
|
||||
respected, but it may be difficult to figure out which axis it will
|
||||
rotate on. It is more intuitive to ignore the child spin parameter
|
||||
and only use the spin parameter to `attach()`. The spin must be
|
||||
scalar but need not be a multiple of 90 degrees.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30) attach(RIGHT,BOT,spin=-37)
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
```
|
||||
|
||||
The last feature provided by the double argument form of `attach()` is
|
||||
alignment, which works in a similar way to `align()`. You can specify
|
||||
`align=` to align the attached child to an edge or corner. The
|
||||
example below shows five different alignments.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
module thing(){
|
||||
color_this("orange")
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8) {
|
||||
attach(TOP,BOT) anchor_arrow(color=[0,1,0],s=12);
|
||||
attach(FWD,BOT) anchor_arrow(s=12);
|
||||
}
|
||||
}
|
||||
prismoid([50,50],[35,35],h=25,anchor=BOT){
|
||||
attach(TOP,BOT,align=FRONT) thing();
|
||||
attach(RIGHT,BOT,align=BOT) thing();
|
||||
attach(RIGHT,BACK,align=FRONT) thing();
|
||||
attach(FRONT,BACK,align=BOT,spin=45) thing();
|
||||
attach(TOP,RIGHT,align=RIGHT,spin=90) thing();
|
||||
}
|
||||
```
|
||||
|
||||
As with `align()` if you turn an object 90 degrees it can match up
|
||||
with parallel edges, but if you turn it an arbitrary angle, a corner
|
||||
of the child will contact the edge of the parent. Also like align()
|
||||
the anchor points of the parent and child are aligned but this does
|
||||
not necessarily mean that edges line up neatly when the shapes have
|
||||
varying angles. This misalignment is visible in the object attached
|
||||
at the RIGHT and aligned to the FRONT.
|
||||
|
||||
You may be wondering why all this fuss with align is necessary.
|
||||
Couldn't you just attach an object at an anchor on an edge? When you
|
||||
do this, the object will be attached using the edge anchor, which is
|
||||
not perpendicular to the faces of the object. The example below shows
|
||||
attachment to an edge anchor and also a corner anchor.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30)
|
||||
color("orange"){
|
||||
attach(RIGHT+FRONT,BOT)
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8);
|
||||
attach(TOP+LEFT+FWD,BOT)
|
||||
prismoid([8,8],[6,6],shift=-[1,1],h=8);
|
||||
}
|
||||
```
|
||||
|
||||
Attachment with CENTER anchors can be surprising because the anchors
|
||||
point upwards, so in the example below, the child's CENTER anchor
|
||||
|
@ -846,6 +908,155 @@ cylinder(d1=30,d2=15,h=25)
|
|||
cylinder(d1=30,d2=15,h=25);
|
||||
```
|
||||
|
||||
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 translating it into the parent. You can do this with the
|
||||
`overlap=` argument to `attach()`. A positive value will cause the
|
||||
child to overlap the parent, and a negative value will move the child
|
||||
away from the parent, leaving a small gap, which may be helpful when
|
||||
doing differences. In the first example we use a very large value of
|
||||
overlap so the cube is sunk deeply into the parent. In the second
|
||||
example a large negative overlap value raises the child high above the
|
||||
parent.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(50)
|
||||
attach(TOP,BOT,overlap=15)
|
||||
color("green")cuboid(20);
|
||||
```
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(50,center=true)
|
||||
attach(TOP,BOT,overlap=-20)
|
||||
cyl(d=20,h=20);
|
||||
```
|
||||
|
||||
As with `position()`, you can still apply your own translations and
|
||||
other transformations even after attaching an object. However, the
|
||||
order of operations now matters. If you apply a translation outside
|
||||
of the anchor then it acts in the parent's global coordinate system, so the
|
||||
child moves up in this example, where the light gray shows the
|
||||
untranslated object.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(50){
|
||||
%attach(RIGHT,BOT)
|
||||
cyl(d1=30,d2=15,h=25);
|
||||
up(13)
|
||||
color("green") attach(RIGHT,BOT)
|
||||
cyl(d1=30,d2=15,h=25);
|
||||
}
|
||||
```
|
||||
|
||||
On the other hand, if you put the translation between the attach and
|
||||
the object in your code, then it will act in the local coordinate system of
|
||||
the parent at the parent's anchor, so in the example below it moves to the right.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(50){
|
||||
%attach(RIGHT,BOT)
|
||||
cyl(d1=30,d2=15,h=25);
|
||||
color("green") attach(RIGHT,BOT)
|
||||
up(13)
|
||||
cyl(d1=30,d2=15,h=25);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Parent Anchor Attachment (Single Argument Attachment)
|
||||
|
||||
The second form of attachment is parent anchor attachment, which just
|
||||
uses a single argument. This form of attachment is less useful in
|
||||
general and does not provide alignment. When you give `attach()` a parent anchor but no child anchor it
|
||||
orients the child according to the pafrent anchor direction but then
|
||||
simply places the child based on its internally defined anchor at the
|
||||
parent anchor position. For most objects the default anchor is the
|
||||
CENTER anchor, so objects will appear sunk half-way into the parent.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(30)
|
||||
attach(TOP)
|
||||
color("green")cuboid(10);
|
||||
```
|
||||
|
||||
Some objects such as `cylinder()`, `prismoid()`, and `anchor_arrow()` have default anchors on the bottom, so they will appear
|
||||
on the surface. For objects like this you can save a little bit of
|
||||
typing by using parent anchor attachment. But in the case of `cube()`
|
||||
the anchor is not centered, so the result is:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cube(30)
|
||||
attach(TOP)
|
||||
color("green")cube(10);
|
||||
```
|
||||
|
||||
In order to make single argument attachment produce the results you
|
||||
need you will probably need to change the child anchor. Note that unlike
|
||||
parent-child anchor attachment, **with parent anchor attachment the `anchor=` and `orient=` arguments
|
||||
are respected.** We could therefore place a cuboid like this:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(30)
|
||||
attach(RIGHT)
|
||||
color("green")cuboid(10,anchor=BOT);
|
||||
```
|
||||
|
||||
If you need to place a cuboid at the anchor point but need it anchored
|
||||
relative to one of the bottom edge or corner anchors then you can do
|
||||
that with parent anchor attachment:
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(30)
|
||||
attach(RIGHT)
|
||||
color("green")cuboid(10,anchor=BOT+FWD);
|
||||
```
|
||||
|
||||
Another case where single argument attachment is useful is when the
|
||||
child doesn't have proper attachment support.
|
||||
If you use double argument attachment in such cases the results will
|
||||
be incorrect because the child doesn't properly respond to the
|
||||
internally propagated anchor directives. With single argument
|
||||
attachment, this is not a problem: the origin
|
||||
of the child will be placed at the parent anchor point. One module
|
||||
without attachment support is `linear_extrude()`.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(20)
|
||||
attach(RIGHT)
|
||||
color("red")linear_extrude(height=2) star(n=7,ir=3,or=7);
|
||||
```
|
||||
|
||||
As noted earlier, you can set `orient=` for children with parent
|
||||
anchor attachment, though the behavior may not be intuitive because
|
||||
the attachment process transforms the coordinate system and the
|
||||
orientation is done in the attached coordinate system. It may be
|
||||
helpful to start with the object attached to TOP and recall the rules
|
||||
from the previous section about how orientation works. The same rules
|
||||
apply here. Note that the forward arrow is pointing down after
|
||||
attaching the object on the RIGHT face.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
cuboid(20){
|
||||
attach(RIGHT)
|
||||
color_this("red")cuboid([2,4,8],orient=RIGHT,anchor=RIGHT)
|
||||
attach(FWD) anchor_arrow();
|
||||
attach(TOP)
|
||||
color_this("red")cuboid([2,4,8],orient=RIGHT,anchor=RIGHT)
|
||||
attach(FWD) anchor_arrow();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Positioning and Attaching Multiple Children
|
||||
|
||||
|
|
Loading…
Reference in a new issue