Fixes for prismoidal geometry with non-UP axis=.

This commit is contained in:
Garth Minette 2022-05-06 18:09:44 -07:00
parent 27a2c524f0
commit ec6b158f8c

View file

@ -1219,7 +1219,7 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
// offset = If given, offsets the perimeter of the volume around the centerpoint. // offset = If given, offsets the perimeter of the volume around the centerpoint.
// anchors = If given as a list of anchor points, allows named anchor points. // anchors = If given as a list of anchor points, allows named anchor points.
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D) // two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
// axis = The vector pointing along the axis of a cylinder geometry. Default: UP // axis = The vector pointing along the axis of a geometry. Default: UP
// geom = If given, uses the pre-defined (via {{attach_geom()}} geometry. // geom = If given, uses the pre-defined (via {{attach_geom()}} geometry.
// //
// Side Effects: // Side Effects:
@ -1385,14 +1385,15 @@ module attachable(
region = !is_undef(region)? region : region = !is_undef(region)? region :
!is_undef(path)? [path] : !is_undef(path)? [path] :
undef; undef;
geom = is_def(geom)? geom : attach_geom( geom = is_def(geom)? geom :
size=size, size2=size2, shift=shift, attach_geom(
r=r, r1=r1, r2=r2, h=h, size=size, size2=size2, shift=shift,
d=d, d1=d1, d2=d2, l=l, r=r, r1=r1, r2=r2, h=h,
vnf=vnf, region=region, extent=extent, d=d, d1=d1, d2=d2, l=l,
cp=cp, offset=offset, anchors=anchors, vnf=vnf, region=region, extent=extent,
two_d=two_d, axis=axis cp=cp, offset=offset, anchors=anchors,
); two_d=two_d, axis=axis
);
m = _attach_transform(anchor,spin,orient,geom); m = _attach_transform(anchor,spin,orient,geom);
multmatrix(m) { multmatrix(m) {
$parent_anchor = anchor; $parent_anchor = anchor;
@ -1499,7 +1500,7 @@ module attachable(
// offset = If given, offsets the perimeter of the volume around the centerpoint. // offset = If given, offsets the perimeter of the volume around the centerpoint.
// anchors = If given as a list of anchor points, allows named anchor points. // anchors = If given as a list of anchor points, allows named anchor points.
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D) // two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
// axis = The vector pointing along the axis of a cylinder geometry. Default: UP // axis = The vector pointing along the axis of a geometry. Default: UP
// p = The VNF, path, or point to transform. // p = The VNF, path, or point to transform.
function reorient( function reorient(
anchor, spin, orient, anchor, spin, orient,
@ -1528,14 +1529,15 @@ function reorient(
) )
(anchor==CENTER && spin==0 && orient==UP && p!=undef)? p : (anchor==CENTER && spin==0 && orient==UP && p!=undef)? p :
let( let(
geom = is_def(geom)? geom : attach_geom( geom = is_def(geom)? geom :
size=size, size2=size2, shift=shift, attach_geom(
r=r, r1=r1, r2=r2, h=h, size=size, size2=size2, shift=shift,
d=d, d1=d1, d2=d2, l=l, r=r, r1=r1, r2=r2, h=h,
vnf=vnf, region=region, extent=extent, d=d, d1=d1, d2=d2, l=l,
cp=cp, offset=offset, anchors=anchors, vnf=vnf, region=region, extent=extent,
two_d=two_d, axis=axis cp=cp, offset=offset, anchors=anchors,
), two_d=two_d, axis=axis
),
$attach_to = undef $attach_to = undef
) _attach_transform(anchor,spin,orient,geom,p); ) _attach_transform(anchor,spin,orient,geom,p);
@ -1605,7 +1607,7 @@ function named_anchor(name, pos, orient=UP, spin=0) = [name, pos, orient, spin];
// offset = If given, offsets the perimeter of the volume around the centerpoint. // offset = If given, offsets the perimeter of the volume around the centerpoint.
// anchors = If given as a list of anchor points, allows named anchor points. // anchors = If given as a list of anchor points, allows named anchor points.
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D) // two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
// axis = The vector pointing along the axis of a cylinder geometry. Default: UP // axis = The vector pointing along the axis of a geometry. Default: UP
// //
// Example(NORENDER): Cubical Shape // Example(NORENDER): Cubical Shape
// geom = attach_geom(size=size); // geom = attach_geom(size=size);
@ -1697,7 +1699,7 @@ function attach_geom(
assert(is_vector(size,2)) assert(is_vector(size,2))
assert(is_num(size2)) assert(is_num(size2))
assert(is_num(shift)) assert(is_num(shift))
["rect", point2d(size), size2, shift, cp, offset, anchors] ["trapezoid", point2d(size), size2, shift, cp, offset, anchors]
) : ( ) : (
let( let(
size2 = default(size2, point2d(size)), size2 = default(size2, point2d(size)),
@ -1706,7 +1708,7 @@ function attach_geom(
assert(is_vector(size,3)) assert(is_vector(size,3))
assert(is_vector(size2,2)) assert(is_vector(size2,2))
assert(is_vector(shift,2)) assert(is_vector(shift,2))
["cuboid", size, size2, shift, axis, cp, offset, anchors] ["prismoid", size, size2, shift, axis, cp, offset, anchors]
) )
) : !is_undef(vnf)? ( ) : !is_undef(vnf)? (
assert(is_vnf(vnf)) assert(is_vnf(vnf))
@ -1748,11 +1750,11 @@ function attach_geom(
assert(is_num(r2) || is_vector(r2,2)) assert(is_num(r2) || is_vector(r2,2))
assert(is_num(l)) assert(is_num(l))
assert(is_vector(shift,2)) assert(is_vector(shift,2))
["cyl", r1, r2, l, shift, axis, cp, offset, anchors] ["conoid", r1, r2, l, shift, axis, cp, offset, anchors]
) : ( ) : (
two_d? ( two_d? (
assert(is_num(r1) || is_vector(r1,2)) assert(is_num(r1) || is_vector(r1,2))
["circle", r1, cp, offset, anchors] ["ellipse", r1, cp, offset, anchors]
) : ( ) : (
assert(is_num(r1) || is_vector(r1,3)) assert(is_num(r1) || is_vector(r1,3))
["spheroid", r1, cp, offset, anchors] ["spheroid", r1, cp, offset, anchors]
@ -1780,7 +1782,7 @@ function attach_geom(
// Returns true if the given attachment geometry description is for a 2D shape. // Returns true if the given attachment geometry description is for a 2D shape.
function _attach_geom_2d(geom) = function _attach_geom_2d(geom) =
let( type = geom[0] ) let( type = geom[0] )
type == "rect" || type == "circle" || type == "trapezoid" || type == "ellipse" ||
type == "rgn_isect" || type == "rgn_extent"; type == "rgn_isect" || type == "rgn_extent";
@ -1793,14 +1795,14 @@ function _attach_geom_2d(geom) =
// Returns the `[X,Y,Z]` bounding size for the given attachment geometry description. // Returns the `[X,Y,Z]` bounding size for the given attachment geometry description.
function _attach_geom_size(geom) = function _attach_geom_size(geom) =
let( type = geom[0] ) let( type = geom[0] )
type == "cuboid"? ( //size, size2, shift type == "prismoid"? ( //size, size2, shift, axis
let( let(
size=geom[1], size2=geom[2], shift=point2d(geom[3]), size=geom[1], size2=geom[2], shift=point2d(geom[3]),
maxx = max(size.x,size2.x), maxx = max(size.x,size2.x),
maxy = max(size.y,size2.y), maxy = max(size.y,size2.y),
z = size.z z = size.z
) [maxx, maxy, z] ) [maxx, maxy, z]
) : type == "cyl"? ( //r1, r2, l, shift ) : type == "conoid"? ( //r1, r2, l, shift
let( let(
r1=geom[1], r2=geom[2], l=geom[3], r1=geom[1], r2=geom[2], l=geom[3],
shift=point2d(geom[4]), axis=point3d(geom[5]), shift=point2d(geom[4]), axis=point3d(geom[5]),
@ -1831,12 +1833,12 @@ function _attach_geom_size(geom) =
mm = pointlist_bounds(flatten(geom[1])), mm = pointlist_bounds(flatten(geom[1])),
delt = mm[1]-mm[0] delt = mm[1]-mm[0]
) [delt.x, delt.y, geom[2]] ) [delt.x, delt.y, geom[2]]
) : type == "rect"? ( //size, size2 ) : type == "trapezoid"? ( //size, size2
let( let(
size=geom[1], size2=geom[2], shift=geom[3], size=geom[1], size2=geom[2], shift=geom[3],
maxx = max(size.x,size2+abs(shift)) maxx = max(size.x,size2+abs(shift))
) [maxx, size.y] ) [maxx, size.y]
) : type == "circle"? ( //r ) : type == "ellipse"? ( //r
let( r=geom[1] ) let( r=geom[1] )
is_num(r)? [2,2]*r : v_mul([2,2],point2d(r)) is_num(r)? [2,2]*r : v_mul([2,2],point2d(r))
) : type == "rgn_isect" || type == "rgn_extent"? ( //path ) : type == "rgn_isect" || type == "rgn_extent"? ( //path
@ -1982,37 +1984,36 @@ function _find_anchor(anchor, geom) =
type = geom[0] type = geom[0]
) )
assert(is_vector(anchor),str("Invalid anchor: anchor=",anchor)) assert(is_vector(anchor),str("Invalid anchor: anchor=",anchor))
let(anchor = point3d(anchor))
anchor==CENTER? [anchor, cp, UP, 0] :
let( let(
anchor = point3d(anchor),
oang = ( oang = (
approx(point2d(anchor), [0,0])? 0 : approx(point2d(anchor), [0,0])? 0 :
atan2(anchor.y, anchor.x)+90 atan2(anchor.y, anchor.x)+90
) )
) )
type == "cuboid"? ( //size, size2, shift type == "prismoid"? ( //size, size2, shift, axis
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[]) let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a cuboid/prismoid must be -1, 0, or 1") assert(all_comps_good, "All components of an anchor for a cuboid/prismoid must be -1, 0, or 1")
let( let(
size=geom[1], size2=geom[2], size=geom[1], size2=geom[2],
shift=point2d(geom[3]), axis=point3d(geom[4]), shift=point2d(geom[3]), axis=point3d(geom[4]),
anch = rot(from=axis, to=UP, p=anchor), anch = rot(from=axis, to=UP, p=anchor),
offset = rot(from=axis, to=UP, p=offset),
h = size.z, h = size.z,
u = (anch.z+1)/2, // u is one of 0, 0.5, or 1 u = (anch.z + 1) / 2, // u is one of 0, 0.5, or 1
axy = point2d(anch), axy = point2d(anch),
bot = point3d(v_mul(point2d(size)/2,axy),-h/2), bot = point3d(v_mul(point2d(size )/2, axy), -h/2),
top = point3d(v_mul(point2d(size2)/2,axy)+shift,h/2), top = point3d(v_mul(point2d(size2)/2, axy) + shift, h/2),
pos = point3d(cp) + lerp(bot,top,u) + offset, pos = point3d(cp) + lerp(bot,top,u) + offset,
vecs = [ vecs = [
if (anchor.x!=0) unit(rot(from=UP, to=unit([(top-bot).x,0,h]), p=[axy.x,0,0]), UP), if (anch.x!=0) unit(rot(from=UP, to=[(top-bot).x,0,h], p=[axy.x,0,0]), UP),
if (anchor.y!=0) unit(rot(from=UP, to=unit([0,(top-bot).y,h]), p=[0,axy.y,0]), UP), if (anch.y!=0) unit(rot(from=UP, to=[0,(top-bot).y,h], p=[0,axy.y,0]), UP),
if (anchor.z!=0) anch==CENTER? UP : unit([0,0,anch.z],UP) if (anch.z!=0) anch==CENTER? UP : unit([0,0,anch.z],UP)
], ],
vec = unit(sum(vecs) / len(vecs)), vec = anchor==CENTER? UP : rot(from=UP, to=axis, p=unit(sum(vecs) / len(vecs))),
pos2 = rot(from=UP, to=axis, p=pos), pos2 = rot(from=UP, to=axis, p=pos)
vec2 = rot(from=UP, to=axis, p=vec) ) [anchor, pos2, vec, oang]
) [anchor, pos2, vec2, oang] ) : type == "conoid"? ( //r1, r2, l, shift
) : type == "cyl"? ( //r1, r2, l, shift
assert(anchor.z == sign(anchor.z), "The Z component of an anchor for a cylinder/cone must be -1, 0, or 1") assert(anchor.z == sign(anchor.z), "The Z component of an anchor for a cylinder/cone must be -1, 0, or 1")
let( let(
rr1=geom[1], rr2=geom[2], l=geom[3], rr1=geom[1], rr2=geom[2], l=geom[3],
@ -2020,6 +2021,7 @@ function _find_anchor(anchor, geom) =
r1 = is_num(rr1)? [rr1,rr1] : point2d(rr1), r1 = is_num(rr1)? [rr1,rr1] : point2d(rr1),
r2 = is_num(rr2)? [rr2,rr2] : point2d(rr2), r2 = is_num(rr2)? [rr2,rr2] : point2d(rr2),
anch = rot(from=axis, to=UP, p=anchor), anch = rot(from=axis, to=UP, p=anchor),
offset = rot(from=axis, to=UP, p=offset),
u = (anch.z+1)/2, u = (anch.z+1)/2,
axy = unit(point2d(anch),[0,0]), axy = unit(point2d(anch),[0,0]),
bot = point3d(v_mul(r1,axy), -l/2), bot = point3d(v_mul(r1,axy), -l/2),
@ -2027,12 +2029,12 @@ function _find_anchor(anchor, geom) =
pos = point3d(cp) + lerp(bot,top,u) + offset, pos = point3d(cp) + lerp(bot,top,u) + offset,
sidevec = rot(from=UP, to=top-bot, p=point3d(axy)), sidevec = rot(from=UP, to=top-bot, p=point3d(axy)),
vvec = anch==CENTER? UP : unit([0,0,anch.z],UP), vvec = anch==CENTER? UP : unit([0,0,anch.z],UP),
vec = anch==CENTER? UP : vec = anch==CENTER? CENTER :
approx(axy,[0,0])? unit(anch,UP) : approx(axy,[0,0])? unit(anch,UP) :
approx(anch.z,0)? sidevec : approx(anch.z,0)? sidevec :
unit((sidevec+vvec)/2,UP), unit((sidevec+vvec)/2,UP),
pos2 = rot(from=UP, to=axis, p=pos), pos2 = rot(from=UP, to=axis, p=pos),
vec2 = rot(from=UP, to=axis, p=vec) vec2 = anch==CENTER? UP : rot(from=UP, to=axis, p=vec)
) [anchor, pos2, vec2, oang] ) [anchor, pos2, vec2, oang]
) : type == "spheroid"? ( //r ) : type == "spheroid"? ( //r
let( let(
@ -2104,7 +2106,7 @@ function _find_anchor(anchor, geom) =
mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : avep, mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : avep,
pos = point3d(cp) + rot(from=RIGHT, to=anchor, p=mpt) pos = point3d(cp) + rot(from=RIGHT, to=anchor, p=mpt)
) [anchor, pos, anchor, oang] ) [anchor, pos, anchor, oang]
) : type == "rect"? ( //size, size2, shift ) : type == "trapezoid"? ( //size, size2, shift
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[]) let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a rectangle/trapezoid must be -1, 0, or 1") assert(all_comps_good, "All components of an anchor for a rectangle/trapezoid must be -1, 0, or 1")
let( let(
@ -2127,7 +2129,7 @@ function _find_anchor(anchor, geom) =
unit((point3d(svec) + BACK) / 2, BACK) unit((point3d(svec) + BACK) / 2, BACK)
) )
) [anchor, pos, vec, 0] ) [anchor, pos, vec, 0]
) : type == "circle"? ( //r ) : type == "ellipse"? ( //r
let( let(
anchor = unit(_force_anchor_2d(anchor),[0,0]), anchor = unit(_force_anchor_2d(anchor),[0,0]),
r = force_list(geom[1],2), r = force_list(geom[1],2),
@ -2137,7 +2139,7 @@ function _find_anchor(anchor, geom) =
px = sign(anchor.x) * sqrt(1/(1/sqr(r.x) + m*m/sqr(r.y))) px = sign(anchor.x) * sqrt(1/(1/sqr(r.x) + m*m/sqr(r.y)))
) )
[px,m*px], [px,m*px],
vec = unit([r.y/r.x*pos.x, r.x/r.y*pos.y]) vec = unit([r.y/r.x*pos.x, r.x/r.y*pos.y],BACK)
) [anchor, point2d(cp+offset)+pos, vec, 0] ) [anchor, point2d(cp+offset)+pos, vec, 0]
) : type == "rgn_isect"? ( //region ) : type == "rgn_isect"? ( //region
let( let(