Merge branch 'master' into revarbat_dev

This commit is contained in:
Revar Desmera 2023-06-17 22:42:18 -07:00
commit e64904dc46
3 changed files with 250 additions and 18 deletions

View file

@ -21,6 +21,7 @@ $overlap = 0;
$color = "default";
$save_color = undef; // Saved color to revert back for children
$anchor_override = undef;
$attach_to = undef;
$attach_anchor = [CENTER, CENTER, UP, 0];
$attach_norot = false;
@ -487,8 +488,9 @@ _ANCHOR_TYPES = ["intersect","hull"];
module position(from)
{
req_children($children);
assert($parent_geom != undef, "No object to attach to!");
dummy1=assert($parent_geom != undef, "No object to position relative to.");
anchors = (is_vector(from)||is_string(from))? [from] : from;
two_d = _attach_geom_2d($parent_geom);
for (anchr = anchors) {
anch = _find_anchor(anchr, $parent_geom);
$attach_to = undef;
@ -499,11 +501,12 @@ module position(from)
}
// Module: orient()
// Synopsis: Orients children's tops in the directon of the specified anchor.
// SynTags: Trans
// Topics: Attachments
// See Also: attachable(), attach(), orient()
// See Also: attachable(), attach(), position()
// Usage:
// PARENT() orient(anchor, [spin]) CHILDREN;
// Description:
@ -513,10 +516,8 @@ module position(from)
// anchor = The anchor on the parent which you want to match the orientation of.
// spin = The spin to add to the children. (Overrides anchor spin.)
// Side Effects:
// `$attach_anchor` is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for the `anchor=`, if given.
// `$attach_to` is set to `undef`.
// `$attach_norot` is set to `true`.
//
// Example: When orienting to an anchor, the spin of the anchor may cause confusion:
// prismoid([50,50],[30,30],h=40) {
// position(TOP+RIGHT)
@ -543,16 +544,132 @@ module orient(anchor, spin) {
anch = _find_anchor(anchor, $parent_geom);
two_d = _attach_geom_2d($parent_geom);
fromvec = two_d? BACK : UP;
$attach_to = undef;
$attach_anchor = anch;
$attach_norot = true;
spin = default(spin, anch[3]);
assert(is_finite(spin));
rot(spin, from=fromvec, to=anch[2]) children();
dummy=assert(is_finite(spin));
$attach_to = undef;
$attach_norot = true;
if (two_d)
rot(spin)rot(from=fromvec, to=anch[2]) children();
else
rot(spin, from=fromvec, to=anch[2]) children();
}
// Module: align()
// Synopsis: Position and orient children with alignment to parent edges.
// SynTags: Trans
// Topics: Attachments
// See Also: attachable(), attach(), position(), orient()
// Usage:
// PARENT() align(anchor, [orient], [spin], [inside=]) CHILDREN;
// Description:
// Positions children to the specified anchor(s) on the parent and anchors the
// children so that they are aligned with the edge(s) of the parent at those parent anchors.
// You can specify a parent anchor point in `orient` and in this case, the top of the child
// is tilted in the direction of that anchor.
// This means you can easily place children so they are aligned flush with edges of the parent.
// In contrast, with {{position()}} you will have to work out the correct anchor for the children
// which is not always obvious. It also enables you to place several children that have different
// anchors, which would otherwise require several {{position()}} calls. The inside argument
// causes the object to appear inside the parent for use with {{diff()}}.
// .
// When you use `align()`, the `orient=` and `anchor=` arguments to the child objects are overriden,
// so they do not have any effect. The `spin=` argument to the child still applies.
// Arguments:
// anchor = parent anchor or list of parent anchors for positioning children
// orient = parent anchor to give direction for orienting the children. Default: UP
// spin = spin in degrees for rotating the children. Default: Derived from orient anchor
// ---
// inside = if true, place object inside the parent instead of outside. Default: false
// Side Effects:
// `$attach_anchor` for each anchor given, this is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
// `$attach_to` is set to `undef`.
// `$attach_norot` is set to `true`.
// if inside is true then set default tag to "remove"
// Example: Child would require anchor of RIGHT+FRONT+BOT if placed with {{position()}}.
// cuboid([50,40,15])
// align(RIGHT+FRONT+TOP)
// color("lightblue")prismoid([10,5],[7,4],height=4);
// Example: Child requires a different anchor for each position, so explicit specification of the anchor for children is impossible in this case, without using two separate commands.
// cuboid([50,40,15])
// align([RIGHT+TOP,LEFT+TOP])
// color("lightblue")prismoid([10,5],[7,4],height=4);
// Example: If you try to spin your child, the spin happens after the alignment anchor, so the child will not be flush:
// cuboid([50,40,15])
// align([RIGHT+TOP])
// color("lightblue")
// prismoid([10,5],[7,4],height=4,spin=90);
// Example: You can instead spin the attached children using the spin parameter to `align()`. In this example, the required anchor is BOT+FWD, which is less obvious.
// cuboid([50,40,15])
// align(RIGHT+TOP,spin=90)
// color("lightblue")prismoid([10,5],[7,4],height=4);
// Example: Here the child is oriented to the RIGHT, so it appears flush with the top. In this case you don't have to figure out that the required child anchor is BOT+BACK.
// cuboid([50,40,15])
// align(RIGHT+TOP,RIGHT)
// color("lightblue")prismoid([10,5],[7,4],height=4);
// Example: If you change the orientation the child still appears aligned flush in its changed orientation:
// cuboid([50,40,15])
// align(RIGHT+TOP,DOWN)
// color("lightblue")prismoid([10,5],[7,4],height=4);
// Example: Objects on the right already have nonzero spin by default, so setting spin=0 changes the spin:
// prismoid(50,30,25){
// align(RIGHT+TOP,RIGHT,spin=0)
// color("lightblue")prismoid([10,5],[7,4],height=4);
// align(RIGHT+BOT,RIGHT)
// color("green")prismoid([10,5],[7,4],height=4);
// }
// Example: Setting inside=true enables us to subtract the child from the parent with {{diff()}. The "remove" tag is automatically applied when you set `inside=true`.
// diff()
// cuboid([40,30,10])
// move(.1*[0,-1,1])
// align(FRONT+TOP,inside=true)
// prismoid([10,5],[7,5],height=4);
module align(anchor,orient=UP,spin,inside=false)
{
req_children($children);
dummy1=assert($parent_geom != undef, "No object to align to.")
assert(is_string(orient) || is_vector(orient),"Bad orient value");
position_anchors = (is_vector(anchor)||is_string(anchor))? [anchor] : anchor;
two_d = _attach_geom_2d($parent_geom);
fromvec = two_d? BACK : UP;
orient_anch = _find_anchor(orient, $parent_geom);
spin = default(spin, orient_anch[3]);
dummy2=assert(is_finite(spin));
$attach_to = undef;
$attach_norot = true;
factor = inside?1:-1;
for (thisanch = position_anchors) {
pos_anch = _find_anchor(thisanch, $parent_geom);
init_anch = two_d ? rot(from=orient_anch[2], to=fromvec, p=zrot(-spin,pos_anch[0]))
: rot(spin, from=fromvec, to=orient_anch[2], reverse=true, p=pos_anch[0]);
quant_anch = [for(v=init_anch) sign(round(v))];
$anchor_override = two_d && quant_anch.y!=0 ? [quant_anch.x,factor*quant_anch.y]
: !two_d && quant_anch.z!=0 ? [quant_anch.x,quant_anch.y, factor*quant_anch.z]
: factor*quant_anch;
$attach_anchor = pos_anch;
translate(pos_anch[1]) {
if (two_d)
rot(spin)rot(from=fromvec, to=orient_anch[2])
if (inside) default_tag("remove") children();
else children();
else
rot(spin, from=fromvec, to=orient_anch[2])
if (inside) default_tag("remove") children();
else children();
}
}
}
// Module: attach()
// Synopsis: Attaches children to a parent object at an anchor point and orientation.
// SynTags: Trans
@ -2358,9 +2475,9 @@ module attachable(
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Got: ",anchor))
assert(is_undef(spin) || is_vector(spin,3) || is_num(spin), str("Got: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient));
anchor = default(anchor, CENTER);
anchor = first_defined([$anchor_override, anchor, CENTER]);
spin = default(spin, 0);
orient = default(orient, UP);
orient = is_def($anchor_override)? UP : default(orient, UP);
region = !is_undef(region)? region :
!is_undef(path)? [path] :
undef;
@ -2381,6 +2498,7 @@ module attachable(
$parent_geom = geom;
$parent_size = _attach_geom_size(geom);
$attach_to = undef;
$anchor_override=undef;
if (_is_shown())
_color($color) children(0);
if (is_def($save_color)) {
@ -2959,6 +3077,7 @@ function _attach_transform(anchor, spin, orient, geom, p) =
assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient))
let(
anchor = default(anchor, CENTER),
spin = default(spin, 0),
orient = default(orient, UP),
two_d = _attach_geom_2d(geom),

View file

@ -23,22 +23,33 @@ include <screw_drive.scad>
// including tolerances for screw fit. You can also create screws with
// various head types and drive types that should match standard hardware.
// Subsection: Screw Naming
// You can specify screws using a string that specifies the screw.
// For ISO (metric) screws the specification has the form: "M`<size>`x`<pitch>`,`<length>`,
// You can specify screws using a string that specifies the screw.
// Metric or ISO screws are specified by a diameter in millimeters and a thread pitch in millimeters. For example,
// an M8x2 screw has a nominal diameter of 8 mm and a thread pitch of 2 mm.
// The screw specification for these screws has the form: "M`<size>`x`<pitch>`,`<length>`,
// so "M6x1,10" specifies a 6mm diameter screw with a thread pitch of 1mm and length of 10mm.
// You can omit the pitch or length, e.g. "M6x1", or "M6,10", or just "M6".
// You can omit the pitch or length, e.g. "M6x1", or "M6,10", or just "M6". If you omit the
// length then you must provide the `length` parameter. If you omit the pitch, the library
// provides a standard pitch for the specified diameter.
// .
// For UTS (English) screws the specification has the form `<size>`-`<threadcount>`,`<length>`, e.g.
// Imperial or UTS screws are specified by a diameter and the number of threads per inch.
// For large screws, the diameter is simply the nominal diameter in inches, so a 5/16-18 screw
// has a nominal diameter of 5/16 inches and 18 threads per inch. For diameters smaller than
// 1/4 inch, the screw diameter is given using a screw gauge, which can be from 0 up to 12.
// A common smaller size is #8-32, an 8 gauge screw with 32 threads per inch.
// For UTS screws the specification has the form `<size>`-`<threadcount>`,`<length>`, e.g.
// "#8-32,1/2", or "1/4-20,1". The units are in inches, including the length. Size can be a
// number from 0 to 12 with or without a leading # to specify a screw gauge size, or any other
// gauge number from 0 to 12 with or without a leading # to specify a screw gauge size, or any other
// value to specify a diameter in inches, either as a float or a fraction, so "0.5-13" and
// "1/2-13" are equivalent. To force interpretation of the value as inches add '' (two
// single-quotes) to the end, e.g. "1''-4" is a one inch screw and "1-80" is a very small
// 1-gauge screw. The pitch is specified using a thread count, the number of threads per inch.
// As with the ISO screws, you can omit the pitch or length and specify "#6-32", "#6,3/4", or simply #6.
// As in the metric case, if you omit the length then you must provide the `length` parameter. If you omit the pitch, the
// library provides a standard pitch for the specified diameter.
// Subsection: Standard Screw Pitch
// If you omit the pitch when specifying a screw or nut then the library supplies a standard screw pitch based
// on the screw diameter. For each screw diameter, multiple standard pitches are possible.
// on the screw diameter as listed in ISO 724 or ASME B1.1. For many diameters, multiple standard pitches exist.
// The available thread pitch types are different for ISO and UTS:
// .
// | ISO | UTS |
@ -2185,6 +2196,7 @@ function _screw_info_english(diam, threadcount, head, thread, drive) =
tentry = struct_val(UTS_thread, diam)
)
assert(is_def(tentry), str("Unknown screw size, \"",diam,"\""))
assert(is_def(tentry[tind]), str("No ",thread," pitch known for screw size, \"",diam,"\""))
INCH / tentry[tind],
head_data =
head=="none" ? let (
@ -2614,8 +2626,10 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
],
tentry = struct_val(ISO_thread, diam)
)
assert(is_def(tentry), str("Unknown screw size, M",diam,""))
assert(is_def(tentry), str("Unknown screw size, M",diam))
assert(is_def(tentry[tind]), str("No ",thread," pitch known for M",diam))
tentry[tind],
head_data =
head=="none" ? let(
metric_setscrew =

View file

@ -376,6 +376,7 @@ cube([50,50,20],center=true)
```
Positioning objects works the same way in 2D.
```openscad-2D
@ -464,6 +465,104 @@ prismoid([50,50],[30,30],h=40)
```
## Aligning children with align()
You may have noticed that with position() and orient(), specifying the
child anchors to position objects flush with their parent can be
annoying, or sometimes even tricky. You can simplify this task by
using the align() module. This module positions children at specified
anchor points on the parent while picking the correct anchor points on
the children so that they line up with faces on the parent object.
In the simplest case, if you want to place a child on the RIGHT side
of its parent, you need to anchor the child to its LEFT anchor:
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
position(RIGHT)
color("lightblue")cuboid(5,anchor=LEFT);
```
Using align(), the determination of the anchor is automatic. Any
anchor you do specify is ignored.
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT)
color("lightblue")cuboid(5);
```
To place the child on top of the parent in the corner you can do use
align as shown below instead of specifying the RIGHT+FRONT+BOT anchor
with position():
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT+FRONT+TOP)
color("lightblue")prismoid([10,5],[7,4],height=4);
```
Both position() and align() can accept a list of anchor locations and
makes several copies of the children, but
if you want the children positioned flush, each copy
requires a different anchor, so it is impossible to do this with a
singlke call to position(), but easily done using align():
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align([RIGHT+TOP,LEFT+TOP])
color("lightblue")prismoid([10,5],[7,4],height=4);
```
Align also accepts a spin argument, which lets you spin the child
while still aligning it:
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT+TOP,spin=90)
color("lightblue")prismoid([10,5],[7,4],height=4);
```
Note that this is different than using the spin argument to the child
object, which will apply after alignment has been done.
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT+TOP)
color("lightblue")prismoid([10,5],[7,4],height=4,spin=90);
```
If you orient the object DOWN it will be attached from its top anchor:
```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT+TOP,DOWN)
color("lightblue")prismoid([10,5],[7,4],height=4);
```
When placing children on the RIGHT and LEFT, there is a spin applied.
This means that setting spin=0 changes the orientation. Here we have
one object with the default and one object with zero spin:
```openscad-3D
include<BOSL2/std.scad>
prismoid(50,30,25){
align(RIGHT+TOP,RIGHT,spin=0)
color("lightblue")prismoid([10,5],[7,4],height=4);
align(RIGHT+BOT,RIGHT)
color("green")prismoid([10,5],[7,4],height=4);
}
```
## Attachment overview
Attachables get their name from their ability to be attached to each