diff --git a/attachments.scad b/attachments.scad index 323a2ef..1c4b19a 100644 --- a/attachments.scad +++ b/attachments.scad @@ -420,12 +420,12 @@ function find_anchor(anchor, geom) = bot = point3d(vmul(point2d(size)/2,axy),-h/2), top = point3d(vmul(point2d(size2)/2,axy)+shift,h/2), 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]), vec = anchor==CENTER? UP : - approx(axy,[0,0])? unit(anchor) : + approx(axy,[0,0])? unit(anchor,UP) : approx(anchor.z,0)? sidevec : - unit((sidevec+vvec)/2) + unit((sidevec+vvec)/2,UP) ) [anchor, pos, vec, oang] ) : type == "cyl"? ( //r1, r2, l, shift let( @@ -433,24 +433,24 @@ function find_anchor(anchor, geom) = r1 = is_num(rr1)? [rr1,rr1] : rr1, r2 = is_num(rr2)? [rr2,rr2] : rr2, u = (anchor.z+1)/2, - axy = unit(point2d(anchor)), + axy = unit(point2d(anchor),[0,0]), bot = point3d(vmul(r1,axy), -l/2), top = point3d(vmul(r2,axy)+shift, l/2), pos = point3d(cp) + lerp(bot,top,u) + offset, 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 : - approx(axy,[0,0])? unit(anchor) : + approx(axy,[0,0])? unit(anchor,UP) : approx(anchor.z,0)? sidevec : - unit((sidevec+vvec)/2) + unit((sidevec+vvec)/2,UP) ) [anchor, pos, vec, oang] ) : type == "spheroid"? ( //r let( rr = geom[1], r = is_num(rr)? [rr,rr,rr] : rr, - anchor = unit(point3d(anchor)), + anchor = unit(point3d(anchor),CENTER), pos = point3d(cp) + vmul(r,anchor) + offset, - vec = unit(vmul(r,anchor)) + vec = unit(vmul(r,anchor),UP) ) [anchor, pos, vec, oang] ) : type == "vnf_isect"? ( //vnf let( @@ -490,7 +490,8 @@ function find_anchor(anchor, geom) = faceplane = plane_from_points(faceverts), nrm = plane_normal(faceplane) ) nrm - ]) / len(nfaces) + ]) / len(nfaces), + UP ) ) [anchor, pos, n, oang] @@ -513,15 +514,15 @@ function find_anchor(anchor, geom) = frpt = [size.x/2*anchor.x, -size.y/2], bkpt = [size2/2*anchor.x, size.y/2], 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] ) : type == "circle"? ( //r let( rr = geom[1], r = is_num(rr)? [rr,rr] : rr, pos = point2d(cp) + vmul(r,anchor) + offset, - anchor = unit(point2d(anchor)), - vec = unit(vmul([r.y,r.x],anchor)) + anchor = unit(point2d(anchor),[0,0]), + vec = unit(vmul([r.y,r.x],anchor),[0,1]) ) [anchor, pos, vec, 0] ) : type == "path_isect"? ( //path let( @@ -534,7 +535,7 @@ function find_anchor(anchor, geom) = isect = ray_segment_intersection([[0,0],anchor], seg1), n = is_undef(isect)? [0,1] : !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 ) 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)), isect = isects[maxidx], pos = point2d(cp) + isect[1], - vec = unit(isect[2]) + vec = unit(isect[2],[0,1]) ) [anchor, pos, vec, 0] ) : type == "path_extent"? ( //path let( diff --git a/shapes2d.scad b/shapes2d.scad index 9a71124..9622ad4 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -237,8 +237,8 @@ module stroke( } else { quatsums = Q_Cumulative([ for (i = idx(path2,end=-2)) let( - vec1 = i==0? UP : unit(path2[i]-path2[i-1]), - vec2 = unit(path2[i+1]-path2[i]), + vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP), + vec2 = unit(path2[i+1]-path2[i], UP), axis = vector_axis(vec1,vec2), ang = vector_angle(vec1,vec2) ) 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), pos = (p1+p2)/2 ) each [ - anchorpt(str("tip",i), tipp, unit(tipp), 0), - anchorpt(str("side",i), pos, unit(pos), 0), + anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0), + anchorpt(str("side",i), pos, unit(pos,BACK), 0), ] ] ) 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), pos = (p1+p2)/2 ) each [ - anchorpt(str("tip",i), tipp, unit(tipp), 0), - anchorpt(str("side",i), pos, unit(pos), 0), + anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0), + anchorpt(str("side",i), pos, unit(pos,BACK), 0), ] ]; 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), pos = (p1+p3)/2 ) each [ - anchorpt(str("tip",i), p1, unit(p1), 0), - anchorpt(str("corner",i), p2, unit(p2), 0), - anchorpt(str("midpt",i), pos, unit(pos), 0), + anchorpt(str("tip",i), p1, unit(p1,BACK), 0), + anchorpt(str("corner",i), p2, unit(p2,BACK), 0), + anchorpt(str("midpt",i), pos, unit(pos,BACK), 0), ] ] ) 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), pos = (p1+p3)/2 ) each [ - anchorpt(str("tip",i), p1, unit(p1), 0), - anchorpt(str("corner",i), p2, unit(p2), 0), - anchorpt(str("midpt",i), pos, unit(pos), 0), + anchorpt(str("tip",i), p1, unit(p1,BACK), 0), + anchorpt(str("corner",i), p2, unit(p2,BACK), 0), + anchorpt(str("midpt",i), pos, unit(pos,BACK), 0), ] ]; attachable(anchor,spin, two_d=true, path=path, anchors=anchors) { diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad index 4b6dd90..dca4069 100644 --- a/tests/test_geometry.scad +++ b/tests/test_geometry.scad @@ -87,7 +87,7 @@ module test_line_normal() { assert(line_normal([[0,0],[-10,0]]) == [0,-1]); assert(line_normal([[0,0],[0,-10]]) == [1,0]); 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)) { p1 = p.x; p2 = p.y; @@ -351,18 +351,18 @@ module test_tri_functions() { opp = p.y; hyp = norm([opp,adj]); ang = atan2(opp,adj); - assert(approx(hyp_opp_to_adj(hyp,opp),adj)); - assert(approx(hyp_ang_to_adj(hyp,ang),adj)); - assert(approx(opp_ang_to_adj(opp,ang),adj)); - assert(approx(hyp_adj_to_opp(hyp,adj),opp)); - assert(approx(hyp_ang_to_opp(hyp,ang),opp)); - assert(approx(adj_ang_to_opp(adj,ang),opp)); - assert(approx(adj_opp_to_hyp(adj,opp),hyp)); - assert(approx(adj_ang_to_hyp(adj,ang),hyp)); - assert(approx(opp_ang_to_hyp(opp,ang),hyp)); - assert(approx(hyp_adj_to_ang(hyp,adj),ang)); - assert(approx(hyp_opp_to_ang(hyp,opp),ang)); - assert(approx(adj_opp_to_ang(adj,opp),ang)); + assert_approx(hyp_opp_to_adj(hyp,opp), adj); + assert_approx(hyp_ang_to_adj(hyp,ang), adj); + assert_approx(opp_ang_to_adj(opp,ang), adj); + assert_approx(hyp_adj_to_opp(hyp,adj), opp); + assert_approx(hyp_ang_to_opp(hyp,ang), opp); + assert_approx(adj_ang_to_opp(adj,ang), opp); + assert_approx(adj_opp_to_hyp(adj,opp), hyp); + assert_approx(adj_ang_to_hyp(adj,ang), hyp); + assert_approx(opp_ang_to_hyp(opp,ang), hyp); + assert_approx(hyp_adj_to_ang(hyp,adj), ang); + assert_approx(hyp_opp_to_ang(hyp,opp), ang); + assert_approx(adj_opp_to_ang(adj,opp), ang); } } test_tri_functions(); diff --git a/vectors.scad b/vectors.scad index 1ee1f5d..8ac891f 100644 --- a/vectors.scad +++ b/vectors.scad @@ -105,18 +105,25 @@ function vceil(v) = [for (x=v) ceil(x)]; // Function: unit() +// Usage: +// unit(v, [dflt]); // Description: -// Returns unit length normalized version of vector v. -// If passed a zero-length vector, returns the unchanged vector. +// Returns unit length normalized version of vector v. If passed a zero-length vector, +// asserts an error unless `dflt` is given, in which case the value of `dflt` is returned. // Arguments: // 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: // unit([10,0,0]); // Returns: [1,0,0] // unit([0,10,0]); // Returns: [0,1,0] // unit([0,0,10]); // Returns: [0,0,1] // unit([0,-10,0]); // Returns: [0,-1,0] -// unit([0,0,0]); // Returns: [0,0,0] -function unit(v) = assert(is_vector(v),str(v)) norm(v)<=EPSILON? v : v/norm(v); +// unit([0,0,0],[1,2,3]); // Returns: [1,2,3] +// unit([0,0,0]); // Asserts an error. +function unit(v, dflt) = + assert(is_vector(v), str("Expected a vector. Got: ",v)) + norm(v)=EPSILON) : dflt) : + v/norm(v); // Function: vector_angle() diff --git a/version.scad b/version.scad index 4402f4c..d88799c 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,389]; +BOSL_VERSION = [2,0,390]; // Section: BOSL Library Version Functions