Merge branch 'master' into master

This commit is contained in:
RonaldoCMP 2020-07-24 14:47:25 +01:00 committed by GitHub
commit d2e851ae42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 287 additions and 127 deletions

View file

@ -277,9 +277,9 @@ function affine_frame_map(x,y,z, reverse=false) =
assert(yvalid,"Input y must be a length 3 vector") assert(yvalid,"Input y must be a length 3 vector")
assert(zvalid,"Input z must be a length 3 vector") assert(zvalid,"Input z must be a length 3 vector")
let( let(
x = is_undef(x)? undef : unit(x), x = is_undef(x)? undef : unit(x,RIGHT),
y = is_undef(y)? undef : unit(y), y = is_undef(y)? undef : unit(y,BACK),
z = is_undef(z)? undef : unit(z), z = is_undef(z)? undef : unit(z,UP),
map = is_undef(x)? [cross(y,z), y, z] : map = is_undef(x)? [cross(y,z), y, z] :
is_undef(y)? [x, cross(z,x), z] : is_undef(y)? [x, cross(z,x), z] :
is_undef(z)? [x, y, cross(x,y)] : is_undef(z)? [x, y, cross(x,y)] :

View file

@ -104,21 +104,13 @@ function slice(list,start,end) =
// in_list("bar", ["foo", "bar", "baz"]); // Returns true. // in_list("bar", ["foo", "bar", "baz"]); // Returns true.
// in_list("bee", ["foo", "bar", "baz"]); // Returns false. // in_list("bee", ["foo", "bar", "baz"]); // Returns false.
// in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true. // in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true.
// in_list("bee", ["foo", "bar", ["bee",0]]); // Returns true.
// in_list("bar", [[2,"foo"], [4,["bar"]], [3,"baz"]]); // Returns false.
// Note:
// When `val==NAN` the answer will be false for any list.
// `val` cannot be a boolean.
// When the some element in `list` is a list containing `val` at it first element, the return is also true.
function in_list(val,list,idx=undef) = function in_list(val,list,idx=undef) =
let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] ) let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] )
s==[] || s[0]==[] ? false s==[] ? false
: is_undef(idx) ? val==list[s] : is_undef(idx) ? val==list[s]
: val==list[s][idx]; : val==list[s][idx];
//***
// 1. for sake of consistence, the arguments were changed to val and list
// 2. in_list(0,[ 1, [0,1],2])) was returning true
// Function: min_index() // Function: min_index()

View file

@ -421,7 +421,7 @@ function find_anchor(anchor, geom) =
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)),UP), 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],UP),
vec = anchor==CENTER? UP : vec = anchor==CENTER? UP :
approx(axy,[0,0])? unit(anchor,UP) : approx(axy,[0,0])? unit(anchor,UP) :
approx(anchor.z,0)? sidevec : approx(anchor.z,0)? sidevec :

View file

