mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
commit
d42ed43674
5 changed files with 79 additions and 85 deletions
100
attachments.scad
100
attachments.scad
|
@ -429,73 +429,51 @@ module position(from)
|
|||
|
||||
// Module: orient()
|
||||
// Usage:
|
||||
// orient(dir, [spin=]) CHILDREN;
|
||||
// PARENT() orient(anchor=, [spin=]) CHILDREN;
|
||||
// PARENT() orient(anchor, [spin]) CHILDREN;
|
||||
// Topics: Attachments
|
||||
// Description:
|
||||
// Orients children such that their top is tilted towards the given direction, or towards the
|
||||
// direction of a given anchor point on the parent. For a step-by-step explanation of
|
||||
// attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Orients children such that their top is tilted in the direction of the specified parent anchor point.
|
||||
// For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// dir = The direction to orient towards.
|
||||
// ---
|
||||
// anchor = The anchor on the parent which you want to match the orientation of. Use instead of `dir`.
|
||||
// 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`.
|
||||
// See Also: attachable(), attach(), orient()
|
||||
// Example: Orienting by Vector
|
||||
// Example: When orienting to an anchor, the spin of the anchor may cause confusion:
|
||||
// prismoid([50,50],[30,30],h=40) {
|
||||
// position(TOP+RIGHT)
|
||||
// orient(RIGHT)
|
||||
// prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT);
|
||||
// }
|
||||
// Example: When orienting to an anchor, the spin of the anchor may cause confusion:
|
||||
// prismoid([50,50],[30,30],h=40) {
|
||||
// position(TOP+RIGHT)
|
||||
// orient(anchor=RIGHT)
|
||||
// prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT);
|
||||
// }
|
||||
// Example: You can override anchor spin with `spin=`.
|
||||
// prismoid([50,50],[30,30],h=40) {
|
||||
// position(TOP+RIGHT)
|
||||
// orient(anchor=RIGHT,spin=0)
|
||||
// orient(RIGHT,spin=0)
|
||||
// prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT);
|
||||
// }
|
||||
// Example: Or you can anchor the child from the back
|
||||
// prismoid([50,50],[30,30],h=40) {
|
||||
// position(TOP+RIGHT)
|
||||
// orient(anchor=RIGHT)
|
||||
// orient(RIGHT)
|
||||
// prismoid([30,30],[0,5],h=20,anchor=BOT+BACK);
|
||||
// }
|
||||
module orient(dir, anchor, spin) {
|
||||
module orient(anchor, spin) {
|
||||
req_children($children);
|
||||
if (!is_undef(dir)) {
|
||||
spin = default(spin, 0);
|
||||
check =
|
||||
assert(anchor==undef, "Only one of dir= or anchor= may be given to orient()")
|
||||
assert(is_vector(dir))
|
||||
assert(is_finite(spin));
|
||||
two_d = _attach_geom_2d($parent_geom);
|
||||
fromvec = two_d? BACK : UP;
|
||||
rot(spin, from=fromvec, to=dir) children();
|
||||
} else {
|
||||
check=
|
||||
assert(dir==undef, "Only one of dir= or anchor= may be given to orient()")
|
||||
assert($parent_geom != undef, "No parent to orient from!")
|
||||
assert(is_string(anchor) || is_vector(anchor));
|
||||
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();
|
||||
}
|
||||
check=
|
||||
assert($parent_geom != undef, "No parent to orient from!")
|
||||
assert(is_string(anchor) || is_vector(anchor));
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2277,8 +2255,8 @@ function attach_geom(
|
|||
assert(is_vector(scale,2))
|
||||
assert(is_num(twist))
|
||||
extent==true
|
||||
? ["xrgn_extent", region, l, twist, scale, shift, cp, offset, anchors]
|
||||
: ["xrgn_isect", region, l, twist, scale, shift, cp, offset, anchors]
|
||||
? ["extrusion_extent", region, l, twist, scale, shift, cp, offset, anchors]
|
||||
: ["extrusion_isect", region, l, twist, scale, shift, cp, offset, anchors]
|
||||
) :
|
||||
let(
|
||||
r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef)
|
||||
|
@ -2373,7 +2351,7 @@ function _attach_geom_size(geom) =
|
|||
mm = pointlist_bounds(geom[1][0]),
|
||||
delt = mm[1]-mm[0]
|
||||
) delt
|
||||
) : type == "xrgn_isect" || type == "xrgn_extent"? ( //path, l
|
||||
) : type == "extrusion_isect" || type == "extrusion_extent"? ( //path, l
|
||||
let(
|
||||
mm = pointlist_bounds(flatten(geom[1])),
|
||||
delt = mm[1]-mm[0]
|
||||
|
@ -2479,7 +2457,7 @@ function _get_cp(geom) =
|
|||
: let(
|
||||
type = in_list(geom[0],["vnf_extent","vnf_isect"]) ? "vnf"
|
||||
: in_list(geom[0],["rgn_extent","rgn_isect"]) ? "path"
|
||||
: in_list(geom[0],["xrgn_extent","xrgn_isect"]) ? "xpath"
|
||||
: in_list(geom[0],["extrusion_extent","extrusion_isect"]) ? "xpath"
|
||||
: "other"
|
||||
)
|
||||
assert(type!="other", "Invalid cp value")
|
||||
|
@ -2488,11 +2466,29 @@ function _get_cp(geom) =
|
|||
[each centroid(geom[1]), if (type=="xpath") 0]
|
||||
)
|
||||
: let(points = type=="vnf"?geom[1][0]:flatten(force_region(geom[1])))
|
||||
cp=="mean" ? [each mean(points), if (type=="xpath") geom[2]/2]
|
||||
: cp=="box" ?[each mean(pointlist_bounds(points)), if (type=="xpath") geom[2]/2]
|
||||
cp=="mean" ? [each mean(points), if (type=="xpath") 0]
|
||||
: cp=="box" ?[each mean(pointlist_bounds(points)), if (type=="xpath") 0]
|
||||
: assert(false,"Invalid cp specification");
|
||||
|
||||
|
||||
function _get_cp(geom) =
|
||||
let(cp=select(geom,-3))
|
||||
is_vector(cp) ? cp
|
||||
: let(
|
||||
is_vnf = in_list(geom[0],["vnf_extent","vnf_isect"])
|
||||
)
|
||||
cp == "centroid" ? (
|
||||
is_vnf && len(geom[1][1])==0
|
||||
? [0,0,0]
|
||||
: centroid(geom[1])
|
||||
)
|
||||
: let(points = is_vnf?geom[1][0]:flatten(force_region(geom[1])))
|
||||
cp=="mean" ? mean(points)
|
||||
: cp=="box" ? mean(pointlist_bounds(points))
|
||||
: assert(false,"Invalid cp specification");
|
||||
|
||||
|
||||
|
||||
function _force_anchor_2d(anchor) =
|
||||
assert(anchor.y==0 || anchor.z==0, "Anchor for a 2D shape cannot be fully 3D. It must have either Y or Z component equal to zero.")
|
||||
anchor.y==0 ? [anchor.x,anchor.z] : point2d(anchor);
|
||||
|
@ -2723,7 +2719,7 @@ function _find_anchor(anchor, geom) =
|
|||
midy = (min(ys)+max(ys))/2,
|
||||
pos = rot(from=RIGHT, to=anchor, p=[maxx,midy])
|
||||
) [anchor, pos, unit(anchor,BACK), 0]
|
||||
) : type=="xrgn_extent" || type=="xrgn_isect" ? ( // extruded region
|
||||
) : type=="extrusion_extent" || type=="extrusion_isect" ? ( // extruded region
|
||||
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
|
||||
let(
|
||||
anchor_xy = point2d(anchor),
|
||||
|
@ -2738,12 +2734,12 @@ function _find_anchor(anchor, geom) =
|
|||
twmat = zrot(lerp(0, -twist, u)),
|
||||
mat = shmat * scmat * twmat
|
||||
)
|
||||
approx(anchor_xy,[0,0]) ? [anchor, apply(mat, up(anchor.z*L/2,cp)), unit(anchor, UP), oang] :
|
||||
approx(anchor_xy,[0,0]) ? [anchor, apply(mat, point3d(cp,anchor.z*L/2)), unit(anchor, UP), oang] :
|
||||
let(
|
||||
newrgn = apply(mat, rgn),
|
||||
newgeom = attach_geom(two_d=true, region=newrgn, extent=type=="xrgn_extent", cp=cp),
|
||||
newgeom = attach_geom(two_d=true, region=newrgn, extent=type=="extrusion_extent", cp=cp),
|
||||
result2d = _find_anchor(anchor_xy, newgeom),
|
||||
pos = point3d(result2d[1], cp.z+anchor.z*L/2),
|
||||
pos = point3d(result2d[1], anchor.z*L/2),
|
||||
vec = unit(point3d(result2d[2], anchor.z),UP),
|
||||
oang = atan2(vec.y,vec.x) + 90
|
||||
)
|
||||
|
|
|
@ -1324,7 +1324,7 @@ function _parse_screw_name(name) =
|
|||
)
|
||||
assert(len(commasplit)<=2, str("More than one comma found in screw name, \"",name,"\""))
|
||||
assert(len(xdash)<=2, str("Screw name has too many '-' or 'x' characters, \"",name,"\""))
|
||||
assert(len(commasplit)==1 || is_num(length), str("Invalid length in screw name, \"",name,"\""))
|
||||
assert(len(commasplit)==1 || is_num(length), str("Invalid length \"", commasplit[1],"\" in screw name, \"",name,"\""))
|
||||
assert(len(xdash)==1 || all_nonnegative(thread),str("Thread pitch not a valid number in screw name, \"",name,"\""))
|
||||
type[0] == "M" || type[0] == "m" ?
|
||||
let(diam = parse_float(substr(type,1)))
|
||||
|
|
35
strings.scad
35
strings.scad
|
@ -468,24 +468,23 @@ function parse_float(str) =
|
|||
// parse_frac("-2 12/4",mixed=false); // Returns nan
|
||||
// parse_frac("2 1/4",mixed=false); // Returns nan
|
||||
function parse_frac(str,mixed=true,improper=true,signed=true) =
|
||||
str == undef ? undef :
|
||||
len(str)==0 ? 0 :
|
||||
signed && str[0]=="-" ? -parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
||||
signed && str[0]=="+" ? parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
||||
mixed ? (
|
||||
!in_list(str_find(str," "), [undef,0]) || is_undef(str_find(str,"/"))? (
|
||||
let(whole = str_split(str,[" "]))
|
||||
_parse_int_recurse(whole[0],10,len(whole[0])-1) + parse_frac(whole[1], mixed=false, improper=improper, signed=false)
|
||||
) : parse_frac(str,mixed=false, improper=improper)
|
||||
) : (
|
||||
let(split = str_split(str,"/"))
|
||||
len(split)!=2 ? (0/0) :
|
||||
let(
|
||||
numerator = _parse_int_recurse(split[0],10,len(split[0])-1),
|
||||
denominator = _parse_int_recurse(split[1],10,len(split[1])-1)
|
||||
) !improper && numerator>=denominator? (0/0) :
|
||||
denominator<0 ? (0/0) : numerator/denominator
|
||||
);
|
||||
str == undef ? undef
|
||||
: len(str)==0 ? 0
|
||||
: str[0]==" " ? NAN
|
||||
: signed && str[0]=="-" ? -parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false)
|
||||
: signed && str[0]=="+" ? parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false)
|
||||
: mixed && (str_find(str," ")!=undef || str_find(str,"/")==undef)? // Mixed allowed and there is a space or no slash
|
||||
let(whole = str_split(str,[" "]))
|
||||
_parse_int_recurse(whole[0],10,len(whole[0])-1) + parse_frac(whole[1], mixed=false, improper=improper, signed=false)
|
||||
: let(split = str_split(str,"/"))
|
||||
len(split)!=2 ? NAN
|
||||
: let(
|
||||
numerator = _parse_int_recurse(split[0],10,len(split[0])-1),
|
||||
denominator = _parse_int_recurse(split[1],10,len(split[1])-1)
|
||||
)
|
||||
!improper && numerator>=denominator? NAN
|
||||
: denominator<0 ? NAN
|
||||
: numerator/denominator;
|
||||
|
||||
|
||||
// Function: parse_num()
|
||||
|
|
|
@ -215,6 +215,12 @@ module test_parse_frac() {
|
|||
assert(parse_frac("3/0") == INF);
|
||||
assert(parse_frac("-3/0") == -INF);
|
||||
assert(is_nan(parse_frac("0/0")));
|
||||
assert(is_nan(parse_frac("-77/9", improper=false)));
|
||||
assert(is_nan(parse_frac("-2 12/4",improper=false)));
|
||||
assert(is_nan(parse_frac("-2 12/4",signed=false)));
|
||||
assert(is_nan(parse_frac("-2 12/4",mixed=false)));
|
||||
assert(is_nan(parse_frac("2 1/4",mixed=false)));
|
||||
assert(is_nan(parse_frac("2", mixed=false)));
|
||||
}
|
||||
test_parse_frac();
|
||||
|
||||
|
|
|
@ -391,19 +391,18 @@ 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
|
||||
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.
|
||||
Using its `anchor=` argument you can orient the
|
||||
child relative to the parent anchor directions. This is different
|
||||
mechanism for re-orienting the child() that eases this burden:
|
||||
it can orient the child relative to the parent anchor directions. This is different
|
||||
than giving an `orient=` argument to the child, because that orients
|
||||
relative to the parent's global coordinate system by just using the vector
|
||||
directly instead of orienting to the parent's anchor, which takes
|
||||
directly, instead of orienting to the parent's anchor, which takes
|
||||
account of face orientation. A series of three
|
||||
examples shows the different results. In the first example, we use
|
||||
only `position()`. The child cube is erected pointing upwards, in the
|
||||
Z direction. In the second example we use `orient=RIGHT` in the child
|
||||
and the result is that the child object points in the X+ direction,
|
||||
without regard for the shape of the parent object. In the final
|
||||
example we apply `orient(anchor=RIGHT)` and the child is oriented
|
||||
example we apply `orient(RIGHT)` and the child is oriented
|
||||
relative to the slanted right face of the parent using the parent
|
||||
RIGHT anchor.
|
||||
|
||||
|
@ -427,7 +426,7 @@ prismoid([50,50],[30,30],h=40)
|
|||
include<BOSL2/std.scad>
|
||||
prismoid([50,50],[30,30],h=40)
|
||||
position(RIGHT+TOP)
|
||||
orient(anchor=RIGHT)
|
||||
orient(RIGHT)
|
||||
cube([15,15,25],anchor=BACK+BOT);
|
||||
```
|
||||
|
||||
|
@ -460,17 +459,11 @@ prismoid([50,50],[30,30],h=40)
|
|||
include<BOSL2/std.scad>
|
||||
prismoid([50,50],[30,30],h=40)
|
||||
position(RIGHT+TOP)
|
||||
orient(anchor=RIGHT)
|
||||
orient(RIGHT)
|
||||
anchor_arrow(40);
|
||||
```
|
||||
|
||||
|
||||
Note also that `orient()` can be used to orient the child relative to
|
||||
the parent global coordinate system using its first argument, `dir=`. This
|
||||
use of `orient()` is the same as using the `orient=` argument for the
|
||||
child object.
|
||||
|
||||
|
||||
## Attachment overview
|
||||
|
||||
Attachables get their name from their ability to be attached to each
|
||||
|
@ -590,7 +583,7 @@ cube(50,center=true)
|
|||
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(anchor=)`, if needed.
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue