add position $align

This commit is contained in:
Adrian Mariano 2023-06-16 18:27:15 -04:00
parent 4a4f871ae8
commit dcfbdfdc71
2 changed files with 3596 additions and 3499 deletions

View File

@ -477,22 +477,57 @@ _ANCHOR_TYPES = ["intersect","hull"];
// `$attach_anchor` for each `from=` anchor given, this is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor. // `$attach_anchor` for each `from=` anchor given, this is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
// `$attach_to` is set to `undef`. // `$attach_to` is set to `undef`.
// `$attach_norot` is set to `true`. // `$attach_norot` is set to `true`.
// `$align` set to the anchor that will position a child flush to the edge of the parent at specified position.
// Example: // Example:
// spheroid(d=20) { // spheroid(d=20) {
// position(TOP) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); // position(TOP) cyl(l=10, d1=10, d2=5, anchor=BOTTOM);
// position(RIGHT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); // position(RIGHT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM);
// position(FRONT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); // position(FRONT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM);
// } // }
// Example: Child would require anchor of RIGHT+FRONT+BOT if given explicitly.
// cuboid([50,40,15])
// position(RIGHT+FRONT+TOP)
// color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
// Example: Child requires a different anchor for each position, so explicit specification of the anchor is impossible in this case.
// cuboid([50,40,15])
// position([RIGHT+TOP,LEFT+TOP])
// color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
// Example: If you try to spin your child, the spin happens after the position anchor, so the child will not be flush:
// cuboid([50,40,15])
// position([RIGHT+TOP])
// color("lightblue")prismoid([10,5],[7,4],height=4,
// anchor=$align, spin=90);
// Example: You can instead spin the attached children using {{orient()}}. In this example, the required anchor is BOT+FWD, which is less obvious.
// cuboid([50,40,15])
// position(RIGHT+TOP)
// orient(TOP, spin=90)
// color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
// Example: Of course, {{orient()}} can also place children on different sides of the parent. In this case you don't have to figure out that the required anchor is BOT+BACK.
// cuboid([50,40,15])
// position(RIGHT+TOP)
// orient(RIGHT)
// color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
// Example: You can combine this with {{diff()}} to remove the child. Note that it's more intuitive to shift the child after positioning, relative to the global coordinate system:
// diff()
// cuboid([50,40,15])
// right(.1)up(.1)
// position(RIGHT+TOP)
// orient(LEFT)
// tag("remove")cuboid([10,5,4], anchor=$align);
module position(from) module position(from)
{ {
req_children($children); req_children($children);
assert($parent_geom != undef, "No object to attach to!"); assert($parent_geom != undef, "No object to attach to!");
anchors = (is_vector(from)||is_string(from))? [from] : from; anchors = (is_vector(from)||is_string(from))? [from] : from;
two_d = _attach_geom_2d($parent_geom);
for (anchr = anchors) { for (anchr = anchors) {
anch = _find_anchor(anchr, $parent_geom); anch = _find_anchor(anchr, $parent_geom);
$attach_to = undef; $attach_to = undef;
$attach_anchor = anch; $attach_anchor = anch;
$attach_norot = true; $attach_norot = true;
$align=two_d && anchr.y!=0 ? [anchr.x,-anchr.y]
:!two_d && anchr.z!=0 ? [anchr.x, anchr.y, -anchr.z]
: -anchr;
translate(anch[1]) children(); translate(anch[1]) children();
} }
} }
@ -506,6 +541,8 @@ module position(from)
// PARENT() orient(anchor, [spin]) CHILDREN; // PARENT() orient(anchor, [spin]) CHILDREN;
// Description: // Description:
// Orients children such that their top is tilted in the direction of the specified parent anchor point. // Orients children such that their top is tilted in the direction of the specified parent anchor point.
// The `$align` variable can help you anchor the child, aligned with the edges of the parent, based
// on the position specified by a parent {{position()}} module. See {{position()}} for examples using `$align`.
// For a step-by-step explanation of attachments, see the [Attachments Tutorial](Tutorial-Attachments). // For a step-by-step explanation of attachments, see the [Attachments Tutorial](Tutorial-Attachments).
// Arguments: // Arguments:
// anchor = The anchor on the parent which you want to match the orientation of. // anchor = The anchor on the parent which you want to match the orientation of.
@ -514,6 +551,7 @@ module position(from)
// `$attach_anchor` is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for the `anchor=`, if given. // `$attach_anchor` is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for the `anchor=`, if given.
// `$attach_to` is set to `undef`. // `$attach_to` is set to `undef`.
// `$attach_norot` is set to `true`. // `$attach_norot` is set to `true`.
// `$align` is set to the anchor that will position the child flush on the parent at a designated {{position()}}
// //
// Example: When orienting to an anchor, the spin of the anchor may cause confusion: // Example: When orienting to an anchor, the spin of the anchor may cause confusion:
// prismoid([50,50],[30,30],h=40) { // prismoid([50,50],[30,30],h=40) {
@ -541,16 +579,27 @@ module orient(anchor, spin) {
anch = _find_anchor(anchor, $parent_geom); anch = _find_anchor(anchor, $parent_geom);
two_d = _attach_geom_2d($parent_geom); two_d = _attach_geom_2d($parent_geom);
fromvec = two_d? BACK : UP; fromvec = two_d? BACK : UP;
spin = default(spin, anch[3]);
assert(is_finite(spin));
$align = is_undef($attach_anchor) ? undef
: two_d ? let(newalign=rot(from=anch[2], to=fromvec, p=zrot(-spin,$attach_anchor[0])))
[sign(newalign.x), -1]
: let(newalign=rot(spin, from=fromvec, to=anch[2], reverse=true, p=$attach_anchor[0]))
[sign(newalign.x), sign(newalign.y), -1];
$attach_to = undef; $attach_to = undef;
$attach_anchor = anch; $attach_anchor = anch;
$attach_norot = true; $attach_norot = true;
spin = default(spin, anch[3]); if (two_d)
assert(is_finite(spin)); rot(spin)rot(from=fromvec, to=anch[2]) children();
rot(spin, from=fromvec, to=anch[2]) children(); else
rot(spin, from=fromvec, to=anch[2]) children();
} }
// Module: attach() // Module: attach()
// Synopsis: Attaches children to a parent object at an anchor point and orientation. // Synopsis: Attaches children to a parent object at an anchor point and orientation.
// Topics: Attachments // Topics: Attachments
@ -2011,6 +2060,7 @@ module attachable(
$parent_geom = geom; $parent_geom = geom;
$parent_size = _attach_geom_size(geom); $parent_size = _attach_geom_size(geom);
$attach_to = undef; $attach_to = undef;
$align=undef;
if (_is_shown()) if (_is_shown())
_color($color) children(0); _color($color) children(0);
if (is_def($save_color)) { if (is_def($save_color)) {

View File

@ -375,6 +375,31 @@ cube([50,50,20],center=true)
position(TOP+RIGHT) left(5) cube([4,50,10], anchor=RIGHT+BOT); position(TOP+RIGHT) left(5) cube([4,50,10], anchor=RIGHT+BOT);
``` ```
When you position a child at an edge or corner of a parent object, you very likely
need to change the anchor for the child in a matching way to align the child with the surface and edge
of the parent. You can automate this process by making use of the `$align` special variable, which
is set by `position()`. To align a child with a corner you can do:
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
position(RIGHT+FRONT+TOP)
color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
```
In this example, the `$align` variable replaces the explicit anchor of `RIGHT+FRONT+BOT` that
would be required for this case. The `position()` module can also accept a list of positions,
and it will place a copy of the child at each location. However, if you want to align multiple
children to the parent in different locations, each child needs a different anchor. This can
be achieved using the `$align` variable:
```openscad-3D
cuboid([50,40,15])
position([RIGHT+TOP,LEFT+TOP])
color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
```
Positioning objects works the same way in 2D. Positioning objects works the same way in 2D.
@ -463,6 +488,28 @@ prismoid([50,50],[30,30],h=40)
anchor_arrow(40); anchor_arrow(40);
``` ```
The potential confusion that spin creates for the proper anchoring of children
can be eliminated using the `$align` variable which takes into account the spin
that the `orient()` module applies.
```openscad-3D
cuboid([50,40,15])
position(RIGHT+TOP)
orient(RIGHT)
color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
```
In this case, the correct anchor is chosen to place the child on the right side
with the appropriate anchor taking the spin into account. You can use this method
for children placed on the top by using orient with a TOP direction, but nonzero spin.
```openscad-3D
cuboid([50,40,15])
position(RIGHT+TOP)
orient(TOP, spin=90)
color("lightblue")prismoid([10,5],[7,4],height=4, anchor=$align);
```
## Attachment overview ## Attachment overview