@ -191,16 +191,17 @@ module debug_faces(vertices, faces, size=1, disabled=false) {
if (face[0] < 0 || face[1] < 0 || face[2] < 0 || face[0] >= vlen || face[1] >= vlen || face[2] >= vlen) { if (face[0] < 0 || face[1] < 0 || face[2] < 0 || face[0] >= vlen || face[1] >= vlen || face[2] >= vlen) {
echo("BAD FACE: ", vlen=vlen, face=face); echo("BAD FACE: ", vlen=vlen, face=face);
} else { } else {
v0 = vertices[face[0]]; verts = select(vertices,face);
v1 = vertices[face[1]]; c = mean(verts);
v2 = vertices[face[2]]; v0 = verts[0];
c = mean(select(vertices,face)); v1 = verts[1];
v2 = verts[2];
dv0 = unit(v1 - v0); dv0 = unit(v1 - v0);
dv1 = unit(v2 - v0); dv1 = unit(v2 - v0);
nrm0 = unit(cross(dv0, dv1)); nrm0 = cross(dv0, dv1);
nrm1 = [0, 0, 1]; nrm1 = UP;
axis = unit(cross(nrm0, nrm1)); axis = vector_axis(nrm0, nrm1);
ang = vector_angle(nrm0, nrm1); ang = vector_angle(nrm0, nrm1);
theta = atan2(nrm0[1], nrm0[0]); theta = atan2(nrm0[1], nrm0[0]);
translate(c) { translate(c) {
rotate(a=180-ang, v=axis) { rotate(a=180-ang, v=axis) {

View file

@ -133,8 +133,9 @@ function distance_from_line(line, pt) =
// color("green") stroke([p1,p1+10*n], endcap2="arrow2"); // color("green") stroke([p1,p1+10*n], endcap2="arrow2");
// color("blue") move_copies([p1,p2]) circle(d=2, $fn=12); // color("blue") move_copies([p1,p2]) circle(d=2, $fn=12);
function line_normal(p1,p2) = function line_normal(p1,p2) =
is_undef(p2)? line_normal(p1[0],p1[1]) : is_undef(p2)?
unit([p1.y-p2.y,p2.x-p1.x]); assert(is_path(p1,2)) line_normal(p1[0],p1[1]) :
assert(is_vector(p1,2)&&is_vector(p2,2)) unit([p1.y-p2.y,p2.x-p1.x]);
// 2D Line intersection from two segments. // 2D Line intersection from two segments.
@ -252,34 +253,192 @@ function segment_intersection(s1,s2,eps=EPSILON) =
// Usage: // Usage:
// line_closest_point(line,pt); // line_closest_point(line,pt);
// Description: // Description:
// Returns the point on the given `line` that is closest to the given point `pt`. // Returns the point on the given 2D or 3D `line` that is closest to the given point `pt`.
// The `line` and `pt` args should either both be 2D or both 3D.
// Arguments: // Arguments:
// line = A list of two points that are on the unbounded line. // line = A list of two points that are on the unbounded line.
// pt = The point to find the closest point on the line to. // pt = The point to find the closest point on the line to.
// Example(2D):
// line = [[-30,0],[30,30]];
// pt = [-32,-10];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// line = [[-30,0],[30,30]];
// pt = [-5,0];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// line = [[-30,0],[30,30]];
// pt = [40,25];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(FlatSpin):
// line = [[-30,-15,0],[30,15,30]];
// pt = [5,5,5];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// line = [[-30,-15,0],[30,15,30]];
// pt = [-35,-15,0];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// line = [[-30,-15,0],[30,15,30]];
// pt = [40,15,25];
// p2 = line_closest_point(line,pt);
// stroke(line, endcaps="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
function line_closest_point(line,pt) = function line_closest_point(line,pt) =
assert(is_path(line)&&len(line)==2)
assert(same_shape(pt,line[0]))
assert(!approx(line[0],line[1]))
let( let(
n = line_normal(line), seglen = norm(line[1]-line[0]),
isect = _general_line_intersection(line,[pt,pt+n]) segvec = (line[1]-line[0])/seglen,
) isect[0]; projection = (pt-line[0]) * segvec
)
line[0] + projection*segvec;
// Function: ray_closest_point()
// Usage:
// ray_closest_point(seg,pt);
// Description:
// Returns the point on the given 2D or 3D ray `ray` that is closest to the given point `pt`.
// The `ray` and `pt` args should either both be 2D or both 3D.
// Arguments:
// ray = The ray, given as a list `[START,POINT]` of the start-point START, and a point POINT on the ray.
// pt = The point to find the closest point on the ray to.
// Example(2D):
// ray = [[-30,0],[30,30]];
// pt = [-32,-10];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// ray = [[-30,0],[30,30]];
// pt = [-5,0];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// ray = [[-30,0],[30,30]];
// pt = [40,25];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(FlatSpin):
// ray = [[-30,-15,0],[30,15,30]];
// pt = [5,5,5];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// ray = [[-30,-15,0],[30,15,30]];
// pt = [-35,-15,0];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// ray = [[-30,-15,0],[30,15,30]];
// pt = [40,15,25];
// p2 = ray_closest_point(ray,pt);
// stroke(ray, endcap2="arrow2");
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
function ray_closest_point(ray,pt) =
assert(is_path(ray)&&len(ray)==2)
assert(same_shape(pt,ray[0]))
assert(!approx(ray[0],ray[1]))
let(
seglen = norm(ray[1]-ray[0]),
segvec = (ray[1]-ray[0])/seglen,
projection = (pt-ray[0]) * segvec
)
projection<=0 ? ray[0] :
ray[0] + projection*segvec;
// Function: segment_closest_point() // Function: segment_closest_point()
// Usage: // Usage:
// segment_closest_point(seg,pt); // segment_closest_point(seg,pt);
// Description: // Description:
// Returns the point on the given line segment `seg` that is closest to the given point `pt`. // Returns the point on the given 2D or 3D line segment `seg` that is closest to the given point `pt`.
// The `seg` and `pt` args should either both be 2D or both 3D.
// Arguments: // Arguments:
// seg = A list of two points that are the endpoints of the bounded line segment. // seg = A list of two points that are the endpoints of the bounded line segment.
// pt = The point to find the closest point on the segment to. // pt = The point to find the closest point on the segment to.
// Example(2D):
// seg = [[-30,0],[30,30]];
// pt = [-32,-10];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// seg = [[-30,0],[30,30]];
// pt = [-5,0];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(2D):
// seg = [[-30,0],[30,30]];
// pt = [40,25];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) circle(r=1,$fn=12);
// color("red") translate(p2) circle(r=1,$fn=12);
// Example(FlatSpin):
// seg = [[-30,-15,0],[30,15,30]];
// pt = [5,5,5];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// seg = [[-30,-15,0],[30,15,30]];
// pt = [-35,-15,0];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
// Example(FlatSpin):
// seg = [[-30,-15,0],[30,15,30]];
// pt = [40,15,25];
// p2 = segment_closest_point(seg,pt);
// stroke(seg);
// color("blue") translate(pt) sphere(r=1,$fn=12);
// color("red") translate(p2) sphere(r=1,$fn=12);
function segment_closest_point(seg,pt) = function segment_closest_point(seg,pt) =
assert(is_path(seg)&&len(seg)==2)
assert(same_shape(pt,seg[0]))
approx(seg[0],seg[1])? seg[0] :
let( let(
n = line_normal(seg), seglen = norm(seg[1]-seg[0]),
isect = _general_line_intersection(seg,[pt,pt+n]) segvec = (seg[1]-seg[0])/seglen,
projection = (pt-seg[0]) * segvec
) )
norm(n)==0? seg[0] : projection<=0 ? seg[0] :
isect[1]<=0? seg[0] : projection>=seglen ? seg[1] :
isect[1]>=1? seg[1] : seg[0] + projection*segvec;
isect[0];
// Section: 2D Triangles // Section: 2D Triangles

View file

@ -159,6 +159,7 @@ include <structs.scad>
// fwd(60) // Note how the different points are cut back by different amounts // fwd(60) // Note how the different points are cut back by different amounts
// stroke(round_corners(zig,radius=1.5,closed=false),width=1); // stroke(round_corners(zig,radius=1.5,closed=false),width=1);
// Example(FlatSpin): Rounding some random 3D paths // Example(FlatSpin): Rounding some random 3D paths
// $fn=36;
// list1= [ // list1= [
// [2.887360, 4.03497, 6.372090], // [2.887360, 4.03497, 6.372090],
// [5.682210, 9.37103, 0.783548], // [5.682210, 9.37103, 0.783548],
@ -926,10 +927,10 @@ function os_profile(points, extra,check_valid, quality, offset_maxstep, offset)
// //
// Example: Chamfered elliptical prism. If you stretch a chamfered cylinder the chamfer will be uneven. // Example: Chamfered elliptical prism. If you stretch a chamfered cylinder the chamfer will be uneven.
// convex_offset_extrude(bottom = os_chamfer(height=-2), top=os_chamfer(height=1), height=7) // convex_offset_extrude(bottom = os_chamfer(height=-2), top=os_chamfer(height=1), height=7)
// xscale(4)circle(r=6); // xscale(4)circle(r=6,$fn=64);
// Example: Elliptical prism with circular roundovers. // Example: Elliptical prism with circular roundovers.
// convex_offset_extrude(bottom=os_circle(r=-2), top=os_circle(r=1), height=7,steps=10) // convex_offset_extrude(bottom=os_circle(r=-2), top=os_circle(r=1), height=7,steps=10)
// xscale(4)circle(r=6); // xscale(4)circle(r=6,$fn=64);
// Example: If you give a non-convex input you get a convex hull output // Example: If you give a non-convex input you get a convex hull output
// right(50) linear_extrude(height=7) star(5,r=22,ir=13); // right(50) linear_extrude(height=7) star(5,r=22,ir=13);
// convex_offset_extrude(bottom = os_chamfer(height=-2), top=os_chamfer(height=1), height=7) // convex_offset_extrude(bottom = os_chamfer(height=-2), top=os_chamfer(height=1), height=7)
@ -1122,6 +1123,7 @@ function _remove_undefined_vals(list) =
// fwd(7) // fwd(7)
// offset_stroke(arc, width=2, start=os_pointed(loc=2,dist=2),end=os_pointed(loc=.5,dist=-1)); // offset_stroke(arc, width=2, start=os_pointed(loc=2,dist=2),end=os_pointed(loc=.5,dist=-1));
// Example(2D): The os_round() end treatment adds roundovers to the end corners by specifying the `cut` parameter. In the first example, the cut parameter is the same at each corner. The bezier smoothness parameter `k` is given to allow a larger cut. In the second example, each corner is given a different roundover, including zero for no rounding at all. The red shows the same strokes without the roundover. // Example(2D): The os_round() end treatment adds roundovers to the end corners by specifying the `cut` parameter. In the first example, the cut parameter is the same at each corner. The bezier smoothness parameter `k` is given to allow a larger cut. In the second example, each corner is given a different roundover, including zero for no rounding at all. The red shows the same strokes without the roundover.
// $fn=36;
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50); // arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// path = [[0,0],[6,2],[9,7],[8,10]]; // path = [[0,0],[6,2],[9,7],[8,10]];
// offset_stroke(path, width=2, rounded=false,start=os_round(angle=-20, cut=0.4,k=.9), end=os_round(angle=-35, cut=0.4,k=.9)); // offset_stroke(path, width=2, rounded=false,start=os_round(angle=-20, cut=0.4,k=.9), end=os_round(angle=-35, cut=0.4,k=.9));
@ -1133,9 +1135,9 @@ function _remove_undefined_vals(list) =
// Example(2D): Negative cut values produce a flaring end. Note how the absolute angle aligns the ends of the first example withi the axes. In the second example positive and negative cut values are combined. Note also that very different cuts are needed at the start end to produce a similar looking flare. // Example(2D): Negative cut values produce a flaring end. Note how the absolute angle aligns the ends of the first example withi the axes. In the second example positive and negative cut values are combined. Note also that very different cuts are needed at the start end to produce a similar looking flare.
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50); // arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// path = [[0,0],[6,2],[9,7],[8,10]]; // path = [[0,0],[6,2],[9,7],[8,10]];
// offset_stroke(path, width=2, rounded=false,start=os_round(cut=-1, abs_angle=90), end=os_round(cut=-0.5, abs_angle=0)); // offset_stroke(path, width=2, rounded=false,start=os_round(cut=-1, abs_angle=90), end=os_round(cut=-0.5, abs_angle=0),$fn=36);
// right(10) // right(10)
// offset_stroke(arc, width=2, rounded=false, start=os_round(cut=[-.75,-.2], angle=-45), end=os_round(cut=[-.2,.2], angle=20)); // offset_stroke(arc, width=2, rounded=false, start=os_round(cut=[-.75,-.2], angle=-45), end=os_round(cut=[-.2,.2], angle=20),$fn=36);
// Example(2D): Setting the width to a vector allows generation of a set of parallel strokes // Example(2D): Setting the width to a vector allows generation of a set of parallel strokes
// path = [[0,0],[4,4],[8,4],[2,9],[10,10]]; // path = [[0,0],[4,4],[8,4],[2,9],[10,10]];
// for(i=[0:.25:2]) // for(i=[0:.25:2])
@ -1146,9 +1148,9 @@ function _remove_undefined_vals(list) =
// offset_stroke(path, rounded=true,width = [i,i+.08]); // offset_stroke(path, rounded=true,width = [i,i+.08]);
// Example(2D): In this example a spurious triangle appears. This results from overly enthusiastic validity checking. Turning validity checking off fixes it in this case. // Example(2D): In this example a spurious triangle appears. This results from overly enthusiastic validity checking. Turning validity checking off fixes it in this case.
// path = [[0,0],[4,4],[8,4],[2,9],[10,10]]; // path = [[0,0],[4,4],[8,4],[2,9],[10,10]];
// offset_stroke(path, check_valid=true,rounded=false,width = [1.4, 1.45]); // offset_stroke(path, check_valid=true,rounded=false,width = [1.4, 1.5]);
// right(2) // right(2)
// offset_stroke(path, check_valid=false,rounded=false,width = [1.4, 1.45]); // offset_stroke(path, check_valid=false,rounded=false,width = [1.4, 1.5]);
// Example(2D): But in this case, disabling the validity check produces an invalid result. // Example(2D): But in this case, disabling the validity check produces an invalid result.
// path = [[0,0],[4,4],[8,4],[2,9],[10,10]]; // path = [[0,0],[4,4],[8,4],[2,9],[10,10]];
// offset_stroke(path, check_valid=true,rounded=false,width = [1.9, 2]); // offset_stroke(path, check_valid=true,rounded=false,width = [1.9, 2]);
@ -1786,7 +1788,7 @@ function _circle_mask(r) =
// less than 180 degrees, and the path shouldn't have closely spaced points at concave points of high curvature because // less than 180 degrees, and the path shouldn't have closely spaced points at concave points of high curvature because
// this will cause self-intersection in the mask polyhedron, resulting in CGAL failures. // this will cause self-intersection in the mask polyhedron, resulting in CGAL failures.
// Arguments: // Arguments:
// r|radius = center radius of the cylindrical shell to cut a hole in // r / radius = center radius of the cylindrical shell to cut a hole in
// thickness = thickness of cylindrical shell (may need to be slighly oversized) // thickness = thickness of cylindrical shell (may need to be slighly oversized)
// path = 2d path that defines the hole to cut // path = 2d path that defines the hole to cut
// Example: The mask as long pointed ends because this was the most efficient way to close off those ends. // Example: The mask as long pointed ends because this was the most efficient way to close off those ends.

View file

@ -97,7 +97,7 @@ def image_compare(file1, file2):
sq = (value * (i % 256) ** 2 for i, value in enumerate(diff)) sq = (value * (i % 256) ** 2 for i, value in enumerate(diff))
sum_squares = sum(sq) sum_squares = sum(sq)
rms = math.sqrt(sum_squares / float(img1.size[0] * img1.size[1])) rms = math.sqrt(sum_squares / float(img1.size[0] * img1.size[1]))
return rms<10 return rms<2
def image_resize(infile, outfile, newsize=(320,240)): def image_resize(infile, outfile, newsize=(320,240)):

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/hull.scad> include <../hull.scad>
testpoints_on_sphere = [ for(p = testpoints_on_sphere = [ for(p =

View file

@ -1,5 +1,5 @@
include<BOSL2/std.scad> include<../std.scad>
include<BOSL2/polyhedra.scad> include<../polyhedra.scad>
$fn=96; $fn=96;

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_ident() { module test_ident() {

View file

@ -33,9 +33,13 @@ module test_in_list() {
assert(in_list("bar", ["foo", "bar", "baz"])); assert(in_list("bar", ["foo", "bar", "baz"]));
assert(!in_list("bee", ["foo", "bar", "baz"])); assert(!in_list("bee", ["foo", "bar", "baz"]));
assert(in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1)); assert(in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1));
assert(!in_list(undef, [3,4,5]));
assert(in_list(undef,[3,4,undef,5]));
assert(!in_list(3,[]));
assert(!in_list(3,[4,5,[3]]));
assert(!in_list("bee", ["foo", "bar", ["bee"]]));
assert(in_list(NAN, [NAN])==false);
} }
test_in_list(); test_in_list();

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_point2d() { module test_point2d() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/cubetruss.scad> include <../cubetruss.scad>
module test_cubetruss_dist() { module test_cubetruss_dist() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_standard_anchors() { module test_standard_anchors() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_is_edge_array() { module test_is_edge_array() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
// Can't test echo output as yet. Include these for coverage calculations. // Can't test echo output as yet. Include these for coverage calculations.

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_point_on_segment2d() { module test_point_on_segment2d() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/linear_bearings.scad> include <../linear_bearings.scad>
module test_get_lmXuu_bearing_diam() { module test_get_lmXuu_bearing_diam() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
// Simple Calculations // Simple Calculations

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_HSL() { module test_HSL() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_square() { module test_square() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/strings.scad> include <../strings.scad>
function rec_cmp(a,b,eps=1e-9) = function rec_cmp(a,b,eps=1e-9) =

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/queues.scad> include <../queues.scad>
module test_queue_init() { module test_queue_init() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/hull.scad> include <../hull.scad>
module test_prismoid() { module test_prismoid() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_turtle() { module test_turtle() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/skin.scad> include <../skin.scad>
module test_skin() { module test_skin() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/stacks.scad> include <../stacks.scad>
module test_stack_init() { module test_stack_init() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/strings.scad> include <../strings.scad>
module test_upcase() { module test_upcase() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/structs.scad> include <../structs.scad>
module test_struct_set() { module test_struct_set() {

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_translate() { module test_translate() {

View file

@ -9,10 +9,11 @@ module test_is_vector() {
assert(is_vector(1) == false); assert(is_vector(1) == false);
assert(is_vector("foo") == false); assert(is_vector("foo") == false);
assert(is_vector(true) == false); assert(is_vector(true) == false);
assert(is_vector([0,0],nonzero=true) == false);
assert(is_vector([0,1e-12,0],nonzero=true) == false); assert(is_vector([0,0,0],zero=true) == true);
assert(is_vector([0,1e-6,0],nonzero=true) == true); assert(is_vector([0,0,0],zero=false) == false);
assert(is_vector([0,1e-6,0],nonzero=true,eps=1e-4) == false); assert(is_vector([0,1,0],zero=true) == false);
assert(is_vector([0,0,1],zero=false) == true);
} }
test_is_vector(); test_is_vector();

View file

@ -1,4 +1,4 @@
include <BOSL2/std.scad> include <../std.scad>
module test_bosl_version() { module test_bosl_version() {

View file

@ -1,5 +1,5 @@
include <BOSL2/std.scad> include <../std.scad>
include <BOSL2/vnf.scad> include <../vnf.scad>
module test_is_vnf() { module test_is_vnf() {

View file

@ -19,31 +19,30 @@
// Arguments: // Arguments:
// v = The value to test to see if it is a vector. // v = The value to test to see if it is a vector.
// length = If given, make sure the vector is `length` items long. // length = If given, make sure the vector is `length` items long.
// zero = If false, require that the length of the vector is not approximately zero. If true, require the length of the vector to be approx zero-length. Default: `undef` (don't check vector length.)
// eps = The minimum vector length that is considered non-zero. Default: `EPSILON` (`1e-9`)
// Example: // Example:
// is_vector(4); // Returns false // is_vector(4); // Returns false
// is_vector([4,true,false]); // Returns false // is_vector([4,true,false]); // Returns false
// is_vector([3,4,INF,5]); // Returns false // is_vector([3,4,INF,5]); // Returns false
// is_vector([3,4,5,6]); // Returns true // is_vector([3,4,5,6]); // Returns true
// is_vector([3,4,undef,5]); // Returns false // is_vector([3,4,undef,5]); // Returns false
// is_vector([3,4,5],3); // Returns true // is_vector([3,4,5],3); // Returns true
// is_vector([3,4,5],4); // Returns true // is_vector([3,4,5],4); // Returns true
// is_vector([]); // Returns false // is_vector([]); // Returns false
// is_vector([0,4,0],3,nonzero=true); // Returns true // is_vector([0,0,0],zero=true); // Returns true
// is_vector([0,0,0],nonzero=true); // Returns false // is_vector([0,0,0],zero=false); // Returns false
// is_vector([0,0,1e-12],nonzero=true); // Returns false // is_vector([0,1,0],zero=true); // Returns false
// is_vector([],nonzero=true); // Returns false // is_vector([0,0,1],zero=false); // Returns true
function is_vector(v,length, nonzero=false, eps=EPSILON) = function is_vector(v,length,zero,eps=EPSILON) =
is_list(v) && is_num(0*(v*v)) is_list(v) && is_num(0*(v*v))
&& (is_undef(length)|| len(v)==length) && (is_undef(length) || len(v)==length)
&& ( ! nonzero || ([]!=[for(vi=v) if(abs(vi)>=eps) 1]) ); && (is_undef(zero) || ((norm(v) >= eps) == !zero));
//***
// including non_zero option
// extended examples
//*** //***
// add_scalar() is an array operation: moved to array.scad // add_scalar() is an array operation: moved to array.scad
// Function: vang() // Function: vang()
// Usage: // Usage:
// theta = vang([X,Y]); // theta = vang([X,Y]);
@ -204,26 +203,28 @@ function vector_axis(v1,v2=undef,v3=undef) =
is_vector(v3) is_vector(v3)
? assert(is_consistent([v3,v2,v1]), "Bad arguments.") ? assert(is_consistent([v3,v2,v1]), "Bad arguments.")
vector_axis(v1-v2, v3-v2) vector_axis(v1-v2, v3-v2)
: assert( is_undef(v3), "Bad arguments.") :
is_undef(v2) assert( is_undef(v3), "Bad arguments.")
? assert( is_list(v1), "Bad arguments.") is_undef(v2)
len(v1) == 2 ? assert( is_list(v1), "Bad arguments.")
? vector_axis(v1[0],v1[1]) len(v1) == 2
: vector_axis(v1[0],v1[1],v1[2]) ? vector_axis(v1[0],v1[1])
: assert( is_vector(v1,nonzero=true) && is_vector(v2,nonzero=true) && is_consistent([v1,v2]) : vector_axis(v1[0],v1[1],v1[2])
, "Bad arguments.") :
let( assert(
eps = 1e-6, is_vector(v1,zero=false) &&
w1 = point3d(v1/norm(v1)), is_vector(v2,zero=false) &&
w2 = point3d(v2/norm(v2)), is_consistent([v1,v2]),
w3 = (norm(w1-w2) > eps && norm(w1+w2) > eps) ? w2 "Bad arguments."
: (norm(vabs(w2)-UP) > eps)? UP )
: RIGHT let(
) unit(cross(w1,w3)); eps = 1e-6,
w1 = point3d(v1/norm(v1)),
w2 = point3d(v2/norm(v2)),
w3 = (norm(w1-w2) > eps && norm(w1+w2) > eps) ? w2
: (norm(vabs(w2)-UP) > eps) ? UP
: RIGHT
) unit(cross(w1,w3));
//***
// completing input data check and refactoring
// Note: vector_angle and vector_axis have the same kind of inputs and two code strategy alternatives
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

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