unit() now asserts error for zero-length vector unless dflt= arg is given.

This commit is contained in:
Garth Minette 2020-07-10 00:03:55 -07:00
parent a0d8c0a5c3
commit dde616dad5
5 changed files with 53 additions and 45 deletions

View file

@ -420,12 +420,12 @@ function find_anchor(anchor, geom) =
bot = point3d(vmul(point2d(size)/2,axy),-h/2), bot = point3d(vmul(point2d(size)/2,axy),-h/2),
top = point3d(vmul(point2d(size2)/2,axy)+shift,h/2), top = point3d(vmul(point2d(size2)/2,axy)+shift,h/2),
pos = point3d(cp) + lerp(bot,top,u) + offset, pos = point3d(cp) + lerp(bot,top,u) + offset,
sidevec = unit(rot(from=UP, to=top-bot, p=point3d(axy))), sidevec = unit(rot(from=UP, to=top-bot, p=point3d(axy)),UP),
vvec = anchor==CENTER? UP : unit([0,0,anchor.z]), vvec = anchor==CENTER? UP : unit([0,0,anchor.z]),
vec = anchor==CENTER? UP : vec = anchor==CENTER? UP :
approx(axy,[0,0])? unit(anchor) : approx(axy,[0,0])? unit(anchor,UP) :
approx(anchor.z,0)? sidevec : approx(anchor.z,0)? sidevec :
unit((sidevec+vvec)/2) unit((sidevec+vvec)/2,UP)
) [anchor, pos, vec, oang] ) [anchor, pos, vec, oang]
) : type == "cyl"? ( //r1, r2, l, shift ) : type == "cyl"? ( //r1, r2, l, shift
let( let(
@ -433,24 +433,24 @@ function find_anchor(anchor, geom) =
r1 = is_num(rr1)? [rr1,rr1] : rr1, r1 = is_num(rr1)? [rr1,rr1] : rr1,
r2 = is_num(rr2)? [rr2,rr2] : rr2, r2 = is_num(rr2)? [rr2,rr2] : rr2,
u = (anchor.z+1)/2, u = (anchor.z+1)/2,
axy = unit(point2d(anchor)), axy = unit(point2d(anchor),[0,0]),
bot = point3d(vmul(r1,axy), -l/2), bot = point3d(vmul(r1,axy), -l/2),
top = point3d(vmul(r2,axy)+shift, l/2), top = point3d(vmul(r2,axy)+shift, l/2),
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 = anchor==CENTER? UP : unit([0,0,anchor.z]), vvec = anchor==CENTER? UP : unit([0,0,anchor.z],UP),
vec = anchor==CENTER? UP : vec = anchor==CENTER? UP :
approx(axy,[0,0])? unit(anchor) : approx(axy,[0,0])? unit(anchor,UP) :
approx(anchor.z,0)? sidevec : approx(anchor.z,0)? sidevec :
unit((sidevec+vvec)/2) unit((sidevec+vvec)/2,UP)
) [anchor, pos, vec, oang] ) [anchor, pos, vec, oang]
) : type == "spheroid"? ( //r ) : type == "spheroid"? ( //r
let( let(
rr = geom[1], rr = geom[1],
r = is_num(rr)? [rr,rr,rr] : rr, r = is_num(rr)? [rr,rr,rr] : rr,
anchor = unit(point3d(anchor)), anchor = unit(point3d(anchor),CENTER),
pos = point3d(cp) + vmul(r,anchor) + offset, pos = point3d(cp) + vmul(r,anchor) + offset,
vec = unit(vmul(r,anchor)) vec = unit(vmul(r,anchor),UP)
) [anchor, pos, vec, oang] ) [anchor, pos, vec, oang]
) : type == "vnf_isect"? ( //vnf ) : type == "vnf_isect"? ( //vnf
let( let(
@ -490,7 +490,8 @@ function find_anchor(anchor, geom) =
faceplane = plane_from_points(faceverts), faceplane = plane_from_points(faceverts),
nrm = plane_normal(faceplane) nrm = plane_normal(faceplane)
) nrm ) nrm
]) / len(nfaces) ]) / len(nfaces),
UP
) )
) )
[anchor, pos, n, oang] [anchor, pos, n, oang]
@ -513,15 +514,15 @@ function find_anchor(anchor, geom) =
frpt = [size.x/2*anchor.x, -size.y/2], frpt = [size.x/2*anchor.x, -size.y/2],
bkpt = [size2/2*anchor.x, size.y/2], bkpt = [size2/2*anchor.x, size.y/2],
pos = point2d(cp) + lerp(frpt, bkpt, u) + offset, pos = point2d(cp) + lerp(frpt, bkpt, u) + offset,
vec = unit(rot(from=BACK, to=bkpt-frpt, p=anchor)) vec = unit(rot(from=BACK, to=bkpt-frpt, p=anchor),[0,1])
) [anchor, pos, vec, 0] ) [anchor, pos, vec, 0]
) : type == "circle"? ( //r ) : type == "circle"? ( //r
let( let(
rr = geom[1], rr = geom[1],
r = is_num(rr)? [rr,rr] : rr, r = is_num(rr)? [rr,rr] : rr,
pos = point2d(cp) + vmul(r,anchor) + offset, pos = point2d(cp) + vmul(r,anchor) + offset,
anchor = unit(point2d(anchor)), anchor = unit(point2d(anchor),[0,0]),
vec = unit(vmul([r.y,r.x],anchor)) vec = unit(vmul([r.y,r.x],anchor),[0,1])
) [anchor, pos, vec, 0] ) [anchor, pos, vec, 0]
) : type == "path_isect"? ( //path ) : type == "path_isect"? ( //path
let( let(
@ -534,7 +535,7 @@ function find_anchor(anchor, geom) =
isect = ray_segment_intersection([[0,0],anchor], seg1), isect = ray_segment_intersection([[0,0],anchor], seg1),
n = is_undef(isect)? [0,1] : n = is_undef(isect)? [0,1] :
!approx(isect, t[1])? line_normal(seg1) : !approx(isect, t[1])? line_normal(seg1) :
unit((line_normal(seg1)+line_normal(seg2))/2), unit((line_normal(seg1)+line_normal(seg2))/2,[0,1]),
n2 = vector_angle(anchor,n)>90? -n : n n2 = vector_angle(anchor,n)>90? -n : n
) )
if(!is_undef(isect) && !approx(isect,t[0])) [norm(isect), isect, n2] if(!is_undef(isect) && !approx(isect,t[0])) [norm(isect), isect, n2]
@ -542,7 +543,7 @@ function find_anchor(anchor, geom) =
maxidx = max_index(subindex(isects,0)), maxidx = max_index(subindex(isects,0)),
isect = isects[maxidx], isect = isects[maxidx],
pos = point2d(cp) + isect[1], pos = point2d(cp) + isect[1],
vec = unit(isect[2]) vec = unit(isect[2],[0,1])
) [anchor, pos, vec, 0] ) [anchor, pos, vec, 0]
) : type == "path_extent"? ( //path ) : type == "path_extent"? ( //path
let( let(

View file

@ -237,8 +237,8 @@ module stroke(
} else { } else {
quatsums = Q_Cumulative([ quatsums = Q_Cumulative([
for (i = idx(path2,end=-2)) let( for (i = idx(path2,end=-2)) let(
vec1 = i==0? UP : unit(path2[i]-path2[i-1]), vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP),
vec2 = unit(path2[i+1]-path2[i]), vec2 = unit(path2[i+1]-path2[i], UP),
axis = vector_axis(vec1,vec2), axis = vector_axis(vec1,vec2),
ang = vector_angle(vec1,vec2) ang = vector_angle(vec1,vec2)
) Quat(axis,ang) ) Quat(axis,ang)
@ -961,8 +961,8 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
tipp = polar_to_xy(r-inset+rounding,a1), tipp = polar_to_xy(r-inset+rounding,a1),
pos = (p1+p2)/2 pos = (p1+p2)/2
) each [ ) each [
anchorpt(str("tip",i), tipp, unit(tipp), 0), anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0),
anchorpt(str("side",i), pos, unit(pos), 0), anchorpt(str("side",i), pos, unit(pos,BACK), 0),
] ]
] ]
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path, anchors=anchors); ) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path, anchors=anchors);
@ -983,8 +983,8 @@ module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false,
tipp = polar_to_xy(r-inset+rounding,a1), tipp = polar_to_xy(r-inset+rounding,a1),
pos = (p1+p2)/2 pos = (p1+p2)/2
) each [ ) each [
anchorpt(str("tip",i), tipp, unit(tipp), 0), anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0),
anchorpt(str("side",i), pos, unit(pos), 0), anchorpt(str("side",i), pos, unit(pos,BACK), 0),
] ]
]; ];
attachable(anchor,spin, two_d=true, path=path, extent=false, anchors=anchors) { attachable(anchor,spin, two_d=true, path=path, extent=false, anchors=anchors) {
@ -1332,9 +1332,9 @@ function star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=
p3 = polar_to_xy(r,a3), p3 = polar_to_xy(r,a3),
pos = (p1+p3)/2 pos = (p1+p3)/2
) each [ ) each [
anchorpt(str("tip",i), p1, unit(p1), 0), anchorpt(str("tip",i), p1, unit(p1,BACK), 0),
anchorpt(str("corner",i), p2, unit(p2), 0), anchorpt(str("corner",i), p2, unit(p2,BACK), 0),
anchorpt(str("midpt",i), pos, unit(pos), 0), anchorpt(str("midpt",i), pos, unit(pos,BACK), 0),
] ]
] ]
) reorient(anchor,spin, two_d=true, path=path, p=path, anchors=anchors); ) reorient(anchor,spin, two_d=true, path=path, p=path, anchors=anchors);
@ -1355,9 +1355,9 @@ module star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0)
p3 = polar_to_xy(r,a3), p3 = polar_to_xy(r,a3),
pos = (p1+p3)/2 pos = (p1+p3)/2
) each [ ) each [
anchorpt(str("tip",i), p1, unit(p1), 0), anchorpt(str("tip",i), p1, unit(p1,BACK), 0),
anchorpt(str("corner",i), p2, unit(p2), 0), anchorpt(str("corner",i), p2, unit(p2,BACK), 0),
anchorpt(str("midpt",i), pos, unit(pos), 0), anchorpt(str("midpt",i), pos, unit(pos,BACK), 0),
] ]
]; ];
attachable(anchor,spin, two_d=true, path=path, anchors=anchors) { attachable(anchor,spin, two_d=true, path=path, anchors=anchors) {

View file

@ -87,7 +87,7 @@ module test_line_normal() {
assert(line_normal([[0,0],[-10,0]]) == [0,-1]); assert(line_normal([[0,0],[-10,0]]) == [0,-1]);
assert(line_normal([[0,0],[0,-10]]) == [1,0]); assert(line_normal([[0,0],[0,-10]]) == [1,0]);
assert(approx(line_normal([[0,0],[10,10]]), [-sqrt(2)/2,sqrt(2)/2])); assert(approx(line_normal([[0,0],[10,10]]), [-sqrt(2)/2,sqrt(2)/2]));
pts = [for (i=list_range(1000)) rands(-100,100,2,seed_value=4312)]; pts = [for (p=pair(rands(-100,100,1000,seed_value=4312))) p];
for (p = pair_wrap(pts)) { for (p = pair_wrap(pts)) {
p1 = p.x; p1 = p.x;
p2 = p.y; p2 = p.y;
@ -351,18 +351,18 @@ module test_tri_functions() {
opp = p.y; opp = p.y;
hyp = norm([opp,adj]); hyp = norm([opp,adj]);
ang = atan2(opp,adj); ang = atan2(opp,adj);
assert(approx(hyp_opp_to_adj(hyp,opp),adj)); assert_approx(hyp_opp_to_adj(hyp,opp), adj);
assert(approx(hyp_ang_to_adj(hyp,ang),adj)); assert_approx(hyp_ang_to_adj(hyp,ang), adj);
assert(approx(opp_ang_to_adj(opp,ang),adj)); assert_approx(opp_ang_to_adj(opp,ang), adj);
assert(approx(hyp_adj_to_opp(hyp,adj),opp)); assert_approx(hyp_adj_to_opp(hyp,adj), opp);
assert(approx(hyp_ang_to_opp(hyp,ang),opp)); assert_approx(hyp_ang_to_opp(hyp,ang), opp);
assert(approx(adj_ang_to_opp(adj,ang),opp)); assert_approx(adj_ang_to_opp(adj,ang), opp);
assert(approx(adj_opp_to_hyp(adj,opp),hyp)); assert_approx(adj_opp_to_hyp(adj,opp), hyp);
assert(approx(adj_ang_to_hyp(adj,ang),hyp)); assert_approx(adj_ang_to_hyp(adj,ang), hyp);
assert(approx(opp_ang_to_hyp(opp,ang),hyp)); assert_approx(opp_ang_to_hyp(opp,ang), hyp);
assert(approx(hyp_adj_to_ang(hyp,adj),ang)); assert_approx(hyp_adj_to_ang(hyp,adj), ang);
assert(approx(hyp_opp_to_ang(hyp,opp),ang)); assert_approx(hyp_opp_to_ang(hyp,opp), ang);
assert(approx(adj_opp_to_ang(adj,opp),ang)); assert_approx(adj_opp_to_ang(adj,opp), ang);
} }
} }
test_tri_functions(); test_tri_functions();

View file

@ -105,18 +105,25 @@ function vceil(v) = [for (x=v) ceil(x)];
// Function: unit() // Function: unit()
// Usage:
// unit(v, [dflt]);
// Description: // Description:
// Returns unit length normalized version of vector v. // Returns unit length normalized version of vector v. If passed a zero-length vector,
// If passed a zero-length vector, returns the unchanged vector. // asserts an error unless `dflt` is given, in which case the value of `dflt` is returned.
// Arguments: // Arguments:
// v = The vector to normalize. // v = The vector to normalize.
// dflt = If given, and input is a zero-length vector, this value is returned. Default: `undef` (assert error on zero-length vector)
// Examples: // Examples:
// unit([10,0,0]); // Returns: [1,0,0] // unit([10,0,0]); // Returns: [1,0,0]
// unit([0,10,0]); // Returns: [0,1,0] // unit([0,10,0]); // Returns: [0,1,0]
// unit([0,0,10]); // Returns: [0,0,1] // unit([0,0,10]); // Returns: [0,0,1]
// unit([0,-10,0]); // Returns: [0,-1,0] // unit([0,-10,0]); // Returns: [0,-1,0]
// unit([0,0,0]); // Returns: [0,0,0] // unit([0,0,0],[1,2,3]); // Returns: [1,2,3]
function unit(v) = assert(is_vector(v),str(v)) norm(v)<=EPSILON? v : v/norm(v); // unit([0,0,0]); // Asserts an error.
function unit(v, dflt) =
assert(is_vector(v), str("Expected a vector. Got: ",v))
norm(v)<EPSILON? (is_undef(dflt)? assert(norm(v)>=EPSILON) : dflt) :
v/norm(v);
// Function: vector_angle() // Function: vector_angle()

View file

@ -8,7 +8,7 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,389]; BOSL_VERSION = [2,0,390];
// Section: BOSL Library Version Functions // Section: BOSL Library Version Functions