Merge pull request #1088 from adrianVmariano/master

misc fixes
This commit is contained in:
Revar Desmera 2023-03-23 15:04:19 -07:00 committed by GitHub
commit d42ed43674
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 85 deletions

View file

@ -429,73 +429,51 @@ module position(from)
// Module: orient() // Module: orient()
// Usage: // Usage:
// orient(dir, [spin=]) CHILDREN; // PARENT() orient(anchor, [spin]) CHILDREN;
// PARENT() orient(anchor=, [spin=]) CHILDREN;
// Topics: Attachments // Topics: Attachments
// Description: // Description:
// Orients children such that their top is tilted towards the given direction, or towards the // Orients children such that their top is tilted in the direction of the specified parent anchor point.
// direction of a given anchor point on the parent. For a step-by-step explanation of // For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments: // Arguments:
// dir = The direction to orient towards. // 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. Use instead of `dir`.
// spin = The spin to add to the children. (Overrides anchor spin.) // spin = The spin to add to the children. (Overrides anchor spin.)
// Side Effects: // Side Effects:
// `$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`.
// See Also: attachable(), attach(), orient() // 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) { // prismoid([50,50],[30,30],h=40) {
// position(TOP+RIGHT) // position(TOP+RIGHT)
// orient(RIGHT) // orient(RIGHT)
// prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT); // 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=`. // Example: You can override anchor spin with `spin=`.
// prismoid([50,50],[30,30],h=40) { // prismoid([50,50],[30,30],h=40) {
// position(TOP+RIGHT) // position(TOP+RIGHT)
// orient(anchor=RIGHT,spin=0) // orient(RIGHT,spin=0)
// prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT); // prismoid([30,30],[0,5],h=20,anchor=BOT+LEFT);
// } // }
// Example: Or you can anchor the child from the back // Example: Or you can anchor the child from the back
// prismoid([50,50],[30,30],h=40) { // prismoid([50,50],[30,30],h=40) {
// position(TOP+RIGHT) // position(TOP+RIGHT)
// orient(anchor=RIGHT) // orient(RIGHT)
// prismoid([30,30],[0,5],h=20,anchor=BOT+BACK); // prismoid([30,30],[0,5],h=20,anchor=BOT+BACK);
// } // }
module orient(dir, anchor, spin) { module orient(anchor, spin) {
req_children($children); req_children($children);
if (!is_undef(dir)) { check=
spin = default(spin, 0); assert($parent_geom != undef, "No parent to orient from!")
check = assert(is_string(anchor) || is_vector(anchor));
assert(anchor==undef, "Only one of dir= or anchor= may be given to orient()") anch = _find_anchor(anchor, $parent_geom);
assert(is_vector(dir)) two_d = _attach_geom_2d($parent_geom);
assert(is_finite(spin)); fromvec = two_d? BACK : UP;
two_d = _attach_geom_2d($parent_geom); $attach_to = undef;
fromvec = two_d? BACK : UP; $attach_anchor = anch;
rot(spin, from=fromvec, to=dir) children(); $attach_norot = true;
} else { spin = default(spin, anch[3]);
check= assert(is_finite(spin));
assert(dir==undef, "Only one of dir= or anchor= may be given to orient()") rot(spin, from=fromvec, to=anch[2]) children();
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_vector(scale,2))
assert(is_num(twist)) assert(is_num(twist))
extent==true extent==true
? ["xrgn_extent", region, l, twist, scale, shift, cp, offset, anchors] ? ["extrusion_extent", region, l, twist, scale, shift, cp, offset, anchors]
: ["xrgn_isect", region, l, twist, scale, shift, cp, offset, anchors] : ["extrusion_isect", region, l, twist, scale, shift, cp, offset, anchors]
) : ) :
let( let(
r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef) 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]), mm = pointlist_bounds(geom[1][0]),
delt = mm[1]-mm[0] delt = mm[1]-mm[0]
) delt ) delt
) : type == "xrgn_isect" || type == "xrgn_extent"? ( //path, l ) : type == "extrusion_isect" || type == "extrusion_extent"? ( //path, l
let( let(
mm = pointlist_bounds(flatten(geom[1])), mm = pointlist_bounds(flatten(geom[1])),
delt = mm[1]-mm[0] delt = mm[1]-mm[0]
@ -2479,7 +2457,7 @@ function _get_cp(geom) =
: let( : let(
type = in_list(geom[0],["vnf_extent","vnf_isect"]) ? "vnf" type = in_list(geom[0],["vnf_extent","vnf_isect"]) ? "vnf"
: in_list(geom[0],["rgn_extent","rgn_isect"]) ? "path" : 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" : "other"
) )
assert(type!="other", "Invalid cp value") assert(type!="other", "Invalid cp value")
@ -2488,11 +2466,29 @@ function _get_cp(geom) =
[each centroid(geom[1]), if (type=="xpath") 0] [each centroid(geom[1]), if (type=="xpath") 0]
) )
: let(points = type=="vnf"?geom[1][0]:flatten(force_region(geom[1]))) : let(points = type=="vnf"?geom[1][0]:flatten(force_region(geom[1])))
cp=="mean" ? [each mean(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") geom[2]/2] : cp=="box" ?[each mean(pointlist_bounds(points)), if (type=="xpath") 0]
: assert(false,"Invalid cp specification"); : 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) = 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.") 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); anchor.y==0 ? [anchor.x,anchor.z] : point2d(anchor);
@ -2723,7 +2719,7 @@ function _find_anchor(anchor, geom) =
midy = (min(ys)+max(ys))/2, midy = (min(ys)+max(ys))/2,
pos = rot(from=RIGHT, to=anchor, p=[maxx,midy]) pos = rot(from=RIGHT, to=anchor, p=[maxx,midy])
) [anchor, pos, unit(anchor,BACK), 0] ) [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.") 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( let(
anchor_xy = point2d(anchor), anchor_xy = point2d(anchor),
@ -2738,12 +2734,12 @@ function _find_anchor(anchor, geom) =
twmat = zrot(lerp(0, -twist, u)), twmat = zrot(lerp(0, -twist, u)),
mat = shmat * scmat * twmat 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( let(
newrgn = apply(mat, rgn), 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), 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), vec = unit(point3d(result2d[2], anchor.z),UP),
oang = atan2(vec.y,vec.x) + 90 oang = atan2(vec.y,vec.x) + 90
) )

View file

@ -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(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(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,"\"")) assert(len(xdash)==1 || all_nonnegative(thread),str("Thread pitch not a valid number in screw name, \"",name,"\""))
type[0] == "M" || type[0] == "m" ? type[0] == "M" || type[0] == "m" ?
let(diam = parse_float(substr(type,1))) let(diam = parse_float(substr(type,1)))

View file

@ -468,24 +468,23 @@ function parse_float(str) =
// parse_frac("-2 12/4",mixed=false); // Returns nan // parse_frac("-2 12/4",mixed=false); // Returns nan
// parse_frac("2 1/4",mixed=false); // Returns nan // parse_frac("2 1/4",mixed=false); // Returns nan
function parse_frac(str,mixed=true,improper=true,signed=true) = function parse_frac(str,mixed=true,improper=true,signed=true) =
str == undef ? undef : str == undef ? undef
len(str)==0 ? 0 : : len(str)==0 ? 0
signed && str[0]=="-" ? -parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) : : 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 ? ( : signed && str[0]=="+" ? parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false)
!in_list(str_find(str," "), [undef,0]) || is_undef(str_find(str,"/"))? ( : mixed && (str_find(str," ")!=undef || str_find(str,"/")==undef)? // Mixed allowed and there is a space or no slash
let(whole = str_split(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_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 ? NAN
let(split = str_split(str,"/")) : let(
len(split)!=2 ? (0/0) : numerator = _parse_int_recurse(split[0],10,len(split[0])-1),
let( denominator = _parse_int_recurse(split[1],10,len(split[1])-1)
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
) !improper && numerator>=denominator? (0/0) : : denominator<0 ? NAN
denominator<0 ? (0/0) : numerator/denominator : numerator/denominator;
);
// Function: parse_num() // Function: parse_num()

View file

@ -215,6 +215,12 @@ module test_parse_frac() {
assert(parse_frac("3/0") == INF); assert(parse_frac("3/0") == INF);
assert(parse_frac("-3/0") == -INF); assert(parse_frac("-3/0") == -INF);
assert(is_nan(parse_frac("0/0"))); 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(); test_parse_frac();

View file

@ -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 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, 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 you need to figure out the correct rotation. The `orient()` module provides a
mechanism for re-orienting the child() that eases this burden. mechanism for re-orienting the child() that eases this burden:
Using its `anchor=` argument you can orient the it can orient the child relative to the parent anchor directions. This is different
child relative to the parent anchor directions. This is different
than giving an `orient=` argument to the child, because that orients than giving an `orient=` argument to the child, because that orients
relative to the parent's global coordinate system by just using the vector 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 account of face orientation. A series of three
examples shows the different results. In the first example, we use examples shows the different results. In the first example, we use
only `position()`. The child cube is erected pointing upwards, in the only `position()`. The child cube is erected pointing upwards, in the
Z direction. In the second example we use `orient=RIGHT` in the child 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, 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 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 relative to the slanted right face of the parent using the parent
RIGHT anchor. RIGHT anchor.
@ -427,7 +426,7 @@ prismoid([50,50],[30,30],h=40)
include<BOSL2/std.scad> include<BOSL2/std.scad>
prismoid([50,50],[30,30],h=40) prismoid([50,50],[30,30],h=40)
position(RIGHT+TOP) position(RIGHT+TOP)
orient(anchor=RIGHT) orient(RIGHT)
cube([15,15,25],anchor=BACK+BOT); cube([15,15,25],anchor=BACK+BOT);
``` ```
@ -460,17 +459,11 @@ prismoid([50,50],[30,30],h=40)
include<BOSL2/std.scad> include<BOSL2/std.scad>
prismoid([50,50],[30,30],h=40) prismoid([50,50],[30,30],h=40)
position(RIGHT+TOP) position(RIGHT+TOP)
orient(anchor=RIGHT) orient(RIGHT)
anchor_arrow(40); 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 ## Attachment overview
Attachables get their name from their ability to be attached to each 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 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 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 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 If you give an anchor point to the child object it moves the child
around (in the attached coordinate system). Or alternatively you can around (in the attached coordinate system). Or alternatively you can