diff --git a/affine.scad b/affine.scad
index dd465db..4ad3f1c 100644
--- a/affine.scad
+++ b/affine.scad
@@ -20,13 +20,13 @@ function ident(n) = [for (i = [0:1:n-1]) [for (j = [0:1:n-1]) (i==j)?1:0]];
// Function: affine2d_to_3d()
// Description: Takes a 3x3 affine2d matrix and returns its 4x4 affine3d equivalent.
function affine2d_to_3d(m) = concat(
- [for (r = [0:2])
- concat(
- [for (c = [0:2]) m[r][c]],
- [0]
- )
- ],
- [[0, 0, 0, 1]]
+ [for (r = [0:2])
+ concat(
+ [for (c = [0:2]) m[r][c]],
+ [0]
+ )
+ ],
+ [[0, 0, 0, 1]]
);
@@ -45,9 +45,9 @@ function affine2d_identity() = ident(3);
// Arguments:
// v = 2D Offset to translate by. [X,Y]
function affine2d_translate(v) = [
- [1, 0, v.x],
- [0, 1, v.y],
- [0 ,0, 1]
+ [1, 0, v.x],
+ [0, 1, v.y],
+ [0 ,0, 1]
];
@@ -57,9 +57,9 @@ function affine2d_translate(v) = [
// Arguments:
// v = 2D vector of scaling factors. [X,Y]
function affine2d_scale(v) = [
- [v.x, 0, 0],
- [ 0, v.y, 0],
- [ 0, 0, 1]
+ [v.x, 0, 0],
+ [ 0, v.y, 0],
+ [ 0, 0, 1]
];
@@ -69,9 +69,9 @@ function affine2d_scale(v) = [
// Arguments:
// ang = Number of degrees to rotate.
function affine2d_zrot(ang) = [
- [cos(ang), -sin(ang), 0],
- [sin(ang), cos(ang), 0],
- [ 0, 0, 1]
+ [cos(ang), -sin(ang), 0],
+ [sin(ang), cos(ang), 0],
+ [ 0, 0, 1]
];
@@ -83,12 +83,12 @@ function affine2d_zrot(ang) = [
// Arguments:
// v = The normal vector of the line to reflect across.
function affine2d_mirror(v) =
- let(v=unit(point2d(v)), a=v.x, b=v.y)
- [
- [1-2*a*a, 0-2*a*b, 0],
- [0-2*a*b, 1-2*b*b, 0],
- [ 0, 0, 1]
- ];
+ let(v=unit(point2d(v)), a=v.x, b=v.y)
+ [
+ [1-2*a*a, 0-2*a*b, 0],
+ [0-2*a*b, 1-2*b*b, 0],
+ [ 0, 0, 1]
+ ];
// Function: affine2d_skew()
@@ -100,9 +100,9 @@ function affine2d_mirror(v) =
// xa = Skew angle, in degrees, in the direction of the X axis.
// ya = Skew angle, in degrees, in the direction of the Y axis.
function affine2d_skew(xa, ya) = [
- [1, tan(xa), 0],
- [tan(ya), 1, 0],
- [0, 0, 1]
+ [1, tan(xa), 0],
+ [tan(ya), 1, 0],
+ [0, 0, 1]
];
@@ -114,8 +114,8 @@ function affine2d_skew(xa, ya) = [
// Arguments:
// affines = A list of 3x3 affine2d matrices.
function affine2d_chain(affines, _m=undef, _i=0) =
- (_i>=len(affines))? (is_undef(_m)? ident(3) : _m) :
- affine2d_chain(affines, _m=(is_undef(_m)? affines[_i] : affines[_i] * _m), _i=_i+1);
+ (_i>=len(affines))? (is_undef(_m)? ident(3) : _m) :
+ affine2d_chain(affines, _m=(is_undef(_m)? affines[_i] : affines[_i] * _m), _i=_i+1);
@@ -133,10 +133,10 @@ function affine3d_identity() = ident(4);
// Arguments:
// v = 3D offset to translate by. [X,Y,Z]
function affine3d_translate(v) = [
- [1, 0, 0, v.x],
- [0, 1, 0, v.y],
- [0, 0, 1, v.z],
- [0 ,0, 0, 1]
+ [1, 0, 0, v.x],
+ [0, 1, 0, v.y],
+ [0, 0, 1, v.z],
+ [0 ,0, 0, 1]
];
@@ -146,10 +146,10 @@ function affine3d_translate(v) = [
// Arguments:
// v = 3D vector of scaling factors. [X,Y,Z]
function affine3d_scale(v) = [
- [v.x, 0, 0, 0],
- [ 0, v.y, 0, 0],
- [ 0, 0, v.z, 0],
- [ 0, 0, 0, 1]
+ [v.x, 0, 0, 0],
+ [ 0, v.y, 0, 0],
+ [ 0, 0, v.z, 0],
+ [ 0, 0, 0, 1]
];
@@ -159,10 +159,10 @@ function affine3d_scale(v) = [
// Arguments:
// ang = number of degrees to rotate.
function affine3d_xrot(ang) = [
- [1, 0, 0, 0],
- [0, cos(ang), -sin(ang), 0],
- [0, sin(ang), cos(ang), 0],
- [0, 0, 0, 1]
+ [1, 0, 0, 0],
+ [0, cos(ang), -sin(ang), 0],
+ [0, sin(ang), cos(ang), 0],
+ [0, 0, 0, 1]
];
@@ -172,10 +172,10 @@ function affine3d_xrot(ang) = [
// Arguments:
// ang = Number of degrees to rotate.
function affine3d_yrot(ang) = [
- [ cos(ang), 0, sin(ang), 0],
- [ 0, 1, 0, 0],
- [-sin(ang), 0, cos(ang), 0],
- [ 0, 0, 0, 1]
+ [ cos(ang), 0, sin(ang), 0],
+ [ 0, 1, 0, 0],
+ [-sin(ang), 0, cos(ang), 0],
+ [ 0, 0, 0, 1]
];
@@ -187,10 +187,10 @@ function affine3d_yrot(ang) = [
// Arguments:
// ang = number of degrees to rotate.
function affine3d_zrot(ang) = [
- [cos(ang), -sin(ang), 0, 0],
- [sin(ang), cos(ang), 0, 0],
- [ 0, 0, 1, 0],
- [ 0, 0, 0, 1]
+ [cos(ang), -sin(ang), 0, 0],
+ [sin(ang), cos(ang), 0, 0],
+ [ 0, 0, 1, 0],
+ [ 0, 0, 0, 1]
];
@@ -203,18 +203,18 @@ function affine3d_zrot(ang) = [
// u = 3D axis vector to rotate around.
// ang = number of degrees to rotate.
function affine3d_rot_by_axis(u, ang) =
- approx(ang,0)? affine3d_identity() :
- let(
- u = unit(u),
- c = cos(ang),
- c2 = 1-c,
- s = sin(ang)
- ) [
- [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
- [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
- [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
- [ 0, 0, 0, 1]
- ];
+ approx(ang,0)? affine3d_identity() :
+ let(
+ u = unit(u),
+ c = cos(ang),
+ c2 = 1-c,
+ s = sin(ang)
+ ) [
+ [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
+ [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
+ [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
+ [ 0, 0, 0, 1]
+ ];
// Function: affine3d_rot_from_to()
@@ -226,22 +226,22 @@ function affine3d_rot_by_axis(u, ang) =
// from = 3D axis vector to rotate from.
// to = 3D axis vector to rotate to.
function affine3d_rot_from_to(from, to) =
- let(
- from = unit(point3d(from)),
- to = unit(point3d(to))
- ) approx(from,to)? affine3d_identity() :
- let(
- u = vector_axis(from,to),
- ang = vector_angle(from,to),
- c = cos(ang),
- c2 = 1-c,
- s = sin(ang)
- ) [
- [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
- [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
- [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
- [ 0, 0, 0, 1]
- ];
+ let(
+ from = unit(point3d(from)),
+ to = unit(point3d(to))
+ ) approx(from,to)? affine3d_identity() :
+ let(
+ u = vector_axis(from,to),
+ ang = vector_angle(from,to),
+ c = cos(ang),
+ c2 = 1-c,
+ s = sin(ang)
+ ) [
+ [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
+ [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
+ [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
+ [ 0, 0, 0, 1]
+ ];
// Function: affine_frame_map()
@@ -266,35 +266,35 @@ function affine3d_rot_from_to(from, to) =
// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
// T = affine_frame_map(x=[0,1,1], y=[0,-1,1]) * affine_frame_map(x=[1,1,0], y=[-1,1,0],reverse=true);
function affine_frame_map(x,y,z, reverse=false) =
- assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
- let(
- xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
- yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
- zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
- )
- assert(xvalid,"Input x 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")
- let(
- x = is_undef(x)? undef : unit(x),
- y = is_undef(y)? undef : unit(y),
- z = is_undef(z)? undef : unit(z),
- map = is_undef(x)? [cross(y,z), y, z] :
- is_undef(y)? [x, cross(z,x), z] :
- is_undef(z)? [x, y, cross(x,y)] :
- [x, y, z]
- )
- reverse? (
- let(
- ocheck = (
- approx(map[0]*map[1],0) &&
- approx(map[0]*map[2],0) &&
- approx(map[1]*map[2],0)
- )
- )
- assert(ocheck, "Inputs must be orthogonal when reverse==true")
- affine2d_to_3d(map)
- ) : affine2d_to_3d(transpose(map));
+ assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
+ let(
+ xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
+ yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
+ zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
+ )
+ assert(xvalid,"Input x 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")
+ let(
+ x = is_undef(x)? undef : unit(x),
+ y = is_undef(y)? undef : unit(y),
+ z = is_undef(z)? undef : unit(z),
+ map = is_undef(x)? [cross(y,z), y, z] :
+ is_undef(y)? [x, cross(z,x), z] :
+ is_undef(z)? [x, y, cross(x,y)] :
+ [x, y, z]
+ )
+ reverse? (
+ let(
+ ocheck = (
+ approx(map[0]*map[1],0) &&
+ approx(map[0]*map[2],0) &&
+ approx(map[1]*map[2],0)
+ )
+ )
+ assert(ocheck, "Inputs must be orthogonal when reverse==true")
+ affine2d_to_3d(map)
+ ) : affine2d_to_3d(transpose(map));
@@ -306,15 +306,15 @@ function affine_frame_map(x,y,z, reverse=false) =
// Arguments:
// v = The normal vector of the plane to reflect across.
function affine3d_mirror(v) =
- let(
- v=unit(point3d(v)),
- a=v.x, b=v.y, c=v.z
- ) [
- [1-2*a*a, -2*a*b, -2*a*c, 0],
- [ -2*b*a, 1-2*b*b, -2*b*c, 0],
- [ -2*c*a, -2*c*b, 1-2*c*c, 0],
- [ 0, 0, 0, 1]
- ];
+ let(
+ v=unit(point3d(v)),
+ a=v.x, b=v.y, c=v.z
+ ) [
+ [1-2*a*a, -2*a*b, -2*a*c, 0],
+ [ -2*b*a, 1-2*b*b, -2*b*c, 0],
+ [ -2*c*a, -2*c*b, 1-2*c*c, 0],
+ [ 0, 0, 0, 1]
+ ];
// Function: affine3d_skew()
@@ -330,10 +330,10 @@ function affine3d_mirror(v) =
// szx = Skew factor multiplier for skewing along the Z axis as you get farther from the X axis. Default: 0
// szy = Skew factor multiplier for skewing along the Z axis as you get farther from the Y axis. Default: 0
function affine3d_skew(sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0) = [
- [ 1, sxy, sxz, 0],
- [syx, 1, syz, 0],
- [szx, szy, 1, 0],
- [ 0, 0, 0, 1]
+ [ 1, sxy, sxz, 0],
+ [syx, 1, syz, 0],
+ [szx, szy, 1, 0],
+ [ 0, 0, 0, 1]
];
@@ -346,10 +346,10 @@ function affine3d_skew(sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0) = [
// xa = Skew angle, in degrees, in the direction of the X axis.
// ya = Skew angle, in degrees, in the direction of the Y axis.
function affine3d_skew_xy(xa, ya) = [
- [1, 0, tan(xa), 0],
- [0, 1, tan(ya), 0],
- [0, 0, 1, 0],
- [0, 0, 0, 1]
+ [1, 0, tan(xa), 0],
+ [0, 1, tan(ya), 0],
+ [0, 0, 1, 0],
+ [0, 0, 0, 1]
];
@@ -362,10 +362,10 @@ function affine3d_skew_xy(xa, ya) = [
// xa = Skew angle, in degrees, in the direction of the X axis.
// za = Skew angle, in degrees, in the direction of the Z axis.
function affine3d_skew_xz(xa, za) = [
- [1, tan(xa), 0, 0],
- [0, 1, 0, 0],
- [0, tan(za), 1, 0],
- [0, 0, 0, 1]
+ [1, tan(xa), 0, 0],
+ [0, 1, 0, 0],
+ [0, tan(za), 1, 0],
+ [0, 0, 0, 1]
];
@@ -378,10 +378,10 @@ function affine3d_skew_xz(xa, za) = [
// ya = Skew angle, in degrees, in the direction of the Y axis.
// za = Skew angle, in degrees, in the direction of the Z axis.
function affine3d_skew_yz(ya, za) = [
- [ 1, 0, 0, 0],
- [tan(ya), 1, 0, 0],
- [tan(za), 0, 1, 0],
- [ 0, 0, 0, 1]
+ [ 1, 0, 0, 0],
+ [tan(ya), 1, 0, 0],
+ [tan(za), 0, 1, 0],
+ [ 0, 0, 0, 1]
];
@@ -393,8 +393,8 @@ function affine3d_skew_yz(ya, za) = [
// Arguments:
// affines = A list of 4x4 affine3d matrices.
function affine3d_chain(affines, _m=undef, _i=0) =
- (_i>=len(affines))? (is_undef(_m)? ident(4) : _m) :
- affine3d_chain(affines, _m=(is_undef(_m)? affines[_i] : affines[_i] * _m), _i=_i+1);
+ (_i>=len(affines))? (is_undef(_m)? ident(4) : _m) :
+ affine3d_chain(affines, _m=(is_undef(_m)? affines[_i] : affines[_i] * _m), _i=_i+1);
// Function: apply()
@@ -464,4 +464,4 @@ function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/arrays.scad b/arrays.scad
index 3fddebb..6ed7be5 100644
--- a/arrays.scad
+++ b/arrays.scad
@@ -44,20 +44,20 @@
// select(l, [1:3]); // Returns [4,5,6]
// select(l, [1,3]); // Returns [4,6]
function select(list, start, end=undef) =
- let(l=len(list))
- end==undef? (
- is_num(start)?
- let(s=(start%l+l)%l) list[s] :
- assert(is_list(start) || is_range(start), "Invalid start parameter")
- [for (i=start) list[(i%l+l)%l]]
- ) : (
- assert(is_num(start), "Invalid start parameter.")
- assert(is_num(end), "Invalid end parameter.")
- let(s=(start%l+l)%l, e=(end%l+l)%l)
- (s<=e)?
- [for (i = [s:1:e]) list[i]] :
- concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]])
- );
+ let(l=len(list))
+ end==undef? (
+ is_num(start)?
+ let(s=(start%l+l)%l) list[s] :
+ assert(is_list(start) || is_range(start), "Invalid start parameter")
+ [for (i=start) list[(i%l+l)%l]]
+ ) : (
+ assert(is_num(start), "Invalid start parameter.")
+ assert(is_num(end), "Invalid end parameter.")
+ let(s=(start%l+l)%l, e=(end%l+l)%l)
+ (s<=e)?
+ [for (i = [s:1:e]) list[i]] :
+ concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]])
+ );
// Function: slice()
@@ -75,10 +75,10 @@ function select(list, start, end=undef) =
// slice([3,4,5,6,7,8,9], 6, -1); // Returns [9]
// slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
function slice(arr,st,end) = let(
- l=len(arr),
- s=st<0?(l+st):st,
- e=end<0?(l+end+1):end
- ) [for (i=[s:1:e-1]) if (e>s) arr[i]];
+ l=len(arr),
+ s=st<0?(l+st):st,
+ e=end<0?(l+end+1):end
+ ) [for (i=[s:1:e-1]) if (e>s) arr[i]];
// Function: in_list()
@@ -107,7 +107,7 @@ function in_list(x,l,idx=undef) = search([x], l, num_returns_per_match=1, index_
// min_index([5,3,9,6,2,7,8,2,1]); // Returns: 4
// min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7]
function min_index(vals, all=false) =
- all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
+ all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
// Function: max_index()
@@ -123,7 +123,7 @@ function min_index(vals, all=false) =
// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) =
- all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
+ all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
// Function: list_increasing()
@@ -136,8 +136,8 @@ function max_index(vals, all=false) =
// list_increasing([1,3,2,4]); // Returns: false
// list_increasing([4,3,2,1]); // Returns: false
function list_increasing(list) =
- assert(is_list(list)||is_string(list))
- len([for (p=pair(list)) if(p.x>p.y) true])==0;
+ assert(is_list(list)||is_string(list))
+ len([for (p=pair(list)) if(p.x>p.y) true])==0;
// Function: list_decreasing()
@@ -150,8 +150,8 @@ function list_increasing(list) =
// list_decreasing([4,2,3,1]); // Returns: false
// list_decreasing([4,3,2,1]); // Returns: true
function list_decreasing(list) =
- assert(is_list(list)||is_string(list))
- len([for (p=pair(list)) if(p.x
=len(n))? val :
- [for (j=[1:1:n[i]]) repeat(val, n, i+1)];
+ is_num(n)? [for(j=[1:1:n]) val] :
+ (i>=len(n))? val :
+ [for (j=[1:1:n[i]]) repeat(val, n, i+1)];
// Function: list_range()
@@ -207,13 +207,13 @@ function repeat(val, n, i=0) =
// list_range(s=4, e=8, step=2); // Returns [4,6,8]
// list_range(n=4, s=[3,4], step=[2,3]); // Returns [[3,4], [5,7], [7,10], [9,13]]
function list_range(n=undef, s=0, e=undef, step=undef) =
- (n!=undef && e!=undef)? (
- assert(is_undef(n) || is_undef(e) || is_undef(step), "At most 2 of n, e, and step can be given.")
- [for (i=[0:1:n-1]) s+(e-s)*i/(n-1)]
- ) : let(step = default(step,1))
- (n!=undef)? [for (i=[0:1:n-1]) let(v=s+step*i) v] :
- (e!=undef)? [for (v=[s:step:e]) v] :
- assert(e!=undef||n!=undef, "Must supply one of `n` or `e`.");
+ (n!=undef && e!=undef)? (
+ assert(is_undef(n) || is_undef(e) || is_undef(step), "At most 2 of n, e, and step can be given.")
+ [for (i=[0:1:n-1]) s+(e-s)*i/(n-1)]
+ ) : let(step = default(step,1))
+ (n!=undef)? [for (i=[0:1:n-1]) let(v=s+step*i) v] :
+ (e!=undef)? [for (v=[s:step:e]) v] :
+ assert(e!=undef||n!=undef, "Must supply one of `n` or `e`.");
@@ -227,8 +227,8 @@ function list_range(n=undef, s=0, e=undef, step=undef) =
// Example:
// reverse([3,4,5,6]); // Returns [6,5,4,3]
function reverse(list) =
- assert(is_list(list)||is_string(list))
- [ for (i = [len(list)-1 : -1 : 0]) list[i] ];
+ assert(is_list(list)||is_string(list))
+ [ for (i = [len(list)-1 : -1 : 0]) list[i] ];
// Function: list_rotate()
@@ -251,9 +251,9 @@ function reverse(list) =
// l8 = list_rotate([1,2,3,4,5],5); // Returns: [1,2,3,4,5]
// l9 = list_rotate([1,2,3,4,5],6); // Returns: [2,3,4,5,1]
function list_rotate(list,n=1) =
- assert(is_list(list)||is_string(list))
- assert(is_num(n))
- select(list,n,n+len(list)-1);
+ assert(is_list(list)||is_string(list))
+ assert(is_num(n))
+ select(list,n,n+len(list)-1);
// Function: deduplicate()
@@ -272,13 +272,13 @@ function list_rotate(list,n=1) =
// deduplicate("Hello"); // Returns: ["H","e","l","o"]
// deduplicate([[3,4],[7,2],[7,1.99],[1,4]],eps=0.1); // Returns: [[3,4],[7,2],[1,4]]
function deduplicate(list, closed=false, eps=EPSILON) =
- assert(is_list(list)||is_string(list))
- let(
- l = len(list),
- end = l-(closed?0:1)
- ) (is_num(list[0]) || is_vector(list[0]))?
- [for (i=[0:1:l-1]) if (i==end || !approx(list[i], list[(i+1)%l], eps)) list[i]] :
- [for (i=[0:1:l-1]) if (i==end || list[i] != list[(i+1)%l]) list[i]];
+ assert(is_list(list)||is_string(list))
+ let(
+ l = len(list),
+ end = l-(closed?0:1)
+ ) (is_num(list[0]) || is_vector(list[0]))?
+ [for (i=[0:1:l-1]) if (i==end || !approx(list[i], list[(i+1)%l], eps)) list[i]] :
+ [for (i=[0:1:l-1]) if (i==end || list[i] != list[(i+1)%l]) list[i]];
// Function: deduplicate_indexed()
@@ -296,23 +296,23 @@ function deduplicate(list, closed=false, eps=EPSILON) =
// deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1]); // Returns: [1,4,3,2,0,1]
// deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1], closed=true); // Returns: [1,4,3,2,0]
function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) =
- assert(is_list(list)||is_string(list))
- assert(indices==[] || is_vector(indices))
- indices==[]? [] :
- let(
- l = len(indices),
- end = l-(closed?0:1)
- ) [
- for (i = [0:1:l-1]) let(
- a = list[indices[i]],
- b = list[indices[(i+1)%l]],
- eq = (a == b)? true :
- (a*0 != b*0)? false :
- is_num(a)? approx(a, b, eps=eps) :
- is_vector(a)? approx(a, b, eps=eps) :
- false
- ) if (i==end || !eq) indices[i]
- ];
+ assert(is_list(list)||is_string(list))
+ assert(indices==[] || is_vector(indices))
+ indices==[]? [] :
+ let(
+ l = len(indices),
+ end = l-(closed?0:1)
+ ) [
+ for (i = [0:1:l-1]) let(
+ a = list[indices[i]],
+ b = list[indices[(i+1)%l]],
+ eq = (a == b)? true :
+ (a*0 != b*0)? false :
+ is_num(a)? approx(a, b, eps=eps) :
+ is_vector(a)? approx(a, b, eps=eps) :
+ false
+ ) if (i==end || !eq) indices[i]
+ ];
// Function: repeat_entries()
@@ -341,17 +341,17 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) =
// echo(repeat_entries(list, 6, exact=false)); // Ouputs [0,0,1,1,2,2,3,3]
// echo(repeat_entries(list, [1,1,2,1], exact=false)); // Ouputs [0,1,2,2,3]
function repeat_entries(list, N, exact = true) =
- assert(is_list(list))
- assert((is_num(N) && N>0) || is_vector(N),"Parameter N to repeat_entries must be postive number or vector")
- let(
- length = len(list),
- reps_guess = is_list(N)?
- assert(len(N)==len(list), "Vector parameter N to repeat_entries has the wrong length")
- N : repeat(N/length,length),
- reps = exact? _sum_preserving_round(reps_guess) :
- [for (val=reps_guess) round(val)]
- )
- [for(i=[0:length-1]) each repeat(list[i],reps[i])];
+ assert(is_list(list))
+ assert((is_num(N) && N>0) || is_vector(N),"Parameter N to repeat_entries must be postive number or vector")
+ let(
+ length = len(list),
+ reps_guess = is_list(N)?
+ assert(len(N)==len(list), "Vector parameter N to repeat_entries has the wrong length")
+ N : repeat(N/length,length),
+ reps = exact? _sum_preserving_round(reps_guess) :
+ [for (val=reps_guess) round(val)]
+ )
+ [for(i=[0:length-1]) each repeat(list[i],reps[i])];
// Function: list_set()
@@ -375,29 +375,29 @@ function repeat_entries(list, N, exact = true) =
// list_set([2,3,4,5], 2, 21); // Returns: [2,3,21,5]
// list_set([2,3,4,5], [1,3], [81,47]); // Returns: [2,81,4,47]
function list_set(list=[],indices,values,dflt=0,minlen=0) =
- assert(is_list(list)||is_string(list))
- !is_list(indices)? (
- (is_num(indices) && indices=len(list) ? dflt : list[j]],
- [values[sortind[0]]],
- [for(i=[1:1:len(sortind)-1]) each
- assert(indices[sortind[i]]!=indices[sortind[i-1]],"Repeated index")
- concat(
- [for(j=[1+indices[sortind[i-1]]:1:indices[sortind[i]]-1]) j>=len(list) ? dflt : list[j]],
- [values[sortind[i]]]
- )
- ],
- slice(list,1+lastind, len(list)),
- repeat(dflt, minlen-lastind-1)
- );
+ assert(is_list(list)||is_string(list))
+ !is_list(indices)? (
+ (is_num(indices) && indices=len(list) ? dflt : list[j]],
+ [values[sortind[0]]],
+ [for(i=[1:1:len(sortind)-1]) each
+ assert(indices[sortind[i]]!=indices[sortind[i-1]],"Repeated index")
+ concat(
+ [for(j=[1+indices[sortind[i-1]]:1:indices[sortind[i]]-1]) j>=len(list) ? dflt : list[j]],
+ [values[sortind[i]]]
+ )
+ ],
+ slice(list,1+lastind, len(list)),
+ repeat(dflt, minlen-lastind-1)
+ );
// Function: list_insert()
@@ -409,31 +409,31 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
// list_insert([3,6,9,12],1,5); // Returns [3,5,6,9,12]
// list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
function list_insert(list, pos, elements, _i=0) =
- assert(is_list(list)||is_string(list))
- is_list(pos)? (
- assert(len(pos)==len(elements))
- let(
- idxs = sortidx(pos),
- lastidx = pos[idxs[len(idxs)-1]]
- )
- concat(
- [
- for(i=idx(idxs)) each concat(
- assert(pos[idxs[i]]<=len(list), "Indices in pos must be <= len(list)")
- [for (j=[(i==0?0:pos[idxs[i-1]]):1:pos[idxs[i]]-1]) list[j]],
- [elements[idxs[i]]]
- )
- ],
- [for (j=[lastidx:1:len(list)-1]) list[j]]
- )
- ) : (
- assert(pos<=len(list), "Indices in pos must be <= len(list)")
- concat(
- slice(list,0,pos),
- elements,
- (poslength)? list_trim(v,length) : list_pad(v,length,fill);
+ assert(is_list(v)||is_string(list))
+ let(l=len(v)) (l==length)? v : (l>length)? list_trim(v,length) : list_pad(v,length,fill);
@@ -596,148 +596,148 @@ function list_fit(v, length, fill) =
// Description:
// Shuffles the input list into random order.
function shuffle(list) =
- assert(is_list(list)||is_string(list))
- len(list)<=1 ? list :
- let (
- rval = rands(0,1,len(list)),
- left = [for (i=[0:len(list)-1]) if (rval[i]< 0.5) list[i]],
- right = [for (i=[0:len(list)-1]) if (rval[i]>=0.5) list[i]]
- ) concat(shuffle(left), shuffle(right));
+ assert(is_list(list)||is_string(list))
+ len(list)<=1 ? list :
+ let (
+ rval = rands(0,1,len(list)),
+ left = [for (i=[0:len(list)-1]) if (rval[i]< 0.5) list[i]],
+ right = [for (i=[0:len(list)-1]) if (rval[i]>=0.5) list[i]]
+ ) concat(shuffle(left), shuffle(right));
// Sort a vector of scalar values
function _sort_scalars(arr) =
- len(arr)<=1 ? arr : let(
- pivot = arr[floor(len(arr)/2)],
- lesser = [ for (y = arr) if (y < pivot) y ],
- equal = [ for (y = arr) if (y == pivot) y ],
- greater = [ for (y = arr) if (y > pivot) y ]
- ) concat( _sort_scalars(lesser), equal, _sort_scalars(greater) );
+ len(arr)<=1 ? arr : let(
+ pivot = arr[floor(len(arr)/2)],
+ lesser = [ for (y = arr) if (y < pivot) y ],
+ equal = [ for (y = arr) if (y == pivot) y ],
+ greater = [ for (y = arr) if (y > pivot) y ]
+ ) concat( _sort_scalars(lesser), equal, _sort_scalars(greater) );
// Sort a vector of vectors based on the first entry only of each vector
function _sort_vectors1(arr) =
- len(arr)<=1 ? arr :
- !(len(arr)>0) ? [] : let(
- pivot = arr[floor(len(arr)/2)],
- lesser = [ for (y = arr) if (y[0] < pivot[0]) y ],
- equal = [ for (y = arr) if (y[0] == pivot[0]) y ],
- greater = [ for (y = arr) if (y[0] > pivot[0]) y ]
- ) concat( _sort_vectors1(lesser), equal, _sort_vectors1(greater) );
+ len(arr)<=1 ? arr :
+ !(len(arr)>0) ? [] : let(
+ pivot = arr[floor(len(arr)/2)],
+ lesser = [ for (y = arr) if (y[0] < pivot[0]) y ],
+ equal = [ for (y = arr) if (y[0] == pivot[0]) y ],
+ greater = [ for (y = arr) if (y[0] > pivot[0]) y ]
+ ) concat( _sort_vectors1(lesser), equal, _sort_vectors1(greater) );
// Sort a vector of vectors based on the first two entries of each vector
// Lexicographic order, remaining entries of vector ignored
function _sort_vectors2(arr) =
- len(arr)<=1 ? arr :
- !(len(arr)>0) ? [] : let(
- pivot = arr[floor(len(arr)/2)],
- lesser = [ for (y = arr) if (y[0] < pivot[0] || (y[0]==pivot[0] && y[1] pivot[0] || (y[0]==pivot[0] && y[1]>pivot[1])) y ]
- ) concat( _sort_vectors2(lesser), equal, _sort_vectors2(greater) );
+ len(arr)<=1 ? arr :
+ !(len(arr)>0) ? [] : let(
+ pivot = arr[floor(len(arr)/2)],
+ lesser = [ for (y = arr) if (y[0] < pivot[0] || (y[0]==pivot[0] && y[1] pivot[0] || (y[0]==pivot[0] && y[1]>pivot[1])) y ]
+ ) concat( _sort_vectors2(lesser), equal, _sort_vectors2(greater) );
// Sort a vector of vectors based on the first three entries of each vector
// Lexicographic order, remaining entries of vector ignored
function _sort_vectors3(arr) =
- len(arr)<=1 ? arr : let(
- pivot = arr[floor(len(arr)/2)],
- lesser = [
- for (y = arr) if (
- y[0] < pivot[0] || (
- y[0]==pivot[0] && (
- y[1] pivot[0] || (
- y[0]==pivot[0] && (
- y[1]>pivot[1] || (
- y[1]==pivot[1] &&
- y[2]>pivot[2]
- )
- )
- )
- ) y
- ]
- ) concat( _sort_vectors3(lesser), equal, _sort_vectors3(greater) );
+ len(arr)<=1 ? arr : let(
+ pivot = arr[floor(len(arr)/2)],
+ lesser = [
+ for (y = arr) if (
+ y[0] < pivot[0] || (
+ y[0]==pivot[0] && (
+ y[1] pivot[0] || (
+ y[0]==pivot[0] && (
+ y[1]>pivot[1] || (
+ y[1]==pivot[1] &&
+ y[2]>pivot[2]
+ )
+ )
+ )
+ ) y
+ ]
+ ) concat( _sort_vectors3(lesser), equal, _sort_vectors3(greater) );
// Sort a vector of vectors based on the first four entries of each vector
// Lexicographic order, remaining entries of vector ignored
function _sort_vectors4(arr) =
- len(arr)<=1 ? arr : let(
- pivot = arr[floor(len(arr)/2)],
- lesser = [
- for (y = arr) if (
- y[0] < pivot[0] || (
- y[0]==pivot[0] && (
- y[1] pivot[0] || (
- y[0]==pivot[0] && (
- y[1]>pivot[1] || (
- y[1]==pivot[1] && (
- y[2]>pivot[2] || (
- y[2]==pivot[2] &&
- y[3]>pivot[3]
- )
- )
- )
- )
- )
- ) y
- ]
- ) concat( _sort_vectors4(lesser), equal, _sort_vectors4(greater) );
+ len(arr)<=1 ? arr : let(
+ pivot = arr[floor(len(arr)/2)],
+ lesser = [
+ for (y = arr) if (
+ y[0] < pivot[0] || (
+ y[0]==pivot[0] && (
+ y[1] pivot[0] || (
+ y[0]==pivot[0] && (
+ y[1]>pivot[1] || (
+ y[1]==pivot[1] && (
+ y[2]>pivot[2] || (
+ y[2]==pivot[2] &&
+ y[3]>pivot[3]
+ )
+ )
+ )
+ )
+ )
+ ) y
+ ]
+ ) concat( _sort_vectors4(lesser), equal, _sort_vectors4(greater) );
function _sort_general(arr, idx=undef) =
- (len(arr)<=1) ? arr :
- let(
- pivot = arr[floor(len(arr)/2)],
- pivotval = idx==undef? pivot : [for (i=idx) pivot[i]],
- compare = [
- for (entry = arr) let(
- val = idx==undef? entry : [for (i=idx) entry[i]],
- cmp = compare_vals(val, pivotval)
- ) cmp
- ],
- lesser = [ for (i = [0:1:len(arr)-1]) if (compare[i] < 0) arr[i] ],
- equal = [ for (i = [0:1:len(arr)-1]) if (compare[i] ==0) arr[i] ],
- greater = [ for (i = [0:1:len(arr)-1]) if (compare[i] > 0) arr[i] ]
- )
- concat(_sort_general(lesser,idx), equal, _sort_general(greater,idx));
+ (len(arr)<=1) ? arr :
+ let(
+ pivot = arr[floor(len(arr)/2)],
+ pivotval = idx==undef? pivot : [for (i=idx) pivot[i]],
+ compare = [
+ for (entry = arr) let(
+ val = idx==undef? entry : [for (i=idx) entry[i]],
+ cmp = compare_vals(val, pivotval)
+ ) cmp
+ ],
+ lesser = [ for (i = [0:1:len(arr)-1]) if (compare[i] < 0) arr[i] ],
+ equal = [ for (i = [0:1:len(arr)-1]) if (compare[i] ==0) arr[i] ],
+ greater = [ for (i = [0:1:len(arr)-1]) if (compare[i] > 0) arr[i] ]
+ )
+ concat(_sort_general(lesser,idx), equal, _sort_general(greater,idx));
// Function: sort()
@@ -756,17 +756,17 @@ function _sort_general(arr, idx=undef) =
// l = [45,2,16,37,8,3,9,23,89,12,34];
// sorted = sort(l); // Returns [2,3,8,9,12,16,23,34,37,45,89]
function sort(list, idx=undef) =
- !is_list(list) || len(list)<=1 ? list :
- is_def(idx) ? _sort_general(list,idx) :
- let(size = array_dim(list))
- len(size)==1 ? _sort_scalars(list) :
- len(size)==2 && size[1] <=4 ? (
- size[1]==0 ? list :
- size[1]==1 ? _sort_vectors1(list) :
- size[1]==2 ? _sort_vectors2(list) :
- size[1]==3 ? _sort_vectors3(list) :
- /*size[1]==4*/ _sort_vectors4(list)
- ) : _sort_general(list);
+ !is_list(list) || len(list)<=1 ? list :
+ is_def(idx) ? _sort_general(list,idx) :
+ let(size = array_dim(list))
+ len(size)==1 ? _sort_scalars(list) :
+ len(size)==2 && size[1] <=4 ? (
+ size[1]==0 ? list :
+ size[1]==1 ? _sort_vectors1(list) :
+ size[1]==2 ? _sort_vectors2(list) :
+ size[1]==3 ? _sort_vectors3(list) :
+ /*size[1]==4*/ _sort_vectors4(list)
+ ) : _sort_general(list);
// Function: sortidx()
@@ -782,31 +782,31 @@ function sort(list, idx=undef) =
// ordered = select(lst, idxs); // Returns: ["b", "c", "d", "e"]
// Example:
// lst = [
-// ["foo", 88, [0,0,1], false],
-// ["bar", 90, [0,1,0], true],
-// ["baz", 89, [1,0,0], false],
-// ["qux", 23, [1,1,1], true]
+// ["foo", 88, [0,0,1], false],
+// ["bar", 90, [0,1,0], true],
+// ["baz", 89, [1,0,0], false],
+// ["qux", 23, [1,1,1], true]
// ];
// idxs1 = sortidx(lst, idx=1); // Returns: [3,0,2,1]
// idxs2 = sortidx(lst, idx=0); // Returns: [1,2,0,3]
// idxs3 = sortidx(lst, idx=[1,3]); // Returns: [3,0,2,1]
function sortidx(list, idx=undef) =
- list==[] ? [] : let(
- size = array_dim(list),
- aug = is_undef(idx) && (len(size) == 1 || (len(size) == 2 && size[1]<=4))?
- zip(list, list_range(len(list))) :
- enumerate(list,idx=idx)
- )
- is_undef(idx) && len(size) == 1? subindex(_sort_vectors1(aug),1) :
- is_undef(idx) && len(size) == 2 && size[1] <=4? (
- size[1]==0? list_range(len(arr)) :
- size[1]==1? subindex(_sort_vectors1(aug),1) :
- size[1]==2? subindex(_sort_vectors2(aug),2) :
- size[1]==3? subindex(_sort_vectors3(aug),3) :
- /*size[1]==4*/ subindex(_sort_vectors4(aug),4)
- ) :
- // general case
- subindex(_sort_general(aug, idx=list_range(s=1,n=len(aug)-1)), 0);
+ list==[] ? [] : let(
+ size = array_dim(list),
+ aug = is_undef(idx) && (len(size) == 1 || (len(size) == 2 && size[1]<=4))?
+ zip(list, list_range(len(list))) :
+ enumerate(list,idx=idx)
+ )
+ is_undef(idx) && len(size) == 1? subindex(_sort_vectors1(aug),1) :
+ is_undef(idx) && len(size) == 2 && size[1] <=4? (
+ size[1]==0? list_range(len(arr)) :
+ size[1]==1? subindex(_sort_vectors1(aug),1) :
+ size[1]==2? subindex(_sort_vectors2(aug),2) :
+ size[1]==3? subindex(_sort_vectors3(aug),3) :
+ /*size[1]==4*/ subindex(_sort_vectors4(aug),4)
+ ) :
+ // general case
+ subindex(_sort_general(aug, idx=list_range(s=1,n=len(aug)-1)), 0);
// Function: unique()
@@ -817,14 +817,14 @@ function sortidx(list, idx=undef) =
// Arguments:
// arr = The list to uniquify.
function unique(arr) =
- assert(is_list(arr)||is_string(arr))
- len(arr)<=1? arr : let(
- sorted = sort(arr)
- ) [
- for (i=[0:1:len(sorted)-1])
- if (i==0 || (sorted[i] != sorted[i-1]))
- sorted[i]
- ];
+ assert(is_list(arr)||is_string(arr))
+ len(arr)<=1? arr : let(
+ sorted = sort(arr)
+ ) [
+ for (i=[0:1:len(sorted)-1])
+ if (i==0 || (sorted[i] != sorted[i-1]))
+ sorted[i]
+ ];
// Function: unique_count()
@@ -860,8 +860,8 @@ function unique_count(arr) =
// colors = ["red", "green", "blue"];
// for (i=idx(colors)) right(20*i) color(colors[i]) circle(d=10);
function idx(list, step=1, end=-1,start=0) =
- assert(is_list(list)||is_string(list))
- [start : step : len(list)+end];
+ assert(is_list(list)||is_string(list))
+ [start : step : len(list)+end];
// Function: enumerate()
@@ -879,10 +879,10 @@ function idx(list, step=1, end=-1,start=0) =
// colors = ["red", "green", "blue"];
// for (p=enumerate(colors)) right(20*p[0]) color(p[1]) circle(d=10);
function enumerate(l,idx=undef) =
- assert(is_list(l)||is_string(list))
- (idx==undef)?
- [for (i=[0:1:len(l)-1]) [i,l[i]]] :
- [for (i=[0:1:len(l)-1]) concat([i], [for (j=idx) l[i][j]])];
+ assert(is_list(l)||is_string(list))
+ (idx==undef)?
+ [for (i=[0:1:len(l)-1]) [i,l[i]]] :
+ [for (i=[0:1:len(l)-1]) concat([i], [for (j=idx) l[i][j]])];
// Function: force_list()
@@ -903,8 +903,8 @@ function force_list(value) = is_list(value) ? value : [value];
// l = ["A","B","C",D"];
// echo([for (p=pair(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC"]
function pair(v) =
- assert(is_list(v)||is_string(v))
- [for (i=[0:1:len(v)-2]) [v[i],v[i+1]]];
+ assert(is_list(v)||is_string(v))
+ [for (i=[0:1:len(v)-2]) [v[i],v[i+1]]];
// Function: pair_wrap()
@@ -916,8 +916,8 @@ function pair(v) =
// l = ["A","B","C","D"];
// echo([for (p=pair_wrap(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC", "AD"]
function pair_wrap(v) =
- assert(is_list(v)||is_string(v))
- [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)]]];
+ assert(is_list(v)||is_string(v))
+ [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)]]];
// Function: triplet()
@@ -929,8 +929,8 @@ function pair_wrap(v) =
// l = ["A","B","C","D","E"];
// echo([for (p=triplet(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "EDC"]
function triplet(v) =
- assert(is_list(v)||is_string(v))
- [for (i=[0:1:len(v)-3]) [v[i],v[i+1],v[i+2]]];
+ assert(is_list(v)||is_string(v))
+ [for (i=[0:1:len(v)-3]) [v[i],v[i+1],v[i+2]]];
// Function: triplet_wrap()
@@ -942,8 +942,8 @@ function triplet(v) =
// l = ["A","B","C","D"];
// echo([for (p=triplet_wrap(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "ADC", "BAD"]
function triplet_wrap(v) =
- assert(is_list(v)||is_string(v))
- [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)],v[(i+2)%len(v)]]];
+ assert(is_list(v)||is_string(v))
+ [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)],v[(i+2)%len(v)]]];
// Function: permute()
@@ -962,10 +962,10 @@ function triplet_wrap(v) =
// Example(2D):
// for (p=permute(regular_ngon(n=7,d=100))) stroke(p);
function permute(l,n=2,_s=0) =
- assert(is_list(l))
- assert(len(l)-_s >= n)
- n==1? [for (i=[_s:1:len(l)-1]) [l[i]]] :
- [for (i=[_s:1:len(l)-n], p=permute(l,n=n-1,_s=i+1)) concat([l[i]], p)];
+ assert(is_list(l))
+ assert(len(l)-_s >= n)
+ n==1? [for (i=[_s:1:len(l)-1]) [l[i]]] :
+ [for (i=[_s:1:len(l)-n], p=permute(l,n=n-1,_s=i+1)) concat([l[i]], p)];
@@ -991,25 +991,25 @@ function permute(l,n=2,_s=0) =
// set_v = set_union(set_a, set_b, get_indices=true);
// // set_v now equals [[5,0,1,2,6], [2,3,5,7,11,1,8]]
function set_union(a, b, get_indices=false) =
- let(
- found1 = search(b, a),
- found2 = search(b, b),
- c = [
- for (i=idx(b))
- if (found1[i] == [] && found2[i] == i)
- b[i]
- ],
- nset = concat(a, c)
- ) !get_indices? nset :
- let(
- la = len(a),
- found3 = search(b, c),
- idxs = [
- for (i=idx(b))
- (found1[i] != [])? found1[i] :
- la + found3[i]
- ]
- ) [idxs, nset];
+ let(
+ found1 = search(b, a),
+ found2 = search(b, b),
+ c = [
+ for (i=idx(b))
+ if (found1[i] == [] && found2[i] == i)
+ b[i]
+ ],
+ nset = concat(a, c)
+ ) !get_indices? nset :
+ let(
+ la = len(a),
+ found3 = search(b, c),
+ idxs = [
+ for (i=idx(b))
+ (found1[i] != [])? found1[i] :
+ la + found3[i]
+ ]
+ ) [idxs, nset];
// Function: set_difference()
@@ -1026,9 +1026,9 @@ function set_union(a, b, get_indices=false) =
// set_d = set_difference(set_a, set_b);
// // set_d now equals [7,11]
function set_difference(a, b) =
- let(
- found = search(a, b, num_returns_per_match=1)
- ) [ for (i=idx(a)) if(found[i]==[]) a[i] ];
+ let(
+ found = search(a, b, num_returns_per_match=1)
+ ) [ for (i=idx(a)) if(found[i]==[]) a[i] ];
// Function: set_intersection()
@@ -1045,9 +1045,9 @@ function set_difference(a, b) =
// set_i = set_intersection(set_a, set_b);
// // set_i now equals [2,3,5]
function set_intersection(a, b) =
- let(
- found = search(a, b, num_returns_per_match=1)
- ) [ for (i=idx(a)) if(found[i]!=[]) a[i] ];
+ let(
+ found = search(a, b, num_returns_per_match=1)
+ ) [ for (i=idx(a)) if(found[i]!=[]) a[i] ];
@@ -1068,8 +1068,8 @@ function set_intersection(a, b) =
// subindex(v,[2,1]); // Returns [[3, 2], [7, 6], [11, 10], [15, 14]]
// subindex(v,[1:3]); // Returns [[2, 3, 4], [6, 7, 8], [10, 11, 12], [14, 15, 16]]
function subindex(v, idx) = [
- for(val=v) let(value=[for(i=idx) val[i]])
- len(value)==1 ? value[0] : value
+ for(val=v) let(value=[for(i=idx) val[i]])
+ len(value)==1 ? value[0] : value
];
@@ -1100,17 +1100,17 @@ function subindex(v, idx) = [
// v2 = [[20,19,18], [17,16,15], [14,13,12]];
// zip(v1,v2); // Returns [[1,2,3,20,19,18], [4,5,6,17,16,15], [7,8,9,14,13,12]]
function zip(vecs, v2, v3, fit=false, fill=undef) =
- (v3!=undef)? zip([vecs,v2,v3], fit=fit, fill=fill) :
- (v2!=undef)? zip([vecs,v2], fit=fit, fill=fill) :
- assert(in_list(fit, [false, "short", "long"]))
- assert(all([for(v=vecs) is_list(v)]), "One of the inputs to zip is not a list")
- let(
- minlen = list_shortest(vecs),
- maxlen = list_longest(vecs),
- dummy = (fit==false)? assert(minlen==maxlen, "Input vectors to zip must have the same length") : 0
- ) (fit == "long")?
- [for(i=[0:1:maxlen-1]) [for(v=vecs) for(x=(i len(dimlist))? 0 : dimlist[depth-1]
- );
+ (depth == undef)? (
+ concat([len(v)], _array_dim_recurse(v))
+ ) : (depth == 0)? (
+ len(v)
+ ) : (
+ let(dimlist = _array_dim_recurse(v))
+ (depth > len(dimlist))? 0 : dimlist[depth-1]
+ );
@@ -1213,9 +1213,9 @@ function array_dim(v, depth=undef) =
// Example:
// transpose([3,4,5]); // Returns: [3,4,5]
function transpose(arr) =
- is_list(arr[0])? [for (i=[0:1:len(arr[0])-1]) [for (j=[0:1:len(arr)-1]) arr[j][i]]] : arr;
+ is_list(arr[0])? [for (i=[0:1:len(arr[0])-1]) [for (j=[0:1:len(arr)-1]) arr[j][i]]] : arr;
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/attachments.scad b/attachments.scad
index bbd93cc..bb6b817 100644
--- a/attachments.scad
+++ b/attachments.scad
@@ -173,75 +173,75 @@ function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, sp
// geom = attach_geom(anchor, spin, orient, path=path);
//
function attach_geom(
- size, size2, shift,
- r,r1,r2, d,d1,d2, l,h,
- vnf, path,
- extent=true,
- offset=[0,0,0],
- anchors=[],
- two_d=false
+ size, size2, shift,
+ r,r1,r2, d,d1,d2, l,h,
+ vnf, path,
+ extent=true,
+ offset=[0,0,0],
+ anchors=[],
+ two_d=false
) =
- assert(is_bool(extent))
- assert(is_vector(offset))
- assert(is_list(anchors))
- assert(is_bool(two_d))
- !is_undef(size)? (
- two_d? (
- let(
- size2 = default(size2, size.x),
- shift = default(shift, 0)
- )
- assert(is_vector(size,2))
- assert(is_num(size2))
- assert(is_num(shift))
- ["rect", point2d(size), size2, shift, offset, anchors]
- ) : (
- let(
- size2 = default(size2, point2d(size)),
- shift = default(shift, [0,0])
- )
- assert(is_vector(size,3))
- assert(is_vector(size2,2))
- assert(is_vector(shift,2))
- ["cuboid", size, size2, shift, offset, anchors]
- )
- ) : !is_undef(vnf)? (
- assert(is_vnf(vnf))
- assert(two_d == false)
- extent? ["vnf_extent", vnf, offset, anchors] :
- ["vnf_isect", vnf, offset, anchors]
- ) : !is_undef(path)? (
- assert(is_path(path),2)
- assert(two_d == true)
- extent? ["path_extent", path, offset, anchors] :
- ["path_isect", path, offset, anchors]
- ) :
- let(
- r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef)
- )
- !is_undef(r1)? (
- let( l = default(l, h) )
- !is_undef(l)? (
- let(
- shift = default(shift, [0,0]),
- r2 = get_radius(r1=r2,d1=d2,r=r,d=d,dflt=undef)
- )
- assert(is_num(r1) || is_vector(r1,2))
- assert(is_num(r2) || is_vector(r2,2))
- assert(is_num(l))
- assert(is_vector(shift,2))
- ["cyl", r1, r2, l, shift, offset, anchors]
- ) : (
- two_d? (
- assert(is_num(r1) || is_vector(r1,2))
- ["circle", r1, offset, anchors]
- ) : (
- assert(is_num(r1) || is_vector(r1,3))
- ["spheroid", r1, offset, anchors]
- )
- )
- ) :
- assert(false, "Unrecognizable geometry description.");
+ assert(is_bool(extent))
+ assert(is_vector(offset))
+ assert(is_list(anchors))
+ assert(is_bool(two_d))
+ !is_undef(size)? (
+ two_d? (
+ let(
+ size2 = default(size2, size.x),
+ shift = default(shift, 0)
+ )
+ assert(is_vector(size,2))
+ assert(is_num(size2))
+ assert(is_num(shift))
+ ["rect", point2d(size), size2, shift, offset, anchors]
+ ) : (
+ let(
+ size2 = default(size2, point2d(size)),
+ shift = default(shift, [0,0])
+ )
+ assert(is_vector(size,3))
+ assert(is_vector(size2,2))
+ assert(is_vector(shift,2))
+ ["cuboid", size, size2, shift, offset, anchors]
+ )
+ ) : !is_undef(vnf)? (
+ assert(is_vnf(vnf))
+ assert(two_d == false)
+ extent? ["vnf_extent", vnf, offset, anchors] :
+ ["vnf_isect", vnf, offset, anchors]
+ ) : !is_undef(path)? (
+ assert(is_path(path),2)
+ assert(two_d == true)
+ extent? ["path_extent", path, offset, anchors] :
+ ["path_isect", path, offset, anchors]
+ ) :
+ let(
+ r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef)
+ )
+ !is_undef(r1)? (
+ let( l = default(l, h) )
+ !is_undef(l)? (
+ let(
+ shift = default(shift, [0,0]),
+ r2 = get_radius(r1=r2,d1=d2,r=r,d=d,dflt=undef)
+ )
+ assert(is_num(r1) || is_vector(r1,2))
+ assert(is_num(r2) || is_vector(r2,2))
+ assert(is_num(l))
+ assert(is_vector(shift,2))
+ ["cyl", r1, r2, l, shift, offset, anchors]
+ ) : (
+ two_d? (
+ assert(is_num(r1) || is_vector(r1,2))
+ ["circle", r1, offset, anchors]
+ ) : (
+ assert(is_num(r1) || is_vector(r1,3))
+ ["spheroid", r1, offset, anchors]
+ )
+ )
+ ) :
+ assert(false, "Unrecognizable geometry description.");
@@ -251,9 +251,9 @@ function attach_geom(
// Description:
// Returns true if the given attachment geometry description is for a 2D shape.
function attach_geom_2d(geom) =
- let( type = geom[0] )
- type == "rect" || type == "circle" ||
- type == "path_isect" || type == "path_extent";
+ let( type = geom[0] )
+ type == "rect" || type == "circle" ||
+ type == "path_isect" || type == "path_extent";
// Function: attach_geom_size()
@@ -262,47 +262,47 @@ function attach_geom_2d(geom) =
// Description:
// Returns the `[X,Y,Z]` bounding size for the given attachment geometry description.
function attach_geom_size(geom) =
- let( type = geom[0] )
- type == "cuboid"? ( //size, size2, shift
- let(
- size=geom[1], size2=geom[2], shift=point2d(geom[3]),
- maxx = max(size.x,size2.x),
- maxy = max(size.y,size2.y),
- z = size.z
- ) [maxx, maxy, z]
- ) : type == "cyl"? ( //r1, r2, l, shift
- let(
- r1=geom[1], r2=geom[2], l=geom[3], shift=point2d(geom[4]),
- rx1 = default(r1[0],r1),
- ry1 = default(r1[1],r1),
- rx2 = default(r2[0],r2),
- ry2 = default(r2[1],r2),
- maxxr = max(rx1,rx2),
- maxyr = max(ry1,ry2)
- ) [2*maxxr,2*maxyr,l]
- ) : type == "spheroid"? ( //r
- let( r=geom[1] )
- is_num(r)? [2,2,2]*r : vmul([2,2,2],r)
- ) : type == "vnf_extent" || type=="vnf_isect"? ( //vnf
- let(
- mm = pointlist_bounds(geom[1][0]),
- delt = mm[1]-mm[0]
- ) delt
- ) : type == "rect"? ( //size, size2
- let(
- size=geom[1], size2=geom[2],
- maxx = max(size.x,size2)
- ) [maxx, size.y]
- ) : type == "circle"? ( //r
- let( r=geom[1] )
- is_num(r)? [2,2]*r : vmul([2,2],r)
- ) : type == "path_isect" || type == "path_extent"? ( //path
- let(
- mm = pointlist_bounds(geom[1]),
- delt = mm[1]-mm[0]
- ) [delt.x, delt.y]
- ) :
- assert(false, "Unknown attachment geometry type.");
+ let( type = geom[0] )
+ type == "cuboid"? ( //size, size2, shift
+ let(
+ size=geom[1], size2=geom[2], shift=point2d(geom[3]),
+ maxx = max(size.x,size2.x),
+ maxy = max(size.y,size2.y),
+ z = size.z
+ ) [maxx, maxy, z]
+ ) : type == "cyl"? ( //r1, r2, l, shift
+ let(
+ r1=geom[1], r2=geom[2], l=geom[3], shift=point2d(geom[4]),
+ rx1 = default(r1[0],r1),
+ ry1 = default(r1[1],r1),
+ rx2 = default(r2[0],r2),
+ ry2 = default(r2[1],r2),
+ maxxr = max(rx1,rx2),
+ maxyr = max(ry1,ry2)
+ ) [2*maxxr,2*maxyr,l]
+ ) : type == "spheroid"? ( //r
+ let( r=geom[1] )
+ is_num(r)? [2,2,2]*r : vmul([2,2,2],r)
+ ) : type == "vnf_extent" || type=="vnf_isect"? ( //vnf
+ let(
+ mm = pointlist_bounds(geom[1][0]),
+ delt = mm[1]-mm[0]
+ ) delt
+ ) : type == "rect"? ( //size, size2
+ let(
+ size=geom[1], size2=geom[2],
+ maxx = max(size.x,size2)
+ ) [maxx, size.y]
+ ) : type == "circle"? ( //r
+ let( r=geom[1] )
+ is_num(r)? [2,2]*r : vmul([2,2],r)
+ ) : type == "path_isect" || type == "path_extent"? ( //path
+ let(
+ mm = pointlist_bounds(geom[1]),
+ delt = mm[1]-mm[0]
+ ) [delt.x, delt.y]
+ ) :
+ assert(false, "Unknown attachment geometry type.");
// Function: attach_transform()
@@ -318,61 +318,61 @@ function attach_geom_size(geom) =
// geom = The geometry description of the shape.
// p = If given as a VNF, path, or point, applies the affine3d transformation matrix to it and returns the result.
function attach_transform(anchor=CENTER, spin=0, orient=UP, geom, p) =
- assert(is_string(anchor) || is_vector(anchor))
- assert(is_vector(orient))
- let(
- two_d = attach_geom_2d(geom),
- m = ($attach_to != undef)? (
- let(
- anch = find_anchor($attach_to, geom),
- pos = anch[1]
- ) two_d? (
- assert(two_d && is_num(spin))
- affine3d_zrot(spin) *
- rot(to=FWD, from=point3d(anch[2])) *
- affine3d_translate(point3d(-pos))
- ) : (
- assert(is_num(spin) || is_vector(spin,3))
- let(
- ang = vector_angle(anch[2], DOWN),
- axis = vector_axis(anch[2], DOWN),
- ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3],
- axis2 = rot(p=axis,[0,0,ang2])
- )
- affine3d_rot_by_axis(axis2,ang) * (
- is_num(spin)? affine3d_zrot(ang2+spin) : (
- affine3d_zrot(spin.z) *
- affine3d_yrot(spin.y) *
- affine3d_xrot(spin.x) *
- affine3d_zrot(ang2)
- )
- ) * affine3d_translate(point3d(-pos))
- )
- ) : (
- let(
- pos = find_anchor(anchor, geom)[1]
- ) two_d? (
- assert(two_d && is_num(spin))
- affine3d_zrot(spin) *
- affine3d_translate(point3d(-pos))
- ) : (
- assert(is_num(spin) || is_vector(spin,3))
- let(
- axis = vector_axis(UP,orient),
- ang = vector_angle(UP,orient)
- )
- affine3d_rot_by_axis(axis,ang) * (
- is_num(spin)? affine3d_zrot(spin) : (
- affine3d_zrot(spin.z) *
- affine3d_yrot(spin.y) *
- affine3d_xrot(spin.x)
- )
- ) * affine3d_translate(point3d(-pos))
- )
- )
- ) is_undef(p)? m :
- is_vnf(p)? [apply(m, p[0]), p[1]] :
- apply(m, p);
+ assert(is_string(anchor) || is_vector(anchor))
+ assert(is_vector(orient))
+ let(
+ two_d = attach_geom_2d(geom),
+ m = ($attach_to != undef)? (
+ let(
+ anch = find_anchor($attach_to, geom),
+ pos = anch[1]
+ ) two_d? (
+ assert(two_d && is_num(spin))
+ affine3d_zrot(spin) *
+ rot(to=FWD, from=point3d(anch[2])) *
+ affine3d_translate(point3d(-pos))
+ ) : (
+ assert(is_num(spin) || is_vector(spin,3))
+ let(
+ ang = vector_angle(anch[2], DOWN),
+ axis = vector_axis(anch[2], DOWN),
+ ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3],
+ axis2 = rot(p=axis,[0,0,ang2])
+ )
+ affine3d_rot_by_axis(axis2,ang) * (
+ is_num(spin)? affine3d_zrot(ang2+spin) : (
+ affine3d_zrot(spin.z) *
+ affine3d_yrot(spin.y) *
+ affine3d_xrot(spin.x) *
+ affine3d_zrot(ang2)
+ )
+ ) * affine3d_translate(point3d(-pos))
+ )
+ ) : (
+ let(
+ pos = find_anchor(anchor, geom)[1]
+ ) two_d? (
+ assert(two_d && is_num(spin))
+ affine3d_zrot(spin) *
+ affine3d_translate(point3d(-pos))
+ ) : (
+ assert(is_num(spin) || is_vector(spin,3))
+ let(
+ axis = vector_axis(UP,orient),
+ ang = vector_angle(UP,orient)
+ )
+ affine3d_rot_by_axis(axis,ang) * (
+ is_num(spin)? affine3d_zrot(spin) : (
+ affine3d_zrot(spin.z) *
+ affine3d_yrot(spin.y) *
+ affine3d_xrot(spin.x)
+ )
+ ) * affine3d_translate(point3d(-pos))
+ )
+ )
+ ) is_undef(p)? m :
+ is_vnf(p)? [apply(m, p[0]), p[1]] :
+ apply(m, p);
// Function: find_anchor()
@@ -387,166 +387,166 @@ function attach_transform(anchor=CENTER, spin=0, orient=UP, geom, p) =
// anchor = Vector or named anchor string.
// geom = The geometry description of the shape.
function find_anchor(anchor, geom) =
- let(
- offset = anchor==CENTER? CENTER : select(geom,-2),
- anchors = select(geom,-1),
- type = geom[0]
- )
- is_string(anchor)? (
- let(found = search([anchor], anchors, num_returns_per_match=1)[0])
- assert(found!=[], str("Unknown anchor: ",anchor))
- anchors[found]
- ) :
- assert(is_vector(anchor),str("anchor=",anchor))
- let(anchor = point3d(anchor))
- anchor==CENTER? [anchor, CENTER, UP, 0] :
- let(
- oang = (
- approx(point2d(anchor), [0,0])? 0 :
- atan2(anchor.y, anchor.x)+90
- )
- )
- type == "cuboid"? ( //size, size2, shift
- let(
- size=geom[1], size2=geom[2], shift=point2d(geom[3]),
- h = size.z,
- u = (anchor.z+1)/2,
- axy = point2d(anchor),
- bot = point3d(vmul(point2d(size)/2,axy),-h/2),
- top = point3d(vmul(point2d(size2)/2,axy)+shift,h/2),
- pos = lerp(bot,top,u)+offset,
- sidevec = unit(rot(from=UP, to=top-bot, p=point3d(axy))),
- vvec = unit([0,0,anchor.z]),
- vec = anchor==CENTER? UP :
- approx(axy,[0,0])? unit(anchor) :
- approx(anchor.z,0)? sidevec :
- unit((sidevec+vvec)/2)
- ) [anchor, pos, vec, oang]
- ) : type == "cyl"? ( //r1, r2, l, shift
- let(
- rr1=geom[1], rr2=geom[2], l=geom[3], shift=point2d(geom[4]),
- r1 = is_num(rr1)? [rr1,rr1] : rr1,
- r2 = is_num(rr2)? [rr2,rr2] : rr2,
- u = (anchor.z+1)/2,
- axy = unit(point2d(anchor)),
- bot = point3d(vmul(r1,axy), -l/2),
- top = point3d(vmul(r2,axy)+shift, l/2),
- pos = lerp(bot,top,u)+offset,
- sidevec = rot(from=UP, to=top-bot, p=point3d(axy)),
- vvec = unit([0,0,anchor.z]),
- vec = anchor==CENTER? UP :
- approx(axy,[0,0])? unit(anchor) :
- approx(anchor.z,0)? sidevec :
- unit((sidevec+vvec)/2)
- ) [anchor, pos, vec, oang]
- ) : type == "spheroid"? ( //r
- let(
- rr = geom[1],
- r = is_num(rr)? [rr,rr,rr] : rr,
- anchor = unit(point3d(anchor))
- ) [anchor, vmul(r,anchor)+offset, unit(vmul(r,anchor)), oang]
- ) : type == "vnf_isect"? ( //vnf
- let(
- vnf=geom[1],
- eps = 1/2048,
- rpts = rot(from=anchor, to=RIGHT, p=vnf[0]),
- hits = [
- for (i = idx(vnf[1])) let(
- face = vnf[1][i],
- verts = select(rpts, face)
- ) if (
- max(subindex(verts,0)) >= -eps &&
- max(subindex(verts,1)) >= -eps &&
- max(subindex(verts,2)) >= -eps &&
- min(subindex(verts,1)) <= eps &&
- min(subindex(verts,2)) <= eps
- ) let(
- pt = polygon_line_intersection(
- select(vnf[0], face),
- [CENTER,anchor], eps=eps
- )
- ) if (!is_undef(pt)) [norm(pt),i,pt]
- ]
- )
- assert(len(hits)>0, "Anchor vector does not intersect with the shape. Attachment failed.")
- let(
- furthest = max_index(subindex(hits,0)),
- pos = hits[furthest][2],
- dist = hits[furthest][0],
- nfaces = [for (hit = hits) if(approx(hit[0],dist,eps=eps)) hit[1]],
- n = unit(
- sum([
- for (i = nfaces) let(
- faceverts = select(vnf[0],vnf[1][i]),
- faceplane = plane_from_points(faceverts),
- nrm = plane_normal(faceplane)
- ) nrm
- ]) / len(nfaces)
- )
- )
- [anchor, pos, n, oang]
- ) : type == "vnf_extent"? ( //vnf
- let(
- vnf=geom[1],
- rpts = rot(from=anchor, to=RIGHT, p=vnf[0]),
- maxx = max(subindex(rpts,0)),
- idxs = [for (i = idx(rpts)) if (approx(rpts[i].x, maxx)) i],
- mm = pointlist_bounds(select(rpts,idxs)),
- avgy = (mm[0].y+mm[1].y)/2,
- avgz = (mm[0].z+mm[1].z)/2,
- mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : [maxx, avgy, avgz],
- pos = rot(from=RIGHT, to=anchor, p=mpt)
- ) [anchor, pos, anchor, oang]
- ) : type == "rect"? ( //size, size2
- let(
- size=geom[1], size2=geom[2],
- u = (anchor.y+1)/2,
- frpt = [size.x/2*anchor.x, -size.y/2],
- bkpt = [size2/2*anchor.x, size.y/2],
- pos = lerp(frpt, bkpt, u),
- vec = unit(rot(from=BACK, to=bkpt-frpt, p=anchor))
- ) [anchor, pos, vec, 0]
- ) : type == "circle"? ( //r
- let(
- rr = geom[1],
- r = is_num(rr)? [rr,rr] : rr,
- anchor = unit(point2d(anchor))
- ) [anchor, vmul(r,anchor)+offset, unit(vmul([r.y,r.x],anchor)), 0]
- ) : type == "path_isect"? ( //path
- let(
- path=geom[1],
- anchor = point2d(anchor),
- isects = [
- for (t=triplet_wrap(path)) let(
- seg1 = [t[0],t[1]],
- seg2 = [t[1],t[2]],
- 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),
- n2 = vector_angle(anchor,n)>90? -n : n
- )
- if(!is_undef(isect) && !approx(isect,t[0])) [norm(isect), isect, n2]
- ],
- maxidx = max_index(subindex(isects,0)),
- isect = isects[maxidx],
- pos = isect[1],
- vec = unit(isect[2])
- ) [anchor, pos, vec, 0]
- ) : type == "path_extent"? ( //path
- let(
- path=geom[1],
- anchor = point2d(anchor),
- rpath = rot(from=anchor, to=RIGHT, p=path),
- maxx = max(subindex(rpath,0)),
- idxs = [for (i = idx(rpath)) if (approx(rpath[i].x, maxx)) i],
- miny = min([for (i=idxs) rpath[i].y]),
- maxy = max([for (i=idxs) rpath[i].y]),
- avgy = (miny+maxy)/2,
- pos = rot(from=RIGHT, to=anchor, p=[maxx,avgy])
- ) [anchor, pos, anchor, 0]
- ) :
- assert(false, "Unknown attachment geometry type.");
+ let(
+ offset = anchor==CENTER? CENTER : select(geom,-2),
+ anchors = select(geom,-1),
+ type = geom[0]
+ )
+ is_string(anchor)? (
+ let(found = search([anchor], anchors, num_returns_per_match=1)[0])
+ assert(found!=[], str("Unknown anchor: ",anchor))
+ anchors[found]
+ ) :
+ assert(is_vector(anchor),str("anchor=",anchor))
+ let(anchor = point3d(anchor))
+ anchor==CENTER? [anchor, CENTER, UP, 0] :
+ let(
+ oang = (
+ approx(point2d(anchor), [0,0])? 0 :
+ atan2(anchor.y, anchor.x)+90
+ )
+ )
+ type == "cuboid"? ( //size, size2, shift
+ let(
+ size=geom[1], size2=geom[2], shift=point2d(geom[3]),
+ h = size.z,
+ u = (anchor.z+1)/2,
+ axy = point2d(anchor),
+ bot = point3d(vmul(point2d(size)/2,axy),-h/2),
+ top = point3d(vmul(point2d(size2)/2,axy)+shift,h/2),
+ pos = lerp(bot,top,u)+offset,
+ sidevec = unit(rot(from=UP, to=top-bot, p=point3d(axy))),
+ vvec = unit([0,0,anchor.z]),
+ vec = anchor==CENTER? UP :
+ approx(axy,[0,0])? unit(anchor) :
+ approx(anchor.z,0)? sidevec :
+ unit((sidevec+vvec)/2)
+ ) [anchor, pos, vec, oang]
+ ) : type == "cyl"? ( //r1, r2, l, shift
+ let(
+ rr1=geom[1], rr2=geom[2], l=geom[3], shift=point2d(geom[4]),
+ r1 = is_num(rr1)? [rr1,rr1] : rr1,
+ r2 = is_num(rr2)? [rr2,rr2] : rr2,
+ u = (anchor.z+1)/2,
+ axy = unit(point2d(anchor)),
+ bot = point3d(vmul(r1,axy), -l/2),
+ top = point3d(vmul(r2,axy)+shift, l/2),
+ pos = lerp(bot,top,u)+offset,
+ sidevec = rot(from=UP, to=top-bot, p=point3d(axy)),
+ vvec = unit([0,0,anchor.z]),
+ vec = anchor==CENTER? UP :
+ approx(axy,[0,0])? unit(anchor) :
+ approx(anchor.z,0)? sidevec :
+ unit((sidevec+vvec)/2)
+ ) [anchor, pos, vec, oang]
+ ) : type == "spheroid"? ( //r
+ let(
+ rr = geom[1],
+ r = is_num(rr)? [rr,rr,rr] : rr,
+ anchor = unit(point3d(anchor))
+ ) [anchor, vmul(r,anchor)+offset, unit(vmul(r,anchor)), oang]
+ ) : type == "vnf_isect"? ( //vnf
+ let(
+ vnf=geom[1],
+ eps = 1/2048,
+ rpts = rot(from=anchor, to=RIGHT, p=vnf[0]),
+ hits = [
+ for (i = idx(vnf[1])) let(
+ face = vnf[1][i],
+ verts = select(rpts, face)
+ ) if (
+ max(subindex(verts,0)) >= -eps &&
+ max(subindex(verts,1)) >= -eps &&
+ max(subindex(verts,2)) >= -eps &&
+ min(subindex(verts,1)) <= eps &&
+ min(subindex(verts,2)) <= eps
+ ) let(
+ pt = polygon_line_intersection(
+ select(vnf[0], face),
+ [CENTER,anchor], eps=eps
+ )
+ ) if (!is_undef(pt)) [norm(pt),i,pt]
+ ]
+ )
+ assert(len(hits)>0, "Anchor vector does not intersect with the shape. Attachment failed.")
+ let(
+ furthest = max_index(subindex(hits,0)),
+ pos = hits[furthest][2],
+ dist = hits[furthest][0],
+ nfaces = [for (hit = hits) if(approx(hit[0],dist,eps=eps)) hit[1]],
+ n = unit(
+ sum([
+ for (i = nfaces) let(
+ faceverts = select(vnf[0],vnf[1][i]),
+ faceplane = plane_from_points(faceverts),
+ nrm = plane_normal(faceplane)
+ ) nrm
+ ]) / len(nfaces)
+ )
+ )
+ [anchor, pos, n, oang]
+ ) : type == "vnf_extent"? ( //vnf
+ let(
+ vnf=geom[1],
+ rpts = rot(from=anchor, to=RIGHT, p=vnf[0]),
+ maxx = max(subindex(rpts,0)),
+ idxs = [for (i = idx(rpts)) if (approx(rpts[i].x, maxx)) i],
+ mm = pointlist_bounds(select(rpts,idxs)),
+ avgy = (mm[0].y+mm[1].y)/2,
+ avgz = (mm[0].z+mm[1].z)/2,
+ mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : [maxx, avgy, avgz],
+ pos = rot(from=RIGHT, to=anchor, p=mpt)
+ ) [anchor, pos, anchor, oang]
+ ) : type == "rect"? ( //size, size2
+ let(
+ size=geom[1], size2=geom[2],
+ u = (anchor.y+1)/2,
+ frpt = [size.x/2*anchor.x, -size.y/2],
+ bkpt = [size2/2*anchor.x, size.y/2],
+ pos = lerp(frpt, bkpt, u),
+ vec = unit(rot(from=BACK, to=bkpt-frpt, p=anchor))
+ ) [anchor, pos, vec, 0]
+ ) : type == "circle"? ( //r
+ let(
+ rr = geom[1],
+ r = is_num(rr)? [rr,rr] : rr,
+ anchor = unit(point2d(anchor))
+ ) [anchor, vmul(r,anchor)+offset, unit(vmul([r.y,r.x],anchor)), 0]
+ ) : type == "path_isect"? ( //path
+ let(
+ path=geom[1],
+ anchor = point2d(anchor),
+ isects = [
+ for (t=triplet_wrap(path)) let(
+ seg1 = [t[0],t[1]],
+ seg2 = [t[1],t[2]],
+ 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),
+ n2 = vector_angle(anchor,n)>90? -n : n
+ )
+ if(!is_undef(isect) && !approx(isect,t[0])) [norm(isect), isect, n2]
+ ],
+ maxidx = max_index(subindex(isects,0)),
+ isect = isects[maxidx],
+ pos = isect[1],
+ vec = unit(isect[2])
+ ) [anchor, pos, vec, 0]
+ ) : type == "path_extent"? ( //path
+ let(
+ path=geom[1],
+ anchor = point2d(anchor),
+ rpath = rot(from=anchor, to=RIGHT, p=path),
+ maxx = max(subindex(rpath,0)),
+ idxs = [for (i = idx(rpath)) if (approx(rpath[i].x, maxx)) i],
+ miny = min([for (i=idxs) rpath[i].y]),
+ maxy = max([for (i=idxs) rpath[i].y]),
+ avgy = (miny+maxy)/2,
+ pos = rot(from=RIGHT, to=anchor, p=[maxx,avgy])
+ ) [anchor, pos, anchor, 0]
+ ) :
+ assert(false, "Unknown attachment geometry type.");
// Function: attachment_is_shown()
@@ -555,13 +555,13 @@ function find_anchor(anchor, geom) =
// Description:
// Returns true if the given space-delimited string of tag names should currently be shown.
function attachment_is_shown(tags) =
- assert(!is_undef($tags_shown))
- assert(!is_undef($tags_hidden))
- let(
- tags = str_split(tags, " "),
- shown = !$tags_shown || any([for (tag=tags) in_list(tag, $tags_shown)]),
- hidden = any([for (tag=tags) in_list(tag, $tags_hidden)])
- ) shown && !hidden;
+ assert(!is_undef($tags_shown))
+ assert(!is_undef($tags_hidden))
+ let(
+ tags = str_split(tags, " "),
+ shown = !$tags_shown || any([for (tag=tags) in_list(tag, $tags_shown)]),
+ hidden = any([for (tag=tags) in_list(tag, $tags_hidden)])
+ ) shown && !hidden;
// Function: reorient()
@@ -620,27 +620,27 @@ function attachment_is_shown(tags) =
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
// p = The VNF, path, or point to transform.
function reorient(
- anchor=CENTER,
- spin=0,
- orient=UP,
- size, size2, shift,
- r,r1,r2, d,d1,d2, l,h,
- vnf, path,
- extent=true,
- offset=[0,0,0],
- anchors=[],
- two_d=false,
- p=undef
+ anchor=CENTER,
+ spin=0,
+ orient=UP,
+ size, size2, shift,
+ r,r1,r2, d,d1,d2, l,h,
+ vnf, path,
+ extent=true,
+ offset=[0,0,0],
+ anchors=[],
+ two_d=false,
+ p=undef
) = (anchor==CENTER && spin==0 && orient==UP && p!=undef)? p : let(
- geom = attach_geom(
- size=size, size2=size2, shift=shift,
- r=r, r1=r1, r2=r2, h=h,
- d=d, d1=d1, d2=d2, l=l,
- vnf=vnf, path=path, extent=extent,
- offset=offset, anchors=anchors,
- two_d=two_d
- ),
- $attach_to = undef
+ geom = attach_geom(
+ size=size, size2=size2, shift=shift,
+ r=r, r1=r1, r2=r2, h=h,
+ d=d, d1=d1, d2=d2, l=l,
+ vnf=vnf, path=path, extent=extent,
+ offset=offset, anchors=anchors,
+ two_d=two_d
+ ),
+ $attach_to = undef
) attach_transform(anchor,spin,orient,geom,p);
@@ -784,47 +784,47 @@ function reorient(
// children();
// }
module attachable(
- anchor=CENTER,
- spin=0,
- orient=UP,
- size, size2, shift,
- r,r1,r2, d,d1,d2, l,h,
- vnf, path,
- extent=true,
- offset=[0,0,0],
- anchors=[],
- two_d=false
+ anchor=CENTER,
+ spin=0,
+ orient=UP,
+ size, size2, shift,
+ r,r1,r2, d,d1,d2, l,h,
+ vnf, path,
+ extent=true,
+ offset=[0,0,0],
+ anchors=[],
+ two_d=false
) {
- assert($children==2, "attachable() expects exactly two children; the shape to manage, and the union of all attachment candidates.");
- assert(!is_undef(anchor), str("anchor undefined in attachable(). Did you forget to set a default value for anchor in ", parent_module(1)));
- assert(!is_undef(spin), str("spin undefined in attachable(). Did you forget to set a default value for spin in ", parent_module(1)));
- assert(!is_undef(orient), str("orient undefined in attachable(). Did you forget to set a default value for orient in ", parent_module(1)));
- geom = attach_geom(
- size=size, size2=size2, shift=shift,
- r=r, r1=r1, r2=r2, h=h,
- d=d, d1=d1, d2=d2, l=l,
- vnf=vnf, path=path, extent=extent,
- offset=offset, anchors=anchors,
- two_d=two_d
- );
- m = attach_transform(anchor,spin,orient,geom);
- multmatrix(m) {
- $parent_anchor = anchor;
- $parent_spin = spin;
- $parent_orient = orient;
- $parent_geom = geom;
- $parent_size = attach_geom_size(geom);
- $attach_to = undef;
- if (attachment_is_shown($tags)) {
- if (is_undef($color)) {
- children(0);
- } else color($color) {
- $color = undef;
- children(0);
- }
- }
- children(1);
- }
+ assert($children==2, "attachable() expects exactly two children; the shape to manage, and the union of all attachment candidates.");
+ assert(!is_undef(anchor), str("anchor undefined in attachable(). Did you forget to set a default value for anchor in ", parent_module(1)));
+ assert(!is_undef(spin), str("spin undefined in attachable(). Did you forget to set a default value for spin in ", parent_module(1)));
+ assert(!is_undef(orient), str("orient undefined in attachable(). Did you forget to set a default value for orient in ", parent_module(1)));
+ geom = attach_geom(
+ size=size, size2=size2, shift=shift,
+ r=r, r1=r1, r2=r2, h=h,
+ d=d, d1=d1, d2=d2, l=l,
+ vnf=vnf, path=path, extent=extent,
+ offset=offset, anchors=anchors,
+ two_d=two_d
+ );
+ m = attach_transform(anchor,spin,orient,geom);
+ multmatrix(m) {
+ $parent_anchor = anchor;
+ $parent_spin = spin;
+ $parent_orient = orient;
+ $parent_geom = geom;
+ $parent_size = attach_geom_size(geom);
+ $attach_to = undef;
+ if (attachment_is_shown($tags)) {
+ if (is_undef($color)) {
+ children(0);
+ } else color($color) {
+ $color = undef;
+ children(0);
+ }
+ }
+ children(1);
+ }
}
@@ -846,15 +846,15 @@ module attachable(
// }
module position(from)
{
- assert($parent_geom != undef, "No object to attach to!");
- anchors = (is_vector(from)||is_string(from))? [from] : from;
- for (anchr = anchors) {
- anch = find_anchor(anchr, $parent_geom);
- $attach_to = undef;
- $attach_anchor = anch;
- $attach_norot = true;
- translate(anch[1]) children();
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ anchors = (is_vector(from)||is_string(from))? [from] : from;
+ for (anchr = anchors) {
+ anch = find_anchor(anchr, $parent_geom);
+ $attach_to = undef;
+ $attach_anchor = anch;
+ $attach_norot = true;
+ translate(anch[1]) children();
+ }
}
@@ -882,22 +882,22 @@ module position(from)
// }
module attach(from, to=undef, overlap=undef, norot=false)
{
- assert($parent_geom != undef, "No object to attach to!");
- overlap = (overlap!=undef)? overlap : $overlap;
- anchors = (is_vector(from)||is_string(from))? [from] : from;
- for (anchr = anchors) {
- anch = find_anchor(anchr, $parent_geom);
- two_d = attach_geom_2d($parent_geom);
- $attach_to = to;
- $attach_anchor = anch;
- $attach_norot = norot;
- if (norot || (norm(anch[2]-UP)<1e-9 && anch[3]==0)) {
- translate(anch[1]) translate([0,0,-overlap]) children();
- } else {
- fromvec = two_d? BACK : UP;
- translate(anch[1]) rot(anch[3],from=fromvec,to=anch[2]) translate([0,0,-overlap]) children();
- }
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ overlap = (overlap!=undef)? overlap : $overlap;
+ anchors = (is_vector(from)||is_string(from))? [from] : from;
+ for (anchr = anchors) {
+ anch = find_anchor(anchr, $parent_geom);
+ two_d = attach_geom_2d($parent_geom);
+ $attach_to = to;
+ $attach_anchor = anch;
+ $attach_norot = norot;
+ if (norot || (norm(anch[2]-UP)<1e-9 && anch[3]==0)) {
+ translate(anch[1]) translate([0,0,-overlap]) children();
+ } else {
+ fromvec = two_d? BACK : UP;
+ translate(anch[1]) rot(anch[3],from=fromvec,to=anch[2]) translate([0,0,-overlap]) children();
+ }
+ }
}
@@ -912,12 +912,12 @@ module attach(from, to=undef, overlap=undef, norot=false)
// d = Diameter of corner mask.
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
module face_profile(faces=[], r, d, convexity=10) {
- faces = is_vector(faces)? [faces] : faces;
- assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "Vector in faces doesn't point at a face.");
- r = get_radius(r=r, d=d, dflt=undef);
- assert(is_num(r) && r>0);
- edge_profile(faces) children();
- corner_profile(faces, convexity=convexity, r=r) children();
+ faces = is_vector(faces)? [faces] : faces;
+ assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "Vector in faces doesn't point at a face.");
+ r = get_radius(r=r, d=d, dflt=undef);
+ assert(is_num(r) && r>0);
+ edge_profile(faces) children();
+ corner_profile(faces, convexity=convexity, r=r) children();
}
@@ -939,35 +939,35 @@ module face_profile(faces=[], r, d, convexity=10) {
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_roundover(r=10, inset=2);
module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
- assert($parent_geom != undef, "No object to attach to!");
- edges = edges(edges, except=except);
- vecs = [
- for (i = [0:3], axis=[0:2])
- if (edges[axis][i]>0)
- EDGE_OFFSETS[axis][i]
- ];
- for (vec = vecs) {
- vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
- assert(vcount == 2, "Not an edge vector!");
- anch = find_anchor(vec, $parent_geom);
- $attach_to = undef;
- $attach_anchor = anch;
- $attach_norot = true;
- $tags = "mask";
- length = sum(vmul($parent_size, [for (x=vec) x?0:1]))+0.1;
- rotang =
- vec.z<0? [90,0,180+vang(point2d(vec))] :
- vec.z==0 && sign(vec.x)==sign(vec.y)? 135+vang(point2d(vec)) :
- vec.z==0 && sign(vec.x)!=sign(vec.y)? [0,180,45+vang(point2d(vec))] :
- [-90,0,180+vang(point2d(vec))];
- translate(anch[1]) {
- rot(rotang) {
- linear_extrude(height=length, center=true, convexity=convexity) {
- children();
- }
- }
- }
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ edges = edges(edges, except=except);
+ vecs = [
+ for (i = [0:3], axis=[0:2])
+ if (edges[axis][i]>0)
+ EDGE_OFFSETS[axis][i]
+ ];
+ for (vec = vecs) {
+ vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
+ assert(vcount == 2, "Not an edge vector!");
+ anch = find_anchor(vec, $parent_geom);
+ $attach_to = undef;
+ $attach_anchor = anch;
+ $attach_norot = true;
+ $tags = "mask";
+ length = sum(vmul($parent_size, [for (x=vec) x?0:1]))+0.1;
+ rotang =
+ vec.z<0? [90,0,180+vang(point2d(vec))] :
+ vec.z==0 && sign(vec.x)==sign(vec.y)? 135+vang(point2d(vec)) :
+ vec.z==0 && sign(vec.x)!=sign(vec.y)? [0,180,45+vang(point2d(vec))] :
+ [-90,0,180+vang(point2d(vec))];
+ translate(anch[1]) {
+ rot(rotang) {
+ linear_extrude(height=length, center=true, convexity=convexity) {
+ children();
+ }
+ }
+ }
+ }
}
// Module: corner_profile()
@@ -988,45 +988,45 @@ module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
// Example:
// diff("mask")
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
-// corner_profile(BOT,r=10)
-// mask2d_teardrop(r=10, angle=40);
+// corner_profile(BOT,r=10)
+// mask2d_teardrop(r=10, angle=40);
// }
module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
- assert($parent_geom != undef, "No object to attach to!");
- r = get_radius(r=r, d=d, dflt=undef);
- assert(is_num(r));
- corners = corners(corners, except=except);
- vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
- for (vec = vecs) {
- vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
- assert(vcount == 3, "Not an edge vector!");
- anch = find_anchor(vec, $parent_geom);
- $attach_to = undef;
- $attach_anchor = anch;
- $attach_norot = true;
- $tags = "mask";
- rotang = vec.z<0?
- [ 0,0,180+vang(point2d(vec))-45] :
- [180,0,-90+vang(point2d(vec))-45];
- translate(anch[1]) {
- rot(rotang) {
- render(convexity=convexity)
- difference() {
- translate(-0.1*[1,1,1]) cube(r+0.1, center=false);
- right(r) back(r) zrot(180) {
- rotate_extrude(angle=90, convexity=convexity) {
- xflip() left(r) {
- difference() {
- square(r,center=false);
- children();
- }
- }
- }
- }
- }
- }
- }
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ r = get_radius(r=r, d=d, dflt=undef);
+ assert(is_num(r));
+ corners = corners(corners, except=except);
+ vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
+ for (vec = vecs) {
+ vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
+ assert(vcount == 3, "Not an edge vector!");
+ anch = find_anchor(vec, $parent_geom);
+ $attach_to = undef;
+ $attach_anchor = anch;
+ $attach_norot = true;
+ $tags = "mask";
+ rotang = vec.z<0?
+ [ 0,0,180+vang(point2d(vec))-45] :
+ [180,0,-90+vang(point2d(vec))-45];
+ translate(anch[1]) {
+ rot(rotang) {
+ render(convexity=convexity)
+ difference() {
+ translate(-0.1*[1,1,1]) cube(r+0.1, center=false);
+ right(r) back(r) zrot(180) {
+ rotate_extrude(angle=90, convexity=convexity) {
+ xflip() left(r) {
+ difference() {
+ square(r,center=false);
+ children();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
@@ -1049,28 +1049,28 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
// edge_mask([TOP,"Z"],except=[BACK,TOP+LEFT])
// rounding_mask_z(l=71,r=10);
module edge_mask(edges=EDGES_ALL, except=[]) {
- assert($parent_geom != undef, "No object to attach to!");
- edges = edges(edges, except=except);
- vecs = [
- for (i = [0:3], axis=[0:2])
- if (edges[axis][i]>0)
- EDGE_OFFSETS[axis][i]
- ];
- for (vec = vecs) {
- vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
- assert(vcount == 2, "Not an edge vector!");
- anch = find_anchor(vec, $parent_geom);
- $attach_to = undef;
- $attach_anchor = anch;
- $attach_norot = true;
- $tags = "mask";
- rotang =
- vec.z<0? [90,0,180+vang(point2d(vec))] :
- vec.z==0 && sign(vec.x)==sign(vec.y)? 135+vang(point2d(vec)) :
- vec.z==0 && sign(vec.x)!=sign(vec.y)? [0,180,45+vang(point2d(vec))] :
- [-90,0,180+vang(point2d(vec))];
- translate(anch[1]) rot(rotang) children();
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ edges = edges(edges, except=except);
+ vecs = [
+ for (i = [0:3], axis=[0:2])
+ if (edges[axis][i]>0)
+ EDGE_OFFSETS[axis][i]
+ ];
+ for (vec = vecs) {
+ vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
+ assert(vcount == 2, "Not an edge vector!");
+ anch = find_anchor(vec, $parent_geom);
+ $attach_to = undef;
+ $attach_anchor = anch;
+ $attach_norot = true;
+ $tags = "mask";
+ rotang =
+ vec.z<0? [90,0,180+vang(point2d(vec))] :
+ vec.z==0 && sign(vec.x)==sign(vec.y)? 135+vang(point2d(vec)) :
+ vec.z==0 && sign(vec.x)!=sign(vec.y)? [0,180,45+vang(point2d(vec))] :
+ [-90,0,180+vang(point2d(vec))];
+ translate(anch[1]) rot(rotang) children();
+ }
}
@@ -1095,22 +1095,22 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
// translate([20,20,20]) sphere(r=20);
// }
module corner_mask(corners=CORNERS_ALL, except=[]) {
- assert($parent_geom != undef, "No object to attach to!");
- corners = corners(corners, except=except);
- vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
- for (vec = vecs) {
- vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
- assert(vcount == 3, "Not an edge vector!");
- anch = find_anchor(vec, $parent_geom);
- $attach_to = undef;
- $attach_anchor = anch;
- $attach_norot = true;
- $tags = "mask";
- rotang = vec.z<0?
- [ 0,0,180+vang(point2d(vec))-45] :
- [180,0,-90+vang(point2d(vec))-45];
- translate(anch[1]) rot(rotang) children();
- }
+ assert($parent_geom != undef, "No object to attach to!");
+ corners = corners(corners, except=except);
+ vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
+ for (vec = vecs) {
+ vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
+ assert(vcount == 3, "Not an edge vector!");
+ anch = find_anchor(vec, $parent_geom);
+ $attach_to = undef;
+ $attach_anchor = anch;
+ $attach_norot = true;
+ $tags = "mask";
+ rotang = vec.z<0?
+ [ 0,0,180+vang(point2d(vec))-45] :
+ [180,0,-90+vang(point2d(vec))-45];
+ translate(anch[1]) rot(rotang) children();
+ }
}
@@ -1123,8 +1123,8 @@ module corner_mask(corners=CORNERS_ALL, except=[]) {
// tags = String containing space delimited set of tags to apply.
module tags(tags)
{
- $tags = tags;
- children();
+ $tags = tags;
+ children();
}
@@ -1139,8 +1139,8 @@ module tags(tags)
// recolor("red") cyl(l=20, d=10);
module recolor(c)
{
- $color = c;
- children();
+ $color = c;
+ children();
}
@@ -1156,8 +1156,8 @@ module recolor(c)
// }
module hide(tags="")
{
- $tags_hidden = tags==""? [] : str_split(tags, " ");
- children();
+ $tags_hidden = tags==""? [] : str_split(tags, " ");
+ children();
}
@@ -1173,8 +1173,8 @@ module hide(tags="")
// }
module show(tags="")
{
- $tags_shown = tags==""? [] : str_split(tags, " ");
- children();
+ $tags_shown = tags==""? [] : str_split(tags, " ");
+ children();
}
@@ -1214,23 +1214,23 @@ module show(tags="")
// }
module diff(neg, pos=undef, keep=undef)
{
- difference() {
- if (pos != undef) {
- show(pos) children();
- } else {
- if (keep == undef) {
- hide(neg) children();
- } else {
- hide(str(neg," ",keep)) children();
- }
- }
- show(neg) children();
- }
- if (keep!=undef) {
- show(keep) children();
- } else if (pos!=undef) {
- hide(str(pos," ",neg)) children();
- }
+ difference() {
+ if (pos != undef) {
+ show(pos) children();
+ } else {
+ if (keep == undef) {
+ hide(neg) children();
+ } else {
+ hide(str(neg," ",keep)) children();
+ }
+ }
+ show(neg) children();
+ }
+ if (keep!=undef) {
+ show(keep) children();
+ } else if (pos!=undef) {
+ hide(str(pos," ",neg)) children();
+ }
}
@@ -1259,23 +1259,23 @@ module diff(neg, pos=undef, keep=undef)
// }
module intersect(a, b=undef, keep=undef)
{
- intersection() {
- if (b != undef) {
- show(b) children();
- } else {
- if (keep == undef) {
- hide(a) children();
- } else {
- hide(str(a," ",keep)) children();
- }
- }
- show(a) children();
- }
- if (keep!=undef) {
- show(keep) children();
- } else if (b!=undef) {
- hide(str(a," ",b)) children();
- }
+ intersection() {
+ if (b != undef) {
+ show(b) children();
+ } else {
+ if (keep == undef) {
+ hide(a) children();
+ } else {
+ hide(str(a," ",keep)) children();
+ }
+ }
+ show(a) children();
+ }
+ if (keep!=undef) {
+ show(keep) children();
+ } else if (b!=undef) {
+ hide(str(a," ",b)) children();
+ }
}
@@ -1299,10 +1299,10 @@ module intersect(a, b=undef, keep=undef)
// }
module hulling(a)
{
- hull() show(a) children();
- children();
+ hull() show(a) children();
+ children();
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/beziers.scad b/beziers.scad
index 3953ef4..68c59fc 100644
--- a/beziers.scad
+++ b/beziers.scad
@@ -81,36 +81,36 @@ include
// lookup table or hard coded powers list the code is about twice as fast as the recursive method.
// Note that everything I tried to simplify or tidy this code made is slower, sometimes a lot slower.
function bezier_points(curve, u) =
- is_num(u) ? bezier_points(curve,[u])[0] :
- let(
- N = len(curve)-1,
- M = _bezier_matrix(N)*curve
- )
- N==0 ? [for(uval=u)[1]*M] :
- N==1 ? [for(uval=u)[1, uval]*M] :
- N==2 ? [for(uval=u)[1, uval, uval*uval]*M] :
- N==3 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval]*M] : // It appears that pow() is as fast or faster for powers 5 or above
- N==4 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval]*M] :
- N==5 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5)]*M] :
- N==6 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6)]*M] :
- N==7 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7)]*M] :
- N==8 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8)]*M] :
- N==9 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8), pow(uval,9)]*M] :
- N==10? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8), pow(uval,9), pow(uval,10)]*M] :
- /* N>=11 */ [for(uval=u)[for (i=[0:1:N]) pow(uval,i)]*M];
+ is_num(u) ? bezier_points(curve,[u])[0] :
+ let(
+ N = len(curve)-1,
+ M = _bezier_matrix(N)*curve
+ )
+ N==0 ? [for(uval=u)[1]*M] :
+ N==1 ? [for(uval=u)[1, uval]*M] :
+ N==2 ? [for(uval=u)[1, uval, uval*uval]*M] :
+ N==3 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval]*M] : // It appears that pow() is as fast or faster for powers 5 or above
+ N==4 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval]*M] :
+ N==5 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5)]*M] :
+ N==6 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6)]*M] :
+ N==7 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7)]*M] :
+ N==8 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8)]*M] :
+ N==9 ? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8), pow(uval,9)]*M] :
+ N==10? [for(uval=u)[1, uval, uval*uval, uval*uval*uval, uval*uval*uval*uval, pow(uval,5),pow(uval,6), pow(uval,7), pow(uval,8), pow(uval,9), pow(uval,10)]*M] :
+ /* N>=11 */ [for(uval=u)[for (i=[0:1:N]) pow(uval,i)]*M];
// Not public.
function _signed_pascals_triangle(N,tri=[[-1]]) =
- len(tri)==N+1 ? tri :
- let(last=tri[len(tri)-1])
- _signed_pascals_triangle(N,concat(tri,[[-1, for(i=[0:1:len(tri)-2]) (i%2==1?-1:1)*(abs(last[i])+abs(last[i+1])),len(last)%2==0? -1:1]]));
+ len(tri)==N+1 ? tri :
+ let(last=tri[len(tri)-1])
+ _signed_pascals_triangle(N,concat(tri,[[-1, for(i=[0:1:len(tri)-2]) (i%2==1?-1:1)*(abs(last[i])+abs(last[i+1])),len(last)%2==0? -1:1]]));
// Not public.
function _compute_bezier_matrix(N) =
- let(tri = _signed_pascals_triangle(N))
- [for(i=[0:N]) concat(tri[N][i]*tri[i], repeat(0,N-i))];
+ let(tri = _signed_pascals_triangle(N))
+ [for(i=[0:N]) concat(tri[N][i]*tri[i], repeat(0,N-i))];
// The bezier matrix, which is related to Pascal's triangle, enables nonrecursive computation
@@ -119,66 +119,66 @@ function _compute_bezier_matrix(N) =
// Not public.
_bezier_matrix_table = [
- [[1]],
- [[ 1, 0],
- [-1, 1]],
- [[1, 0, 0],
- [-2, 2, 0],
- [1, -2, 1]],
- [[ 1, 0, 0, 0],
- [-3, 3, 0, 0],
- [ 3,-6, 3, 0],
- [-1, 3,-3, 1]],
- [[ 1, 0, 0, 0, 0],
- [-4, 4, 0, 0, 0],
- [ 6,-12, 6, 0, 0],
- [-4, 12,-12, 4, 0],
- [ 1, -4, 6,-4, 1]],
- [[ 1, 0, 0, 0, 0, 0],
- [ -5, 5, 0, 0, 0, 0],
- [ 10,-20, 10, 0, 0, 0],
- [-10, 30,-30, 10, 0, 0],
- [ 5,-20, 30,-20, 5, 0],
- [ -1, 5,-10, 10,-5, 1]],
- [[ 1, 0, 0, 0, 0, 0, 0],
- [ -6, 6, 0, 0, 0, 0, 0],
- [ 15,-30, 15, 0, 0, 0, 0],
- [-20, 60,-60, 20, 0, 0, 0],
- [ 15,-60, 90,-60, 15, 0, 0],
- [ -6, 30,-60, 60,-30, 6, 0],
- [ 1, -6, 15,-20, 15,-6, 1]],
- [[ 1, 0, 0, 0, 0, 0, 0, 0],
- [ -7, 7, 0, 0, 0, 0, 0, 0],
- [ 21, -42, 21, 0, 0, 0, 0, 0],
- [-35, 105,-105, 35, 0, 0, 0, 0],
- [ 35,-140, 210,-140, 35, 0, 0, 0],
- [-21, 105,-210, 210,-105, 21, 0, 0],
- [ 7, -42, 105,-140, 105,-42, 7, 0],
- [ -1, 7, -21, 35, -35, 21,-7, 1]],
- [[ 1, 0, 0, 0, 0, 0, 0, 0, 0],
- [ -8, 8, 0, 0, 0, 0, 0, 0, 0],
- [ 28, -56, 28, 0, 0, 0, 0, 0, 0],
- [-56, 168,-168, 56, 0, 0, 0, 0, 0],
- [ 70,-280, 420,-280, 70, 0, 0, 0, 0],
- [-56, 280,-560, 560,-280, 56, 0, 0, 0],
- [ 28,-168, 420,-560, 420,-168, 28, 0, 0],
- [ -8, 56,-168, 280,-280, 168,-56, 8, 0],
- [ 1, -8, 28, -56, 70, -56, 28,-8, 1]],
- [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [-9, 9, 0, 0, 0, 0, 0, 0, 0, 0], [36, -72, 36, 0, 0, 0, 0, 0, 0, 0], [-84, 252, -252, 84, 0, 0, 0, 0, 0, 0],
- [126, -504, 756, -504, 126, 0, 0, 0, 0, 0], [-126, 630, -1260, 1260, -630, 126, 0, 0, 0, 0], [84, -504, 1260, -1680, 1260, -504, 84, 0, 0, 0],
- [-36, 252, -756, 1260, -1260, 756, -252, 36, 0, 0], [9, -72, 252, -504, 630, -504, 252, -72, 9, 0], [-1, 9, -36, 84, -126, 126, -84, 36, -9, 1]],
- [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [-10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0], [45, -90, 45, 0, 0, 0, 0, 0, 0, 0, 0], [-120, 360, -360, 120, 0, 0, 0, 0, 0, 0, 0],
- [210, -840, 1260, -840, 210, 0, 0, 0, 0, 0, 0], [-252, 1260, -2520, 2520, -1260, 252, 0, 0, 0, 0, 0],
- [210, -1260, 3150, -4200, 3150, -1260, 210, 0, 0, 0, 0], [-120, 840, -2520, 4200, -4200, 2520, -840, 120, 0, 0, 0],
- [45, -360, 1260, -2520, 3150, -2520, 1260, -360, 45, 0, 0], [-10, 90, -360, 840, -1260, 1260, -840, 360, -90, 10, 0],
- [1, -10, 45, -120, 210, -252, 210, -120, 45, -10, 1]]
+ [[1]],
+ [[ 1, 0],
+ [-1, 1]],
+ [[1, 0, 0],
+ [-2, 2, 0],
+ [1, -2, 1]],
+ [[ 1, 0, 0, 0],
+ [-3, 3, 0, 0],
+ [ 3,-6, 3, 0],
+ [-1, 3,-3, 1]],
+ [[ 1, 0, 0, 0, 0],
+ [-4, 4, 0, 0, 0],
+ [ 6,-12, 6, 0, 0],
+ [-4, 12,-12, 4, 0],
+ [ 1, -4, 6,-4, 1]],
+ [[ 1, 0, 0, 0, 0, 0],
+ [ -5, 5, 0, 0, 0, 0],
+ [ 10,-20, 10, 0, 0, 0],
+ [-10, 30,-30, 10, 0, 0],
+ [ 5,-20, 30,-20, 5, 0],
+ [ -1, 5,-10, 10,-5, 1]],
+ [[ 1, 0, 0, 0, 0, 0, 0],
+ [ -6, 6, 0, 0, 0, 0, 0],
+ [ 15,-30, 15, 0, 0, 0, 0],
+ [-20, 60,-60, 20, 0, 0, 0],
+ [ 15,-60, 90,-60, 15, 0, 0],
+ [ -6, 30,-60, 60,-30, 6, 0],
+ [ 1, -6, 15,-20, 15,-6, 1]],
+ [[ 1, 0, 0, 0, 0, 0, 0, 0],
+ [ -7, 7, 0, 0, 0, 0, 0, 0],
+ [ 21, -42, 21, 0, 0, 0, 0, 0],
+ [-35, 105,-105, 35, 0, 0, 0, 0],
+ [ 35,-140, 210,-140, 35, 0, 0, 0],
+ [-21, 105,-210, 210,-105, 21, 0, 0],
+ [ 7, -42, 105,-140, 105,-42, 7, 0],
+ [ -1, 7, -21, 35, -35, 21,-7, 1]],
+ [[ 1, 0, 0, 0, 0, 0, 0, 0, 0],
+ [ -8, 8, 0, 0, 0, 0, 0, 0, 0],
+ [ 28, -56, 28, 0, 0, 0, 0, 0, 0],
+ [-56, 168,-168, 56, 0, 0, 0, 0, 0],
+ [ 70,-280, 420,-280, 70, 0, 0, 0, 0],
+ [-56, 280,-560, 560,-280, 56, 0, 0, 0],
+ [ 28,-168, 420,-560, 420,-168, 28, 0, 0],
+ [ -8, 56,-168, 280,-280, 168,-56, 8, 0],
+ [ 1, -8, 28, -56, 70, -56, 28,-8, 1]],
+ [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [-9, 9, 0, 0, 0, 0, 0, 0, 0, 0], [36, -72, 36, 0, 0, 0, 0, 0, 0, 0], [-84, 252, -252, 84, 0, 0, 0, 0, 0, 0],
+ [126, -504, 756, -504, 126, 0, 0, 0, 0, 0], [-126, 630, -1260, 1260, -630, 126, 0, 0, 0, 0], [84, -504, 1260, -1680, 1260, -504, 84, 0, 0, 0],
+ [-36, 252, -756, 1260, -1260, 756, -252, 36, 0, 0], [9, -72, 252, -504, 630, -504, 252, -72, 9, 0], [-1, 9, -36, 84, -126, 126, -84, 36, -9, 1]],
+ [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [-10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0], [45, -90, 45, 0, 0, 0, 0, 0, 0, 0, 0], [-120, 360, -360, 120, 0, 0, 0, 0, 0, 0, 0],
+ [210, -840, 1260, -840, 210, 0, 0, 0, 0, 0, 0], [-252, 1260, -2520, 2520, -1260, 252, 0, 0, 0, 0, 0],
+ [210, -1260, 3150, -4200, 3150, -1260, 210, 0, 0, 0, 0], [-120, 840, -2520, 4200, -4200, 2520, -840, 120, 0, 0, 0],
+ [45, -360, 1260, -2520, 3150, -2520, 1260, -360, 45, 0, 0], [-10, 90, -360, 840, -1260, 1260, -840, 360, -90, 10, 0],
+ [1, -10, 45, -120, 210, -252, 210, -120, 45, -10, 1]]
];
// Not public.
function _bezier_matrix(N) =
- N>10 ? _compute_bezier_matrix(N) :
- _bezier_matrix_table[N];
+ N>10 ? _compute_bezier_matrix(N) :
+ _bezier_matrix_table[N];
// Function: bezier_derivative()
@@ -192,12 +192,12 @@ function _bezier_matrix(N) =
// u = The proportion of the way along the curve to find the derivative of. 0<=`u`<=1 If given as a list or range, returns a list of derivatives, one for each u value.
// order = The order of the derivative to return. Default: 1 (for the first derivative)
function bezier_derivative(curve, u, order=1) =
- assert(is_int(order) && order>=0)
- order==0? bezier_points(curve, u) : let(
- N = len(curve) - 1,
- dpts = N * deltas(curve)
- ) order==1? bezier_points(dpts, u) :
- bezier_derivative(dpts, u, order-1);
+ assert(is_int(order) && order>=0)
+ order==0? bezier_points(curve, u) : let(
+ N = len(curve) - 1,
+ dpts = N * deltas(curve)
+ ) order==1? bezier_points(dpts, u) :
+ bezier_derivative(dpts, u, order-1);
@@ -210,10 +210,10 @@ function bezier_derivative(curve, u, order=1) =
// curve = The list of endpoints and control points for this bezier segment.
// u = The proportion of the way along the curve to find the tangent vector of. 0<=`u`<=1 If given as a list or range, returns a list of tangent vectors, one for each u value.
function bezier_tangent(curve, u) =
- let(
- res = bezier_derivative(curve, u)
- ) is_vector(res)? unit(res) :
- [for (v=res) unit(v)];
+ let(
+ res = bezier_derivative(curve, u)
+ ) is_vector(res)? unit(res) :
+ [for (v=res) unit(v)];
@@ -229,17 +229,17 @@ function bezier_tangent(curve, u) =
// curve = The list of endpoints and control points for this bezier segment.
// u = The proportion of the way along the curve to find the curvature of. 0<=`u`<=1 If given as a list or range, returns a list of curvature values, one for each u value.
function bezier_curvature(curve, u) =
- is_num(u) ? bezier_curvature(curve,[u])[0] :
- let(
- d1 = bezier_derivative(curve, u, 1),
- d2 = bezier_derivative(curve, u, 2)
- ) [
- for(i=idx(d1))
- sqrt(
- sqr(norm(d1[i])*norm(d2[i])) -
- sqr(d1[i]*d2[i])
- ) / pow(norm(d1[i]),3)
- ];
+ is_num(u) ? bezier_curvature(curve,[u])[0] :
+ let(
+ d1 = bezier_derivative(curve, u, 1),
+ d2 = bezier_derivative(curve, u, 2)
+ ) [
+ for(i=idx(d1))
+ sqrt(
+ sqr(norm(d1[i])*norm(d2[i])) -
+ sqr(d1[i]*d2[i])
+ ) / pow(norm(d1[i]),3)
+ ];
@@ -289,32 +289,32 @@ function bezier_curve(curve,n) = bezier_points(curve, [0:1/n:(n-0.5)/n]);
// color("red") translate(pt) sphere(r=1);
// color("blue") translate(bezier_points(bez,u)) sphere(r=1);
function bezier_segment_closest_point(curve, pt, max_err=0.01, u=0, end_u=1) =
- let(
- steps = len(curve)*3,
- uvals = [u, for (i=[0:1:steps]) (end_u-u)*(i/steps)+u, end_u],
- path = bezier_points(curve,uvals),
- minima_ranges = [
- for (i = [1:1:len(uvals)-2]) let(
- d1 = norm(path[i-1]-pt),
- d2 = norm(path[i ]-pt),
- d3 = norm(path[i+1]-pt)
- ) if (d2<=d1 && d2<=d3) [uvals[i-1],uvals[i+1]]
- ]
- ) len(minima_ranges)>1? (
- let(
- min_us = [
- for (minima = minima_ranges)
- bezier_segment_closest_point(curve, pt, max_err=max_err, u=minima.x, end_u=minima.y)
- ],
- dists = [for (v=min_us) norm(bezier_points(curve,v)-pt)],
- min_i = min_index(dists)
- ) min_us[min_i]
- ) : let(
- minima = minima_ranges[0],
- pp = bezier_points(curve, minima),
- err = norm(pp[1]-pp[0])
- ) err1? (
+ let(
+ min_us = [
+ for (minima = minima_ranges)
+ bezier_segment_closest_point(curve, pt, max_err=max_err, u=minima.x, end_u=minima.y)
+ ],
+ dists = [for (v=min_us) norm(bezier_points(curve,v)-pt)],
+ min_i = min_index(dists)
+ ) min_us[min_i]
+ ) : let(
+ minima = minima_ranges[0],
+ pp = bezier_points(curve, minima),
+ err = norm(pp[1]-pp[0])
+ ) err= len(path))? (
- let(curve = select(path, min_seg*N, (min_seg+1)*N))
- [min_seg, bezier_segment_closest_point(curve, pt, max_err=max_err)]
- ) : (
- let(
- curve = select(path,seg*N,(seg+1)*N),
- u = bezier_segment_closest_point(curve, pt, max_err=0.05),
- dist = norm(bezier_points(curve, u)-pt),
- mseg = (min_dist==undef || dist= len(path))? (
+ let(curve = select(path, min_seg*N, (min_seg+1)*N))
+ [min_seg, bezier_segment_closest_point(curve, pt, max_err=max_err)]
+ ) : (
+ let(
+ curve = select(path,seg*N,(seg+1)*N),
+ u = bezier_segment_closest_point(curve, pt, max_err=0.05),
+ dist = norm(bezier_points(curve, u)-pt),
+ mseg = (min_dist==undef || dist= len(patches))? vnf :
- bezier_patch(patches[i], splinesteps=splinesteps, vnf=vnf, style=style)
- ) (i >= len(patches))? vnf :
- bezier_surface(patches=patches, splinesteps=splinesteps, vnf=vnf, style=style, i=i+1);
+ let(
+ vnf = (i >= len(patches))? vnf :
+ bezier_patch(patches[i], splinesteps=splinesteps, vnf=vnf, style=style)
+ ) (i >= len(patches))? vnf :
+ bezier_surface(patches=patches, splinesteps=splinesteps, vnf=vnf, style=style, i=i+1);
@@ -1217,10 +1217,10 @@ function bezier_surface(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="defaul
// bezier_polyhedron([patch1, patch2], splinesteps=8);
module bezier_polyhedron(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="default", convexity=10)
{
- vnf_polyhedron(
- bezier_surface(patches=patches, splinesteps=splinesteps, vnf=vnf, style=style),
- convexity=convexity
- );
+ vnf_polyhedron(
+ bezier_surface(patches=patches, splinesteps=splinesteps, vnf=vnf, style=style),
+ convexity=convexity
+ );
}
@@ -1263,33 +1263,33 @@ module trace_bezier_patches(patches=[], size, splinesteps=16, showcps=true, show
assert(is_bool(showpatch));
assert(is_int(convexity) && convexity>0);
for (patch = patches) {
- size = is_num(size)? size :
- let( bounds = pointlist_bounds(flatten(patch)) )
- max(bounds[1]-bounds[0])*0.01;
- if (showcps) {
- move_copies(flatten(patch)) color("red") sphere(d=size*2);
- color("cyan") {
- if (is_tripatch(patch)) {
- for (i=[0:1:len(patch)-2], j=[0:1:len(patch[i])-2]) {
- extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size);
- extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
- extrude_from_to(patch[i+1][j], patch[i][j+1]) circle(d=size);
- }
- } else {
- for (i=[0:1:len(patch)-1], j=[0:1:len(patch[i])-1]) {
- if (i
// pco1810_neck();
module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
{
- inner_d = 21.74;
- neck_d = 26.19;
- neck_h = 5.00;
- support_d = 33.00;
- support_width = 1.45;
- support_rad = 0.40;
- support_h = 21.00;
- support_ang = 16;
- tamper_ring_d = 27.97;
- tamper_ring_width = 0.50;
- tamper_ring_r = 1.60;
- tamper_base_d = 25.71;
- tamper_base_h = 14.10;
- threadbase_d = 24.51;
- thread_pitch = 3.18;
- thread_angle = 20;
- thread_od = 27.43;
- lip_d = 25.07;
- lip_h = 1.70;
- lip_leadin_r = 0.20;
- lip_recess_d = 24.94;
- lip_recess_h = 1.00;
- lip_roundover_r = 0.58;
+ inner_d = 21.74;
+ neck_d = 26.19;
+ neck_h = 5.00;
+ support_d = 33.00;
+ support_width = 1.45;
+ support_rad = 0.40;
+ support_h = 21.00;
+ support_ang = 16;
+ tamper_ring_d = 27.97;
+ tamper_ring_width = 0.50;
+ tamper_ring_r = 1.60;
+ tamper_base_d = 25.71;
+ tamper_base_h = 14.10;
+ threadbase_d = 24.51;
+ thread_pitch = 3.18;
+ thread_angle = 20;
+ thread_od = 27.43;
+ lip_d = 25.07;
+ lip_h = 1.70;
+ lip_leadin_r = 0.20;
+ lip_recess_d = 24.94;
+ lip_recess_h = 1.00;
+ lip_roundover_r = 0.58;
- $fn = segs(support_d/2);
- h = support_h+neck_h;
- thread_h = (thread_od-threadbase_d)/2;
- anchors = [
- anchorpt("support-ring", [0,0,neck_h-h/2]),
- anchorpt("tamper-ring", [0,0,h/2-tamper_base_h])
- ];
- attachable(anchor,spin,orient, d=support_d, l=h, anchors=anchors) {
- down(h/2) {
- rotate_extrude(convexity=10) {
- polygon(turtle(
- state=[inner_d/2,0], [
- "untilx", neck_d/2,
- "left", 90,
- "move", neck_h - 1,
- "arcright", 1, 90,
- "untilx", support_d/2-support_rad,
- "arcleft", support_rad, 90,
- "move", support_width,
- "arcleft", support_rad, 90-support_ang,
- "untilx", tamper_base_d/2,
- "right", 90-support_ang,
- "untily", h-tamper_base_h, // Tamper ring holder base.
- "right", 90,
- "untilx", tamper_ring_d/2,
- "left", 90,
- "move", tamper_ring_width,
- "arcleft", tamper_ring_r, 90,
- "untilx", threadbase_d/2,
- "right", 90,
- "untily", h-lip_h-lip_leadin_r, // Lip base.
- "arcright", lip_leadin_r, 90,
- "untilx", lip_d/2,
- "left", 90,
- "untily", h-lip_recess_h,
- "left", 90,
- "untilx", lip_recess_d/2,
- "right", 90,
- "untily", h-lip_roundover_r,
- "arcleft", lip_roundover_r, 90,
- "untilx", inner_d/2
- ]
- ));
- }
- up(h-lip_h) {
- bottom_half() {
- difference() {
- thread_helix(
- base_d=threadbase_d-0.1,
- pitch=thread_pitch,
- thread_depth=thread_h+0.1,
- thread_angle=thread_angle,
- twist=810,
- higbee=75,
- anchor=TOP
- );
- zrot_copies(rots=[90,270]) {
- zrot_copies(rots=[-28,28], r=threadbase_d/2) {
- prismoid([20,1.82], [20,1.82+2*sin(29)*thread_h], h=thread_h+0.1, anchor=BOT, orient=RIGHT);
- }
- }
- }
- }
- }
- }
- children();
- }
+ $fn = segs(support_d/2);
+ h = support_h+neck_h;
+ thread_h = (thread_od-threadbase_d)/2;
+ anchors = [
+ anchorpt("support-ring", [0,0,neck_h-h/2]),
+ anchorpt("tamper-ring", [0,0,h/2-tamper_base_h])
+ ];
+ attachable(anchor,spin,orient, d=support_d, l=h, anchors=anchors) {
+ down(h/2) {
+ rotate_extrude(convexity=10) {
+ polygon(turtle(
+ state=[inner_d/2,0], [
+ "untilx", neck_d/2,
+ "left", 90,
+ "move", neck_h - 1,
+ "arcright", 1, 90,
+ "untilx", support_d/2-support_rad,
+ "arcleft", support_rad, 90,
+ "move", support_width,
+ "arcleft", support_rad, 90-support_ang,
+ "untilx", tamper_base_d/2,
+ "right", 90-support_ang,
+ "untily", h-tamper_base_h, // Tamper ring holder base.
+ "right", 90,
+ "untilx", tamper_ring_d/2,
+ "left", 90,
+ "move", tamper_ring_width,
+ "arcleft", tamper_ring_r, 90,
+ "untilx", threadbase_d/2,
+ "right", 90,
+ "untily", h-lip_h-lip_leadin_r, // Lip base.
+ "arcright", lip_leadin_r, 90,
+ "untilx", lip_d/2,
+ "left", 90,
+ "untily", h-lip_recess_h,
+ "left", 90,
+ "untilx", lip_recess_d/2,
+ "right", 90,
+ "untily", h-lip_roundover_r,
+ "arcleft", lip_roundover_r, 90,
+ "untilx", inner_d/2
+ ]
+ ));
+ }
+ up(h-lip_h) {
+ bottom_half() {
+ difference() {
+ thread_helix(
+ base_d=threadbase_d-0.1,
+ pitch=thread_pitch,
+ thread_depth=thread_h+0.1,
+ thread_angle=thread_angle,
+ twist=810,
+ higbee=75,
+ anchor=TOP
+ );
+ zrot_copies(rots=[90,270]) {
+ zrot_copies(rots=[-28,28], r=threadbase_d/2) {
+ prismoid([20,1.82], [20,1.82+2*sin(29)*thread_h], h=thread_h+0.1, anchor=BOT, orient=RIGHT);
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -146,41 +146,41 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
// pco1810_cap(texture="ribbed");
module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
{
- cap_id = 28.58;
- tamper_ring_h = 14.10;
- thread_pitch = 3.18;
- thread_angle = 20;
- thread_od = cap_id;
- thread_depth = 1.6;
+ cap_id = 28.58;
+ tamper_ring_h = 14.10;
+ thread_pitch = 3.18;
+ thread_angle = 20;
+ thread_od = cap_id;
+ thread_depth = 1.6;
- $fn = segs(33/2);
- w = cap_id + 2*wall;
- h = tamper_ring_h + wall;
- anchors = [
- anchorpt("inside-top", [0,0,-(h/2-wall)])
- ];
- attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
- down(h/2) zrot(45) {
- difference() {
- union() {
- if (texture == "knurled") {
- knurled_cylinder(d=w, helix=45, l=tamper_ring_h+wall, anchor=BOTTOM);
- cyl(d=w-1.5, l=tamper_ring_h+wall, anchor=BOTTOM);
- } else if (texture == "ribbed") {
- zrot_copies(n=30, r=(w-1)/2) {
- cube([1, 1, tamper_ring_h+wall], anchor=BOTTOM);
- }
- cyl(d=w-1, l=tamper_ring_h+wall, anchor=BOTTOM);
- } else {
- cyl(d=w, l=tamper_ring_h+wall, anchor=BOTTOM);
- }
- }
- up(wall) cyl(d=cap_id, h=tamper_ring_h+wall, anchor=BOTTOM);
- }
- up(wall+2) thread_helix(base_d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, thread_angle=thread_angle, twist=810, higbee=45, internal=true, anchor=BOTTOM);
- }
- children();
- }
+ $fn = segs(33/2);
+ w = cap_id + 2*wall;
+ h = tamper_ring_h + wall;
+ anchors = [
+ anchorpt("inside-top", [0,0,-(h/2-wall)])
+ ];
+ attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
+ down(h/2) zrot(45) {
+ difference() {
+ union() {
+ if (texture == "knurled") {
+ knurled_cylinder(d=w, helix=45, l=tamper_ring_h+wall, anchor=BOTTOM);
+ cyl(d=w-1.5, l=tamper_ring_h+wall, anchor=BOTTOM);
+ } else if (texture == "ribbed") {
+ zrot_copies(n=30, r=(w-1)/2) {
+ cube([1, 1, tamper_ring_h+wall], anchor=BOTTOM);
+ }
+ cyl(d=w-1, l=tamper_ring_h+wall, anchor=BOTTOM);
+ } else {
+ cyl(d=w, l=tamper_ring_h+wall, anchor=BOTTOM);
+ }
+ }
+ up(wall) cyl(d=cap_id, h=tamper_ring_h+wall, anchor=BOTTOM);
+ }
+ up(wall+2) thread_helix(base_d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, thread_angle=thread_angle, twist=810, higbee=45, internal=true, anchor=BOTTOM);
+ }
+ children();
+ }
}
@@ -204,97 +204,97 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
// pco1881_neck();
module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
{
- inner_d = 21.74;
- neck_d = 26.19;
- neck_h = 5.00;
- support_d = 33.00;
- support_width = 0.58;
- support_rad = 0.30;
- support_h = 17.00;
- support_ang = 15;
- tamper_ring_d = 28.00;
- tamper_ring_width = 0.30;
- tamper_ring_ang = 45;
- tamper_base_d = 25.71;
- tamper_base_h = 11.20;
- tamper_divot_r = 1.08;
- threadbase_d = 24.20;
- thread_pitch = 2.70;
- thread_angle = 15;
- thread_od = 27.4;
- lip_d = 25.07;
- lip_h = 1.70;
- lip_leadin_r = 0.30;
- lip_recess_d = 24.94;
- lip_recess_h = 1.00;
- lip_roundover_r = 0.58;
+ inner_d = 21.74;
+ neck_d = 26.19;
+ neck_h = 5.00;
+ support_d = 33.00;
+ support_width = 0.58;
+ support_rad = 0.30;
+ support_h = 17.00;
+ support_ang = 15;
+ tamper_ring_d = 28.00;
+ tamper_ring_width = 0.30;
+ tamper_ring_ang = 45;
+ tamper_base_d = 25.71;
+ tamper_base_h = 11.20;
+ tamper_divot_r = 1.08;
+ threadbase_d = 24.20;
+ thread_pitch = 2.70;
+ thread_angle = 15;
+ thread_od = 27.4;
+ lip_d = 25.07;
+ lip_h = 1.70;
+ lip_leadin_r = 0.30;
+ lip_recess_d = 24.94;
+ lip_recess_h = 1.00;
+ lip_roundover_r = 0.58;
- $fn = segs(support_d/2);
- h = support_h+neck_h;
- thread_h = (thread_od-threadbase_d)/2;
- anchors = [
- anchorpt("support-ring", [0,0,neck_h-h/2]),
- anchorpt("tamper-ring", [0,0,h/2-tamper_base_h])
- ];
- attachable(anchor,spin,orient, d=support_d, l=h, anchors=anchors) {
- down(h/2) {
- rotate_extrude(convexity=10) {
- polygon(turtle(
- state=[inner_d/2,0], [
- "untilx", neck_d/2,
- "left", 90,
- "move", neck_h - 1,
- "arcright", 1, 90,
- "untilx", support_d/2-support_rad,
- "arcleft", support_rad, 90,
- "move", support_width,
- "arcleft", support_rad, 90-support_ang,
- "untilx", tamper_base_d/2,
- "arcright", tamper_divot_r, 180-support_ang*2,
- "left", 90-support_ang,
- "untily", h-tamper_base_h, // Tamper ring holder base.
- "right", 90,
- "untilx", tamper_ring_d/2,
- "left", 90,
- "move", tamper_ring_width,
- "left", tamper_ring_ang,
- "untilx", threadbase_d/2,
- "right", tamper_ring_ang,
- "untily", h-lip_h-lip_leadin_r, // Lip base.
- "arcright", lip_leadin_r, 90,
- "untilx", lip_d/2,
- "left", 90,
- "untily", h-lip_recess_h,
- "left", 90,
- "untilx", lip_recess_d/2,
- "right", 90,
- "untily", h-lip_roundover_r,
- "arcleft", lip_roundover_r, 90,
- "untilx", inner_d/2
- ]
- ));
- }
- up(h-lip_h) {
- difference() {
- thread_helix(
- base_d=threadbase_d-0.1,
- pitch=thread_pitch,
- thread_depth=thread_h+0.1,
- thread_angle=thread_angle,
- twist=650,
- higbee=75,
- anchor=TOP
- );
- zrot_copies(rots=[90,270]) {
- zrot_copies(rots=[-28,28], r=threadbase_d/2) {
- prismoid([20,1.82], [20,1.82+2*sin(29)*thread_h], h=thread_h+0.1, anchor=BOT, orient=RIGHT);
- }
- }
- }
- }
- }
- children();
- }
+ $fn = segs(support_d/2);
+ h = support_h+neck_h;
+ thread_h = (thread_od-threadbase_d)/2;
+ anchors = [
+ anchorpt("support-ring", [0,0,neck_h-h/2]),
+ anchorpt("tamper-ring", [0,0,h/2-tamper_base_h])
+ ];
+ attachable(anchor,spin,orient, d=support_d, l=h, anchors=anchors) {
+ down(h/2) {
+ rotate_extrude(convexity=10) {
+ polygon(turtle(
+ state=[inner_d/2,0], [
+ "untilx", neck_d/2,
+ "left", 90,
+ "move", neck_h - 1,
+ "arcright", 1, 90,
+ "untilx", support_d/2-support_rad,
+ "arcleft", support_rad, 90,
+ "move", support_width,
+ "arcleft", support_rad, 90-support_ang,
+ "untilx", tamper_base_d/2,
+ "arcright", tamper_divot_r, 180-support_ang*2,
+ "left", 90-support_ang,
+ "untily", h-tamper_base_h, // Tamper ring holder base.
+ "right", 90,
+ "untilx", tamper_ring_d/2,
+ "left", 90,
+ "move", tamper_ring_width,
+ "left", tamper_ring_ang,
+ "untilx", threadbase_d/2,
+ "right", tamper_ring_ang,
+ "untily", h-lip_h-lip_leadin_r, // Lip base.
+ "arcright", lip_leadin_r, 90,
+ "untilx", lip_d/2,
+ "left", 90,
+ "untily", h-lip_recess_h,
+ "left", 90,
+ "untilx", lip_recess_d/2,
+ "right", 90,
+ "untily", h-lip_roundover_r,
+ "arcleft", lip_roundover_r, 90,
+ "untilx", inner_d/2
+ ]
+ ));
+ }
+ up(h-lip_h) {
+ difference() {
+ thread_helix(
+ base_d=threadbase_d-0.1,
+ pitch=thread_pitch,
+ thread_depth=thread_h+0.1,
+ thread_angle=thread_angle,
+ twist=650,
+ higbee=75,
+ anchor=TOP
+ );
+ zrot_copies(rots=[90,270]) {
+ zrot_copies(rots=[-28,28], r=threadbase_d/2) {
+ prismoid([20,1.82], [20,1.82+2*sin(29)*thread_h], h=thread_h+0.1, anchor=BOT, orient=RIGHT);
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -317,36 +317,36 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
// pco1881_cap(texture="ribbed");
module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
{
- $fn = segs(33/2);
- w = 28.58 + 2*wall;
- h = 11.2 + wall;
- anchors = [
- anchorpt("inside-top", [0,0,-(h/2-wall)])
- ];
- attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
- down(h/2) zrot(45) {
- difference() {
- union() {
- if (texture == "knurled") {
- knurled_cylinder(d=w, helix=45, l=11.2+wall, anchor=BOTTOM);
- cyl(d=w-1.5, l=11.2+wall, anchor=BOTTOM);
- } else if (texture == "ribbed") {
- zrot_copies(n=30, r=(w-1)/2) {
- cube([1, 1, 11.2+wall], anchor=BOTTOM);
- }
- cyl(d=w-1, l=11.2+wall, anchor=BOTTOM);
- } else {
- cyl(d=w, l=11.2+wall, anchor=BOTTOM);
- }
- }
- up(wall) cyl(d=28.58, h=11.2+wall, anchor=BOTTOM);
- }
- up(wall+2) thread_helix(base_d=25.5, pitch=2.7, thread_depth=1.6, thread_angle=15, twist=650, higbee=45, internal=true, anchor=BOTTOM);
- }
- children();
- }
+ $fn = segs(33/2);
+ w = 28.58 + 2*wall;
+ h = 11.2 + wall;
+ anchors = [
+ anchorpt("inside-top", [0,0,-(h/2-wall)])
+ ];
+ attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
+ down(h/2) zrot(45) {
+ difference() {
+ union() {
+ if (texture == "knurled") {
+ knurled_cylinder(d=w, helix=45, l=11.2+wall, anchor=BOTTOM);
+ cyl(d=w-1.5, l=11.2+wall, anchor=BOTTOM);
+ } else if (texture == "ribbed") {
+ zrot_copies(n=30, r=(w-1)/2) {
+ cube([1, 1, 11.2+wall], anchor=BOTTOM);
+ }
+ cyl(d=w-1, l=11.2+wall, anchor=BOTTOM);
+ } else {
+ cyl(d=w, l=11.2+wall, anchor=BOTTOM);
+ }
+ }
+ up(wall) cyl(d=28.58, h=11.2+wall, anchor=BOTTOM);
+ }
+ up(wall+2) thread_helix(base_d=25.5, pitch=2.7, thread_depth=1.6, thread_angle=15, twist=650, higbee=45, internal=true, anchor=BOTTOM);
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/common.scad b/common.scad
index 31d5811..11b117c 100644
--- a/common.scad
+++ b/common.scad
@@ -17,12 +17,12 @@
// Description:
// Returns a string representing the type of the value. One of "undef", "boolean", "number", "string", "list", or "range"
function typeof(x) =
- is_undef(x)? "undef" :
- is_bool(x)? "boolean" :
- is_num(x)? "number" :
- is_string(x)? "string" :
- is_list(x)? "list" :
- "range";
+ is_undef(x)? "undef" :
+ is_bool(x)? "boolean" :
+ is_num(x)? "number" :
+ is_string(x)? "string" :
+ is_list(x)? "list" :
+ "range";
// Function: is_type()
@@ -43,9 +43,9 @@ function typeof(x) =
// is_str3 = is_type(["foo"], "string"); // Returns: false
// is_str4 = is_type(3, "string"); // Returns: false
function is_type(x,types) =
- is_list(types)? in_list(typeof(x),types) :
- is_string(types)? typeof(x) == types :
- assert(is_list(types)||is_string(types));
+ is_list(types)? in_list(typeof(x),types) :
+ is_string(types)? typeof(x) == types :
+ assert(is_list(types)||is_string(types));
// Function: is_def()
@@ -100,9 +100,9 @@ function is_range(x) = is_num(x[0]) && !is_list(x);
// is_list_of([[1,[3,4]], [4,[5,6]]], [1,[2,3]]); // Returne true
// is_list_of([[1,[3,INF]], [4,[5,6]]], [1,[2,3]]); // Returne false
function is_list_of(list,pattern) =
- let(pattern = 0*pattern)
- is_list(list) &&
- []==[for(entry=list) if (entry*0 != pattern) entry];
+ let(pattern = 0*pattern)
+ is_list(list) &&
+ []==[for(entry=list) if (entry*0 != pattern) entry];
// Function: is_consistent()
@@ -153,13 +153,13 @@ function default(v,dflt=undef) = is_undef(v)? dflt : v;
// v = The list whose items are being checked.
// recursive = If true, sublists are checked recursively for defined values. The first sublist that has a defined item is returned.
function first_defined(v,recursive=false,_i=0) =
- _i0? ($fn>3? $fn : 3) :
- ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs)));
+ $fn>0? ($fn>3? $fn : 3) :
+ ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs)));
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/constants.scad b/constants.scad
index 4be92c3..ed5bd80 100644
--- a/constants.scad
+++ b/constants.scad
@@ -118,4 +118,4 @@ FORWARD = FRONT; // Vector pointing forward, alias to `FRONT`.
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/coords.scad b/coords.scad
index 19f3406..97729be 100644
--- a/coords.scad
+++ b/coords.scad
@@ -30,10 +30,10 @@ function point2d(p, fill=0) = [for (i=[0:1]) (p[i]==undef)? fill : p[i]];
// points = A list of 2D or 3D points/vectors.
// fill = Value to fill missing values in vectors with.
function path2d(points) =
- assert(is_path(points,dim=undef,fast=true),"Input to path2d is not a path")
- let (result = points * concat(ident(2), repeat([0,0], len(points[0])-2)))
- assert(is_def(result), "Invalid input to path2d")
- result;
+ assert(is_path(points,dim=undef,fast=true),"Input to path2d is not a path")
+ let (result = points * concat(ident(2), repeat([0,0], len(points[0])-2)))
+ assert(is_def(result), "Invalid input to path2d")
+ result;
// Function: point3d()
@@ -53,16 +53,16 @@ function point3d(p, fill=0) = [for (i=[0:2]) (p[i]==undef)? fill : p[i]];
// points = A list of 2D, 3D or higher dimensional points/vectors.
// fill = Value to fill missing values in vectors with (in the 2D case)
function path3d(points, fill=0) =
- assert(is_num(fill))
- assert(is_path(points, dim=undef, fast=true), "Input to path3d is not a path")
- let (
- change = len(points[0])-3,
- M = change < 0? [[1,0,0],[0,1,0]] :
- concat(ident(3), repeat([0,0,0],change)),
- result = points*M
- )
- assert(is_def(result), "Input to path3d is invalid")
- fill == 0 || change>=0 ? result : result + repeat([0,0,fill], len(result));
+ assert(is_num(fill))
+ assert(is_path(points, dim=undef, fast=true), "Input to path3d is not a path")
+ let (
+ change = len(points[0])-3,
+ M = change < 0? [[1,0,0],[0,1,0]] :
+ concat(ident(3), repeat([0,0,0],change)),
+ result = points*M
+ )
+ assert(is_def(result), "Input to path3d is invalid")
+ fill == 0 || change>=0 ? result : result + repeat([0,0,fill], len(result));
// Function: point4d()
@@ -118,9 +118,9 @@ function path4d(points, fill=0) =
// xy = polar_to_xy(40,30); // Returns: ~[34.6410162, 15]
// xy = polar_to_xy([40,30]); // Returns: ~[34.6410162, 15]
function polar_to_xy(r,theta=undef) = let(
- rad = theta==undef? r[0] : r,
- t = theta==undef? r[1] : theta
- ) rad*[cos(t), sin(t)];
+ rad = theta==undef? r[0] : r,
+ t = theta==undef? r[1] : theta
+ ) rad*[cos(t), sin(t)];
// Function: xy_to_polar()
@@ -137,9 +137,9 @@ function polar_to_xy(r,theta=undef) = let(
// plr = xy_to_polar(20,30);
// plr = xy_to_polar([40,60]);
function xy_to_polar(x,y=undef) = let(
- xx = y==undef? x[0] : x,
- yy = y==undef? x[1] : y
- ) [norm([xx,yy]), atan2(yy,xx)];
+ xx = y==undef? x[0] : x,
+ yy = y==undef? x[1] : y
+ ) [norm([xx,yy]), atan2(yy,xx)];
// Function: project_plane()
@@ -169,26 +169,26 @@ function xy_to_polar(x,y=undef) = let(
// xy = project_plane(pt, a, b, c);
// xy2 = project_plane(pt, [a,b,c]);
function project_plane(point, a, b, c) =
- is_undef(b) && is_undef(c) && is_list(a)? let(
- mat = is_vector(a,4)? plane_transform(a) :
- assert(is_path(a) && len(a)>=3)
- plane_transform(plane_from_points(a)),
- pts = is_vector(point)? point2d(apply(mat,point)) :
- is_path(point)? path2d(apply(mat,point)) :
- is_region(point)? [for (x=point) path2d(apply(mat,x))] :
- assert(false, "point must be a 3D point, path, or region.")
- ) pts :
- assert(is_vector(a))
- assert(is_vector(b))
- assert(is_vector(c))
- assert(is_vector(point)||is_path(point))
- let(
- u = unit(b-a),
- v = unit(c-a),
- n = unit(cross(u,v)),
- w = unit(cross(n,u)),
- relpoint = apply(move(-a),point)
- ) relpoint * transpose([w,u]);
+ is_undef(b) && is_undef(c) && is_list(a)? let(
+ mat = is_vector(a,4)? plane_transform(a) :
+ assert(is_path(a) && len(a)>=3)
+ plane_transform(plane_from_points(a)),
+ pts = is_vector(point)? point2d(apply(mat,point)) :
+ is_path(point)? path2d(apply(mat,point)) :
+ is_region(point)? [for (x=point) path2d(apply(mat,x))] :
+ assert(false, "point must be a 3D point, path, or region.")
+ ) pts :
+ assert(is_vector(a))
+ assert(is_vector(b))
+ assert(is_vector(c))
+ assert(is_vector(point)||is_path(point))
+ let(
+ u = unit(b-a),
+ v = unit(c-a),
+ n = unit(cross(u,v)),
+ w = unit(cross(n,u)),
+ relpoint = apply(move(-a),point)
+ ) relpoint * transpose([w,u]);
// Function: lift_plane()
@@ -210,27 +210,27 @@ function project_plane(point, a, b, c) =
// b = A 3D point that the plane passes through. Used to define the plane.
// c = A 3D point that the plane passes through. Used to define the plane.
function lift_plane(point, a, b, c) =
- is_undef(b) && is_undef(c) && is_list(a)? let(
- mat = is_vector(a,4)? plane_transform(a) :
- assert(is_path(a) && len(a)>=3)
- plane_transform(plane_from_points(a)),
- imat = matrix_inverse(mat),
- pts = is_vector(point)? apply(imat,point3d(point)) :
- is_path(point)? apply(imat,path3d(point)) :
- is_region(point)? [for (x=point) apply(imat,path3d(x))] :
- assert(false, "point must be a 2D point, path, or region.")
- ) pts :
- assert(is_vector(a))
- assert(is_vector(b))
- assert(is_vector(c))
- assert(is_vector(point)||is_path(point))
- let(
- u = unit(b-a),
- v = unit(c-a),
- n = unit(cross(u,v)),
- w = unit(cross(n,u)),
- remapped = point*[w,u]
- ) apply(move(a),remapped);
+ is_undef(b) && is_undef(c) && is_list(a)? let(
+ mat = is_vector(a,4)? plane_transform(a) :
+ assert(is_path(a) && len(a)>=3)
+ plane_transform(plane_from_points(a)),
+ imat = matrix_inverse(mat),
+ pts = is_vector(point)? apply(imat,point3d(point)) :
+ is_path(point)? apply(imat,path3d(point)) :
+ is_region(point)? [for (x=point) apply(imat,path3d(x))] :
+ assert(false, "point must be a 2D point, path, or region.")
+ ) pts :
+ assert(is_vector(a))
+ assert(is_vector(b))
+ assert(is_vector(c))
+ assert(is_vector(point)||is_path(point))
+ let(
+ u = unit(b-a),
+ v = unit(c-a),
+ n = unit(cross(u,v)),
+ w = unit(cross(n,u)),
+ remapped = point*[w,u]
+ ) apply(move(a),remapped);
// Function: cylindrical_to_xyz()
@@ -247,10 +247,10 @@ function lift_plane(point, a, b, c) =
// xyz = cylindrical_to_xyz(20,30,40);
// xyz = cylindrical_to_xyz([40,60,50]);
function cylindrical_to_xyz(r,theta=undef,z=undef) = let(
- rad = theta==undef? r[0] : r,
- t = theta==undef? r[1] : theta,
- zed = theta==undef? r[2] : z
- ) [rad*cos(t), rad*sin(t), zed];
+ rad = theta==undef? r[0] : r,
+ t = theta==undef? r[1] : theta,
+ zed = theta==undef? r[2] : z
+ ) [rad*cos(t), rad*sin(t), zed];
// Function: xyz_to_cylindrical()
@@ -269,8 +269,8 @@ function cylindrical_to_xyz(r,theta=undef,z=undef) = let(
// cyl = xyz_to_cylindrical(20,30,40);
// cyl = xyz_to_cylindrical([40,50,70]);
function xyz_to_cylindrical(x,y=undef,z=undef) = let(
- p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
- ) [norm([p.x,p.y]), atan2(p.y,p.x), p.z];
+ p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
+ ) [norm([p.x,p.y]), atan2(p.y,p.x), p.z];
// Function: spherical_to_xyz()
@@ -288,10 +288,10 @@ function xyz_to_cylindrical(x,y=undef,z=undef) = let(
// xyz = spherical_to_xyz(20,30,40);
// xyz = spherical_to_xyz([40,60,50]);
function spherical_to_xyz(r,theta=undef,phi=undef) = let(
- rad = theta==undef? r[0] : r,
- t = theta==undef? r[1] : theta,
- p = theta==undef? r[2] : phi
- ) rad*[sin(p)*cos(t), sin(p)*sin(t), cos(p)];
+ rad = theta==undef? r[0] : r,
+ t = theta==undef? r[1] : theta,
+ p = theta==undef? r[2] : phi
+ ) rad*[sin(p)*cos(t), sin(p)*sin(t), cos(p)];
// Function: xyz_to_spherical()
@@ -310,8 +310,8 @@ function spherical_to_xyz(r,theta=undef,phi=undef) = let(
// sph = xyz_to_spherical(20,30,40);
// sph = xyz_to_spherical([40,50,70]);
function xyz_to_spherical(x,y=undef,z=undef) = let(
- p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
- ) [norm(p), atan2(p.y,p.x), atan2(norm([p.x,p.y]),p.z)];
+ p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
+ ) [norm(p), atan2(p.y,p.x), atan2(norm([p.x,p.y]),p.z)];
// Function: altaz_to_xyz()
@@ -329,10 +329,10 @@ function xyz_to_spherical(x,y=undef,z=undef) = let(
// xyz = altaz_to_xyz(20,30,40);
// xyz = altaz_to_xyz([40,60,50]);
function altaz_to_xyz(alt,az=undef,r=undef) = let(
- p = az==undef? alt[0] : alt,
- t = 90 - (az==undef? alt[1] : az),
- rad = az==undef? alt[2] : r
- ) rad*[cos(p)*cos(t), cos(p)*sin(t), sin(p)];
+ p = az==undef? alt[0] : alt,
+ t = 90 - (az==undef? alt[1] : az),
+ rad = az==undef? alt[2] : r
+ ) rad*[cos(p)*cos(t), cos(p)*sin(t), sin(p)];
// Function: xyz_to_altaz()
@@ -352,9 +352,9 @@ function altaz_to_xyz(alt,az=undef,r=undef) = let(
// aa = xyz_to_altaz(20,30,40);
// aa = xyz_to_altaz([40,50,70]);
function xyz_to_altaz(x,y=undef,z=undef) = let(
- p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
- ) [atan2(p.z,norm([p.x,p.y])), atan2(p.x,p.y), norm(p)];
+ p = is_num(x)? [x, default(y,0), default(z,0)] : point3d(x)
+ ) [atan2(p.z,norm([p.x,p.y])), atan2(p.x,p.y), norm(p)];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/cubetruss.scad b/cubetruss.scad
index 3306eb8..b372b75 100644
--- a/cubetruss.scad
+++ b/cubetruss.scad
@@ -25,10 +25,10 @@ $cubetruss_clip_thickness = 1.6;
// size = The length of each side of the cubetruss cubes. Default: `$cubetruss_size` (usually 30)
// strut = The width of the struts on the cubetruss cubes. Default: `$cubetruss_strut_size` (usually 3)
function cubetruss_dist(cubes=0, gaps=0, size=undef, strut=undef) =
- let(
- size = is_undef(size)? $cubetruss_size : size,
- strut = is_undef(strut)? $cubetruss_strut_size : strut
- ) cubes*(size-strut)+gaps*strut;
+ let(
+ size = is_undef(size)? $cubetruss_size : size,
+ strut = is_undef(strut)? $cubetruss_strut_size : strut
+ ) cubes*(size-strut)+gaps*strut;
// Module: cubetruss_segment()
@@ -49,52 +49,52 @@ function cubetruss_dist(cubes=0, gaps=0, size=undef, strut=undef) =
// cubetruss_segment(strut=4);
// cubetruss_segment(size=40);
module cubetruss_segment(size=undef, strut=undef, bracing=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
- h = size;
- crossthick = strut/sqrt(2);
- voffset = 0.333;
- attachable(anchor,spin,orient, size=[size,size,size]) {
- render(convexity=10)
- union() {
- difference() {
- // Start with a cube.
- cube([size, size, h], center=true);
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
+ h = size;
+ crossthick = strut/sqrt(2);
+ voffset = 0.333;
+ attachable(anchor,spin,orient, size=[size,size,size]) {
+ render(convexity=10)
+ union() {
+ difference() {
+ // Start with a cube.
+ cube([size, size, h], center=true);
- cube([size-strut*2, size-strut*2, h-strut*2], center=true);
+ cube([size-strut*2, size-strut*2, h-strut*2], center=true);
- // Hollow out octogons in X and Y axes.
- zrot_copies([0,90]) {
- xrot(90) zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
- }
+ // Hollow out octogons in X and Y axes.
+ zrot_copies([0,90]) {
+ xrot(90) zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
+ }
- // Hollow out octogon vertically.
- zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
- }
+ // Hollow out octogon vertically.
+ zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
+ }
- // Interior cross-supports
- if (bracing) {
- for (i = [-1,1]) {
- zrot(i*45) {
- difference() {
- cube([crossthick, (size-strut)*sqrt(2), h], center=true);
- up(i*voffset) {
- yscale(1.3) {
- yrot(90) {
- zrot(180/6) {
- cylinder(h=crossthick+1, d=(min(h,size)-2*strut)/cos(180/6)-2*voffset, center=true, $fn=6);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- children();
- }
+ // Interior cross-supports
+ if (bracing) {
+ for (i = [-1,1]) {
+ zrot(i*45) {
+ difference() {
+ cube([crossthick, (size-strut)*sqrt(2), h], center=true);
+ up(i*voffset) {
+ yscale(1.3) {
+ yrot(90) {
+ zrot(180/6) {
+ cylinder(h=crossthick+1, d=(min(h,size)-2*strut)/cos(180/6)-2*voffset, center=true, $fn=6);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -116,47 +116,47 @@ module cubetruss_segment(size=undef, strut=undef, bracing=undef, anchor=CENTER,
// cubetruss_clip(extents=1);
// cubetruss_clip(clipthick=2.5);
module cubetruss_clip(extents=1, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- cliplen = strut * 2.6;
- clipheight = min(size+strut, size/3+2*strut*2.6);
- clipsize = 0.5;
- s = [extents*(size-strut)+strut+2*clipthick, strut*2, clipheight-2*strut];
- attachable(anchor,spin,orient, size=s) {
- xflip_copy(offset=(extents*(size-strut)+strut)/2) {
- difference() {
- union() {
- difference() {
- right(clipthick/2-0.01) {
- back(strut) {
- difference() {
- xrot(90) prismoid([clipthick, clipheight], [clipthick, clipheight-cliplen*2], h=cliplen);
- right(clipthick/2) chamfer_mask_z(l=clipheight+0.1, chamfer=clipthick);
- }
- }
- }
- fwd(strut*3/2) {
- cube([$slop, strut*3, size], center=true);
- }
- }
- right($slop/2+0.01) {
- fwd(strut*1.25+$slop) {
- yrot(-90) prismoid([clipheight-cliplen*2, strut/2], [clipheight-cliplen*2-2*clipsize, strut/2], h=clipsize+0.01);
- }
- }
- }
- fwd(strut*1.6) {
- left(clipsize) {
- yscale(1.5) chamfer_mask_z(l=size+1, chamfer=clipsize+clipthick/3);
- }
- }
- zcopies(clipheight-strut) cube([clipthick*3, cliplen*2, strut], center=true);
- zcopies(clipheight-2*strut) right(clipthick) chamfer_mask_y(l=cliplen*2, chamfer=clipthick);
- }
- }
- children();
- }
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ cliplen = strut * 2.6;
+ clipheight = min(size+strut, size/3+2*strut*2.6);
+ clipsize = 0.5;
+ s = [extents*(size-strut)+strut+2*clipthick, strut*2, clipheight-2*strut];
+ attachable(anchor,spin,orient, size=s) {
+ xflip_copy(offset=(extents*(size-strut)+strut)/2) {
+ difference() {
+ union() {
+ difference() {
+ right(clipthick/2-0.01) {
+ back(strut) {
+ difference() {
+ xrot(90) prismoid([clipthick, clipheight], [clipthick, clipheight-cliplen*2], h=cliplen);
+ right(clipthick/2) chamfer_mask_z(l=clipheight+0.1, chamfer=clipthick);
+ }
+ }
+ }
+ fwd(strut*3/2) {
+ cube([$slop, strut*3, size], center=true);
+ }
+ }
+ right($slop/2+0.01) {
+ fwd(strut*1.25+$slop) {
+ yrot(-90) prismoid([clipheight-cliplen*2, strut/2], [clipheight-cliplen*2-2*clipsize, strut/2], h=clipsize+0.01);
+ }
+ }
+ }
+ fwd(strut*1.6) {
+ left(clipsize) {
+ yscale(1.5) chamfer_mask_z(l=size+1, chamfer=clipsize+clipthick/3);
+ }
+ }
+ zcopies(clipheight-strut) cube([clipthick*3, cliplen*2, strut], center=true);
+ zcopies(clipheight-2*strut) right(clipthick) chamfer_mask_y(l=cliplen*2, chamfer=clipthick);
+ }
+ }
+ children();
+ }
}
@@ -177,60 +177,60 @@ module cubetruss_clip(extents=1, size=undef, strut=undef, clipthick=undef, ancho
// cubetruss_foot(w=1);
// cubetruss_foot(w=3);
module cubetruss_foot(w=1, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- clipsize = 0.5;
- wall_h = strut+clipthick*1.5;
- cyld = (size-2*strut)/cos(180/8);
- s = [w*(size-strut)+strut+2*clipthick, size-2*strut, strut+clipthick];
- attachable(anchor,spin,orient, size=s, offset=[0,0,(strut-clipthick)/2]) {
- down(clipthick) {
- // Base
- up(clipthick/2) {
- cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges=edges("Z"));
- }
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ clipsize = 0.5;
+ wall_h = strut+clipthick*1.5;
+ cyld = (size-2*strut)/cos(180/8);
+ s = [w*(size-strut)+strut+2*clipthick, size-2*strut, strut+clipthick];
+ attachable(anchor,spin,orient, size=s, offset=[0,0,(strut-clipthick)/2]) {
+ down(clipthick) {
+ // Base
+ up(clipthick/2) {
+ cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges=edges("Z"));
+ }
- // Walls
- xcopies(w*(size-strut)+strut+clipthick) {
- up(clipthick-0.01) {
- prismoid([clipthick, (size-4*strut)], [clipthick, size/3.5], h=wall_h, anchor=BOT);
- }
- }
+ // Walls
+ xcopies(w*(size-strut)+strut+clipthick) {
+ up(clipthick-0.01) {
+ prismoid([clipthick, (size-4*strut)], [clipthick, size/3.5], h=wall_h, anchor=BOT);
+ }
+ }
- // Horiz Wall Clips
- up(clipthick+strut+$slop*2) {
- xcopies(w*(size-strut)+strut) {
- prismoid([clipsize*2, size/3.5], [0.1, size/3.5], h=clipsize*3, anchor=BOT);
- }
- }
+ // Horiz Wall Clips
+ up(clipthick+strut+$slop*2) {
+ xcopies(w*(size-strut)+strut) {
+ prismoid([clipsize*2, size/3.5], [0.1, size/3.5], h=clipsize*3, anchor=BOT);
+ }
+ }
- // Middle plugs
- for (xcol = [0:w-1]) {
- right((xcol-(w-1)/2)*(size-strut)) {
- difference() {
- // Start with octagon to fit sides.
- up(clipthick-0.01) {
- zrot(180/8) cylinder(h=strut, d1=cyld-4*$slop, d2=cyld-4*$slop-1, center=false, $fn=8);
- }
+ // Middle plugs
+ for (xcol = [0:w-1]) {
+ right((xcol-(w-1)/2)*(size-strut)) {
+ difference() {
+ // Start with octagon to fit sides.
+ up(clipthick-0.01) {
+ zrot(180/8) cylinder(h=strut, d1=cyld-4*$slop, d2=cyld-4*$slop-1, center=false, $fn=8);
+ }
- // Bevel to fit.
- up(clipthick+strut) {
- ycopies(size-2*strut-4*$slop) {
- chamfer_mask_x(l=size-strut, chamfer=strut*2/3);
- }
- }
+ // Bevel to fit.
+ up(clipthick+strut) {
+ ycopies(size-2*strut-4*$slop) {
+ chamfer_mask_x(l=size-strut, chamfer=strut*2/3);
+ }
+ }
- // Cut out X for possible top mount.
- zrot_copies([-45, 45]) {
- cube([size*3, strut/sqrt(2)+2*$slop, size*3], center=true);
- }
- }
- }
- }
- }
- children();
- }
+ // Cut out X for possible top mount.
+ zrot_copies([-45, 45]) {
+ cube([size*3, strut/sqrt(2)+2*$slop, size*3], center=true);
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -253,49 +253,49 @@ module cubetruss_foot(w=1, size=undef, strut=undef, clipthick=undef, anchor=CENT
// cubetruss_joiner(w=1, vert=true);
// cubetruss_joiner(w=2, vert=true, anchor=BOT);
module cubetruss_joiner(w=1, vert=true, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- clipsize = 0.5;
- s = [cubetruss_dist(w,1)+2*clipthick, cubetruss_dist(2,0)-0.1, strut+clipthick];
- attachable(anchor,spin,orient, size=s, offset=[0,0,-(clipthick-strut)/2]) {
- down(clipthick) {
- // Base
- cube([w*(size-strut)+strut+2*clipthick, size, clipthick], anchor=BOT);
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ clipsize = 0.5;
+ s = [cubetruss_dist(w,1)+2*clipthick, cubetruss_dist(2,0)-0.1, strut+clipthick];
+ attachable(anchor,spin,orient, size=s, offset=[0,0,-(clipthick-strut)/2]) {
+ down(clipthick) {
+ // Base
+ cube([w*(size-strut)+strut+2*clipthick, size, clipthick], anchor=BOT);
- xcopies(w*(size-strut)+strut+clipthick) {
- cube([clipthick, size, clipthick+strut*3/4], anchor=BOT);
- }
+ xcopies(w*(size-strut)+strut+clipthick) {
+ cube([clipthick, size, clipthick+strut*3/4], anchor=BOT);
+ }
- // Use feet
- ycopies(size) {
- cubetruss_foot(w=w, size=size, strut=strut, clipthick=clipthick, anchor=BOT);
- }
+ // Use feet
+ ycopies(size) {
+ cubetruss_foot(w=w, size=size, strut=strut, clipthick=clipthick, anchor=BOT);
+ }
- if (vert) {
- // Vert Walls
- xcopies(w*(size-strut)+strut+clipthick) {
- up(clipthick-0.01) {
- prismoid([clipthick, size], [clipthick, 2*strut+2*clipthick], h=size*0.6, anchor=BOT);
- }
- }
+ if (vert) {
+ // Vert Walls
+ xcopies(w*(size-strut)+strut+clipthick) {
+ up(clipthick-0.01) {
+ prismoid([clipthick, size], [clipthick, 2*strut+2*clipthick], h=size*0.6, anchor=BOT);
+ }
+ }
- // Vert Wall Clips
- up(size/2) {
- xflip_copy(offset=(w*(size-strut)+strut+0.02)/2) {
- yflip_copy(offset=strut+$slop/2) {
- yrot(-90) {
- back_half() {
- prismoid([size/3.5, clipthick*2], [size/3.5-4*2*clipsize, 0.1], h=2*clipsize, anchor=BOT);
- }
- }
- }
- }
- }
- }
- }
- children();
- }
+ // Vert Wall Clips
+ up(size/2) {
+ xflip_copy(offset=(w*(size-strut)+strut+0.02)/2) {
+ yflip_copy(offset=strut+$slop/2) {
+ yrot(-90) {
+ back_half() {
+ prismoid([size/3.5, clipthick*2], [size/3.5-4*2*clipsize, 0.1], h=2*clipsize, anchor=BOT);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -314,29 +314,29 @@ module cubetruss_joiner(w=1, vert=true, size=undef, strut=undef, clipthick=undef
// cubetruss_uclip(dual=false);
// cubetruss_uclip(dual=true);
module cubetruss_uclip(dual=true, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- clipsize = 0.5;
- s = [(dual?2:1)*strut+2*clipthick+$slop, strut+2*clipthick, size/3.5];
- attachable(anchor,spin,orient, size=s) {
- union() {
- difference() {
- cube(s, center=true);
- back(clipthick) cube([(dual?2:1)*strut+$slop, strut+2*clipthick, size+1], center=true);
- }
- back((strut+$slop)/2) {
- xflip_copy(offset=(dual?1:0.5)*strut+$slop/2) {
- yrot(-90) {
- back_half() {
- prismoid([size/3.5, clipthick*1.87], [size/3.5, 0.1], h=clipsize, anchor=BOT);
- }
- }
- }
- }
- }
- children();
- }
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ clipsize = 0.5;
+ s = [(dual?2:1)*strut+2*clipthick+$slop, strut+2*clipthick, size/3.5];
+ attachable(anchor,spin,orient, size=s) {
+ union() {
+ difference() {
+ cube(s, center=true);
+ back(clipthick) cube([(dual?2:1)*strut+$slop, strut+2*clipthick, size+1], center=true);
+ }
+ back((strut+$slop)/2) {
+ xflip_copy(offset=(dual?1:0.5)*strut+$slop/2) {
+ yrot(-90) {
+ back_half() {
+ prismoid([size/3.5, clipthick*1.87], [size/3.5, 0.1], h=clipsize, anchor=BOT);
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -363,48 +363,48 @@ module cubetruss_uclip(dual=true, size=undef, strut=undef, clipthick=undef, anch
// cubetruss(extents=[1,4,2]);
// cubetruss(extents=[1,4,2], bracing=false);
module cubetruss(extents=6, clips=[], bracing=undef, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- clips = is_vector(clips)? [clips] : clips;
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- extents = is_vector(extents)? point3d(extents,fill=1) : [1,extents,1];
- w = extents[0];
- l = extents[1];
- h = extents[2];
- s = [cubetruss_dist(w,1), cubetruss_dist(l,1), cubetruss_dist(h,1)];
- attachable(anchor,spin,orient, size=s) {
- union() {
- for (zrow = [0:h-1]) {
- up((zrow-(h-1)/2)*(size-strut)) {
- for (xcol = [0:w-1]) {
- right((xcol-(w-1)/2)*(size-strut)) {
- for (ycol = [0:l-1]) {
- back((ycol-(l-1)/2)*(size-strut)) {
- cubetruss_segment(size=size, strut=strut, bracing=bracing);
- }
- }
- }
- }
- }
- }
- if (clipthick > 0) {
- for (vec = clips) {
- exts = vabs(rot(from=FWD, to=vec, p=extents));
- rot(from=FWD,to=vec) {
- for (zrow = [0:1:exts.z-1]) {
- up((zrow-(exts.z-1)/2)*(size-strut)) {
- fwd((exts.y*(size-strut)+strut)/2) {
- cubetruss_clip(size=size, strut=strut, extents=exts.x, clipthick=clipthick);
- }
- }
- }
- }
- }
- }
- }
- children();
- }
+ clips = is_vector(clips)? [clips] : clips;
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ extents = is_vector(extents)? point3d(extents,fill=1) : [1,extents,1];
+ w = extents[0];
+ l = extents[1];
+ h = extents[2];
+ s = [cubetruss_dist(w,1), cubetruss_dist(l,1), cubetruss_dist(h,1)];
+ attachable(anchor,spin,orient, size=s) {
+ union() {
+ for (zrow = [0:h-1]) {
+ up((zrow-(h-1)/2)*(size-strut)) {
+ for (xcol = [0:w-1]) {
+ right((xcol-(w-1)/2)*(size-strut)) {
+ for (ycol = [0:l-1]) {
+ back((ycol-(l-1)/2)*(size-strut)) {
+ cubetruss_segment(size=size, strut=strut, bracing=bracing);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (clipthick > 0) {
+ for (vec = clips) {
+ exts = vabs(rot(from=FWD, to=vec, p=extents));
+ rot(from=FWD,to=vec) {
+ for (zrow = [0:1:exts.z-1]) {
+ up((zrow-(exts.z-1)/2)*(size-strut)) {
+ fwd((exts.y*(size-strut)+strut)/2) {
+ cubetruss_clip(size=size, strut=strut, extents=exts.x, clipthick=clipthick);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -430,53 +430,53 @@ module cubetruss(extents=6, clips=[], bracing=undef, size=undef, strut=undef, cl
// cubetruss_corner(extents=[3,0,3,0,2]);
// cubetruss_corner(extents=[3,3,3,3,2]);
module cubetruss_corner(h=1, extents=[1,1,0,0,1], bracing=undef, size=undef, strut=undef, clipthick=undef, anchor=CENTER, spin=0, orient=UP) {
- size = is_undef(size)? $cubetruss_size : size;
- strut = is_undef(strut)? $cubetruss_strut_size : strut;
- bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
- clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
- exts = is_vector(extents)? list_fit(extents,5,fill=0) : [extents, extents, 0, 0, extents];
- s = [cubetruss_dist(1+exts[0]+exts[2],1), cubetruss_dist(1+exts[1]+exts[3],1), cubetruss_dist(h+exts[4],1)];
- offset = [cubetruss_dist(exts[0]-exts[2],0), cubetruss_dist(exts[1]-exts[3],0), cubetruss_dist(exts[4],0)]/2;
- attachable(anchor,spin,orient, size=s, offset=offset) {
- union() {
- for (zcol = [0:h-1]) {
- up((size-strut+0.01)*zcol) {
- cubetruss_segment(size=size, strut=strut, bracing=bracing);
- }
- }
- for (dir = [0:3]) {
- if (exts[dir] != undef && exts[dir] > 0) {
- zrot(dir*90) {
- for (zcol = [0:h-1]) {
- up((size-strut+0.01)*zcol) {
- for (i = [1:exts[dir]]) {
- right((size-strut+0.01)*i) cubetruss_segment(size=size, strut=strut, bracing=bracing);
- }
- if (clipthick > 0) {
- right(exts[dir]*(size-strut)+size/2) {
- zrot(90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
- }
- }
- }
- }
- }
- }
- }
- if (exts[4] != undef && exts[4] > 0) {
- for (i = [1:exts[4]]) {
- up((size-strut+0.01)*(i+h-1)) cubetruss_segment(size=size, strut=strut, bracing=bracing);
- }
- if (clipthick > 0) {
- up((exts[4]+h-1)*(size-strut)+size/2) {
- xrot(-90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
- }
- }
- }
- }
- children();
- }
+ size = is_undef(size)? $cubetruss_size : size;
+ strut = is_undef(strut)? $cubetruss_strut_size : strut;
+ bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
+ clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
+ exts = is_vector(extents)? list_fit(extents,5,fill=0) : [extents, extents, 0, 0, extents];
+ s = [cubetruss_dist(1+exts[0]+exts[2],1), cubetruss_dist(1+exts[1]+exts[3],1), cubetruss_dist(h+exts[4],1)];
+ offset = [cubetruss_dist(exts[0]-exts[2],0), cubetruss_dist(exts[1]-exts[3],0), cubetruss_dist(exts[4],0)]/2;
+ attachable(anchor,spin,orient, size=s, offset=offset) {
+ union() {
+ for (zcol = [0:h-1]) {
+ up((size-strut+0.01)*zcol) {
+ cubetruss_segment(size=size, strut=strut, bracing=bracing);
+ }
+ }
+ for (dir = [0:3]) {
+ if (exts[dir] != undef && exts[dir] > 0) {
+ zrot(dir*90) {
+ for (zcol = [0:h-1]) {
+ up((size-strut+0.01)*zcol) {
+ for (i = [1:exts[dir]]) {
+ right((size-strut+0.01)*i) cubetruss_segment(size=size, strut=strut, bracing=bracing);
+ }
+ if (clipthick > 0) {
+ right(exts[dir]*(size-strut)+size/2) {
+ zrot(90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (exts[4] != undef && exts[4] > 0) {
+ for (i = [1:exts[4]]) {
+ up((size-strut+0.01)*(i+h-1)) cubetruss_segment(size=size, strut=strut, bracing=bracing);
+ }
+ if (clipthick > 0) {
+ up((exts[4]+h-1)*(size-strut)+size/2) {
+ xrot(-90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
+ }
+ }
+ }
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/debug.scad b/debug.scad
index b183e7a..3ff5704 100644
--- a/debug.scad
+++ b/debug.scad
@@ -28,33 +28,33 @@ include
// polyline = [for (a=[0:30:210]) 10*[cos(a), sin(a), sin(a)]];
// trace_polyline(polyline, showpts=true, size=0.5, color="lightgreen");
module trace_polyline(pline, closed=false, showpts=false, N=1, size=1, color="yellow") {
- assert(is_path(pline),"Input pline is not a path");
- sides = segs(size/2);
- pline = closed? close_path(pline) : pline;
- if (showpts) {
- for (i = [0:1:len(pline)-1]) {
- translate(pline[i]) {
- if (i%N == 0) {
- color("blue") sphere(d=size*2.5, $fn=8);
- } else {
- color("red") {
- cylinder(d=size/2, h=size*3, center=true, $fn=8);
- xrot(90) cylinder(d=size/2, h=size*3, center=true, $fn=8);
- yrot(90) cylinder(d=size/2, h=size*3, center=true, $fn=8);
- }
- }
- }
- }
- }
- if (N!=3) {
- color(color) stroke(path3d(pline), width=size, $fn=8);
- } else {
- for (i = [0:1:len(pline)-2]) {
- if (N!=3 || (i%N) != 1) {
- color(color) extrude_from_to(pline[i], pline[i+1]) circle(d=size, $fn=sides);
- }
- }
- }
+ assert(is_path(pline),"Input pline is not a path");
+ sides = segs(size/2);
+ pline = closed? close_path(pline) : pline;
+ if (showpts) {
+ for (i = [0:1:len(pline)-1]) {
+ translate(pline[i]) {
+ if (i%N == 0) {
+ color("blue") sphere(d=size*2.5, $fn=8);
+ } else {
+ color("red") {
+ cylinder(d=size/2, h=size*3, center=true, $fn=8);
+ xrot(90) cylinder(d=size/2, h=size*3, center=true, $fn=8);
+ yrot(90) cylinder(d=size/2, h=size*3, center=true, $fn=8);
+ }
+ }
+ }
+ }
+ }
+ if (N!=3) {
+ color(color) stroke(path3d(pline), width=size, $fn=8);
+ } else {
+ for (i = [0:1:len(pline)-2]) {
+ if (N!=3 || (i%N) != 1) {
+ color(color) extrude_from_to(pline[i], pline[i+1]) circle(d=size, $fn=sides);
+ }
+ }
+ }
}
@@ -77,44 +77,44 @@ module trace_polyline(pline, closed=false, showpts=false, N=1, size=1, color="ye
// );
module debug_polygon(points, paths=undef, convexity=2, size=1)
{
- pths = is_undef(paths)? [for (i=[0:1:len(points)-1]) i] : is_num(paths[0])? [paths] : paths;
- echo(points=points);
- echo(paths=paths);
- linear_extrude(height=0.01, convexity=convexity, center=true) {
- polygon(points=points, paths=paths, convexity=convexity);
- }
- for (i = [0:1:len(points)-1]) {
- color("red") {
- up(0.2) {
- translate(points[i]) {
- linear_extrude(height=0.1, convexity=10, center=true) {
- text(text=str(i), size=size, halign="center", valign="center");
- }
- }
- }
- }
- }
- for (j = [0:1:len(paths)-1]) {
- path = paths[j];
- translate(points[path[0]]) {
- color("cyan") up(0.1) cylinder(d=size*1.5, h=0.01, center=false, $fn=12);
- }
- translate(points[path[len(path)-1]]) {
- color("pink") up(0.11) cylinder(d=size*1.5, h=0.01, center=false, $fn=4);
- }
- for (i = [0:1:len(path)-1]) {
- midpt = (points[path[i]] + points[path[(i+1)%len(path)]])/2;
- color("blue") {
- up(0.2) {
- translate(midpt) {
- linear_extrude(height=0.1, convexity=10, center=true) {
- text(text=str(chr(65+j),i), size=size/2, halign="center", valign="center");
- }
- }
- }
- }
- }
- }
+ pths = is_undef(paths)? [for (i=[0:1:len(points)-1]) i] : is_num(paths[0])? [paths] : paths;
+ echo(points=points);
+ echo(paths=paths);
+ linear_extrude(height=0.01, convexity=convexity, center=true) {
+ polygon(points=points, paths=paths, convexity=convexity);
+ }
+ for (i = [0:1:len(points)-1]) {
+ color("red") {
+ up(0.2) {
+ translate(points[i]) {
+ linear_extrude(height=0.1, convexity=10, center=true) {
+ text(text=str(i), size=size, halign="center", valign="center");
+ }
+ }
+ }
+ }
+ }
+ for (j = [0:1:len(paths)-1]) {
+ path = paths[j];
+ translate(points[path[0]]) {
+ color("cyan") up(0.1) cylinder(d=size*1.5, h=0.01, center=false, $fn=12);
+ }
+ translate(points[path[len(path)-1]]) {
+ color("pink") up(0.11) cylinder(d=size*1.5, h=0.01, center=false, $fn=4);
+ }
+ for (i = [0:1:len(path)-1]) {
+ midpt = (points[path[i]] + points[path[(i+1)%len(path)]])/2;
+ color("blue") {
+ up(0.2) {
+ translate(midpt) {
+ linear_extrude(height=0.1, convexity=10, center=true) {
+ text(text=str(chr(65+j),i), size=size/2, halign="center", valign="center");
+ }
+ }
+ }
+ }
+ }
+ }
}
@@ -138,29 +138,29 @@ module debug_polygon(points, paths=undef, convexity=2, size=1)
// polyhedron(points=verts, faces=faces);
// }
module debug_vertices(vertices, size=1, disabled=false) {
- if (!disabled) {
- echo(vertices=vertices);
- color("blue") {
- for (i = [0:1:len(vertices)-1]) {
- v = vertices[i];
- translate(v) {
- up(size/8) zrot($vpr[2]) xrot(90) {
- linear_extrude(height=size/10, center=true, convexity=10) {
- text(text=str(i), size=size, halign="center");
- }
- }
- sphere(size/10);
- }
- }
- }
- }
- if ($children > 0) {
- if (!disabled) {
- color([0.2, 1.0, 0, 0.5]) children();
- } else {
- children();
- }
- }
+ if (!disabled) {
+ echo(vertices=vertices);
+ color("blue") {
+ for (i = [0:1:len(vertices)-1]) {
+ v = vertices[i];
+ translate(v) {
+ up(size/8) zrot($vpr[2]) xrot(90) {
+ linear_extrude(height=size/10, center=true, convexity=10) {
+ text(text=str(i), size=size, halign="center");
+ }
+ }
+ sphere(size/10);
+ }
+ }
+ }
+ }
+ if ($children > 0) {
+ if (!disabled) {
+ color([0.2, 1.0, 0, 0.5]) children();
+ } else {
+ children();
+ }
+ }
}
@@ -183,46 +183,46 @@ module debug_vertices(vertices, size=1, disabled=false) {
// polyhedron(points=verts, faces=faces);
// }
module debug_faces(vertices, faces, size=1, disabled=false) {
- if (!disabled) {
- vlen = len(vertices);
- color("red") {
- for (i = [0:1:len(faces)-1]) {
- face = faces[i];
- 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);
- } else {
- v0 = vertices[face[0]];
- v1 = vertices[face[1]];
- v2 = vertices[face[2]];
- c = mean(select(vertices,face));
- dv0 = unit(v1 - v0);
- dv1 = unit(v2 - v0);
- nrm0 = unit(cross(dv0, dv1));
- nrm1 = [0, 0, 1];
- axis = unit(cross(nrm0, nrm1));
- ang = vector_angle(nrm0, nrm1);
- theta = atan2(nrm0[1], nrm0[0]);
- translate(c) {
- rotate(a=180-ang, v=axis) {
- zrot(theta-90)
- linear_extrude(height=size/10, center=true, convexity=10) {
- union() {
- text(text=str(i), size=size, halign="center");
- text(text=str("_"), size=size, halign="center");
- }
- }
- }
- }
- }
- }
- }
- }
- debug_vertices(vertices, size=size, disabled=disabled) {
- children();
- }
- if (!disabled) {
- echo(faces=faces);
- }
+ if (!disabled) {
+ vlen = len(vertices);
+ color("red") {
+ for (i = [0:1:len(faces)-1]) {
+ face = faces[i];
+ 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);
+ } else {
+ v0 = vertices[face[0]];
+ v1 = vertices[face[1]];
+ v2 = vertices[face[2]];
+ c = mean(select(vertices,face));
+ dv0 = unit(v1 - v0);
+ dv1 = unit(v2 - v0);
+ nrm0 = unit(cross(dv0, dv1));
+ nrm1 = [0, 0, 1];
+ axis = unit(cross(nrm0, nrm1));
+ ang = vector_angle(nrm0, nrm1);
+ theta = atan2(nrm0[1], nrm0[0]);
+ translate(c) {
+ rotate(a=180-ang, v=axis) {
+ zrot(theta-90)
+ linear_extrude(height=size/10, center=true, convexity=10) {
+ union() {
+ text(text=str(i), size=size, halign="center");
+ text(text=str("_"), size=size, halign="center");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ debug_vertices(vertices, size=size, disabled=disabled) {
+ children();
+ }
+ if (!disabled) {
+ echo(faces=faces);
+ }
}
@@ -245,9 +245,9 @@ module debug_faces(vertices, faces, size=1, disabled=false) {
// faces = [[0,1,2], [5,4,3], [0,3,4], [0,4,1], [1,4,5], [1,5,2], [2,5,3], [2,3,0]];
// debug_polyhedron(points=verts, faces=faces, txtsize=1);
module debug_polyhedron(points, faces, convexity=10, txtsize=1, disabled=false) {
- debug_faces(vertices=points, faces=faces, size=txtsize, disabled=disabled) {
- polyhedron(points=points, faces=faces, convexity=convexity);
- }
+ debug_faces(vertices=points, faces=faces, size=txtsize, disabled=disabled) {
+ polyhedron(points=points, faces=faces, convexity=convexity);
+ }
}
@@ -256,11 +256,11 @@ module debug_polyhedron(points, faces, convexity=10, txtsize=1, disabled=false)
// Description:
// Return the vectors for all standard anchors.
function standard_anchors() = [
- for (
- zv = [TOP, CENTER, BOTTOM],
- yv = [FRONT, CENTER, BACK],
- xv = [LEFT, CENTER, RIGHT]
- ) xv+yv+zv
+ for (
+ zv = [TOP, CENTER, BOTTOM],
+ yv = [FRONT, CENTER, BACK],
+ xv = [LEFT, CENTER, RIGHT]
+ ) xv+yv+zv
];
@@ -277,19 +277,19 @@ function standard_anchors() = [
// Example:
// anchor_arrow(s=20);
module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow") {
- $fn=12;
- recolor("gray") spheroid(d=s/6) {
- attach(CENTER,BOT) recolor(color) cyl(h=s*2/3, d=s/15) {
- attach(TOP,BOT) cyl(h=s/3, d1=s/5, d2=0) {
- if(flag) {
- position(BOT)
- recolor([1,0.5,0.5])
- cuboid([s/100, s/6, s/4], anchor=FRONT+BOT);
- }
- children();
- }
- }
- }
+ $fn=12;
+ recolor("gray") spheroid(d=s/6) {
+ attach(CENTER,BOT) recolor(color) cyl(h=s*2/3, d=s/15) {
+ attach(TOP,BOT) cyl(h=s/3, d1=s/5, d2=0) {
+ if(flag) {
+ position(BOT)
+ recolor([1,0.5,0.5])
+ cuboid([s/100, s/6, s/4], anchor=FRONT+BOT);
+ }
+ children();
+ }
+ }
+ }
}
@@ -303,8 +303,8 @@ module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow"
// Example(FlatSpin):
// show_internal_anchors() cube(50, center=true) show_anchors();
module show_internal_anchors(opacity=0.2) {
- show("anchor-arrow") children() show_anchors();
- hide("anchor-arrow") recolor(list_pad(point3d($color),4,fill=opacity)) children();
+ show("anchor-arrow") children() show_anchors();
+ hide("anchor-arrow") recolor(list_pad(point3d($color),4,fill=opacity)) children();
}
@@ -318,29 +318,29 @@ module show_internal_anchors(opacity=0.2) {
// Example(FlatSpin):
// cube(50, center=true) show_anchors();
module show_anchors(s=10, std=true, custom=true) {
- if (std) {
- for (anchor=standard_anchors()) {
- attach(anchor) anchor_arrow(s);
- }
- }
- if (custom) {
- for (anchor=select($parent_geom,-1)) {
- attach(anchor[0]) {
- anchor_arrow(s, color="cyan");
- recolor("black")
- noop($tags="anchor-arrow") {
- xrot(90) {
- up(s/10) {
- linear_extrude(height=0.01, convexity=12, center=true) {
- text(text=anchor[0], size=s/4, halign="center", valign="center");
- }
- }
- }
- }
- }
- }
- }
- children();
+ if (std) {
+ for (anchor=standard_anchors()) {
+ attach(anchor) anchor_arrow(s);
+ }
+ }
+ if (custom) {
+ for (anchor=select($parent_geom,-1)) {
+ attach(anchor[0]) {
+ anchor_arrow(s, color="cyan");
+ recolor("black")
+ noop($tags="anchor-arrow") {
+ xrot(90) {
+ up(s/10) {
+ linear_extrude(height=0.01, convexity=12, center=true) {
+ text(text=anchor[0], size=s/4, halign="center", valign="center");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
}
@@ -353,12 +353,12 @@ module show_anchors(s=10, std=true, custom=true) {
// Examples:
// frame_ref(25);
module frame_ref(s=15) {
- cube(0.01, center=true) {
- attach(RIGHT) anchor_arrow(s=s, flag=false, color="red");
- attach(BACK) anchor_arrow(s=s, flag=false, color="green");
- attach(TOP) anchor_arrow(s=s, flag=false, color="blue");
- children();
- }
+ cube(0.01, center=true) {
+ attach(RIGHT) anchor_arrow(s=s, flag=false, color="red");
+ attach(BACK) anchor_arrow(s=s, flag=false, color="green");
+ attach(TOP) anchor_arrow(s=s, flag=false, color="blue");
+ children();
+ }
}
@@ -389,63 +389,63 @@ module frame_ref(s=15) {
// fwd(50)ruler(300,width=50,labels=true);
module ruler(length=100, width=undef, thickness=1, depth=3, labels=false, pipscale=1/3, maxscale=undef, colors=["black","white"], alpha=1.0, unit=1, inch=false, anchor=LEFT+BACK+TOP, spin=0, orient=UP)
{
- inchfactor = 25.4;
- assert(depth<=5, "Cannot render scales smaller than depth=5");
- assert(len(colors)==2, "colors must contain a list of exactly two colors.");
- length = inch ? inchfactor * length : length;
- unit = inch ? inchfactor*unit : unit;
- maxscale = is_def(maxscale)? maxscale : floor(log(length/unit-EPSILON));
- scales = unit * [for(logsize = [maxscale:-1:maxscale-depth+1]) pow(10,logsize)];
- widthfactor = (1-pipscale) / (1-pow(pipscale,depth));
- width = default(width, scales[0]);
- widths = width * widthfactor * [for(logsize = [0:-1:-depth+1]) pow(pipscale,-logsize)];
- offsets = concat([0],cumsum(widths));
- attachable(anchor,spin,orient, size=[length,width,thickness]) {
- translate([-length/2, -width/2, 0])
- for(i=[0:1:len(scales)-1]) {
- count = ceil(length/scales[i]);
- fontsize = 0.5*min(widths[i], scales[i]/ceil(log(count*scales[i]/unit)));
- back(offsets[i]) {
- xcopies(scales[i], n=count, sp=[0,0,0]) union() {
- actlen = ($idx0 ? quantup(widths[i],1/1024) : widths[i]; // What is the i>0 test supposed to do here?
- cube([quantup(actlen,1/1024),quantup(w,1/1024),thickness], anchor=FRONT+LEFT);
- }
- mark =
- i == 0 && $idx % 10 == 0 && $idx != 0 ? 0 :
- i == 0 && $idx % 10 == 9 && $idx != count-1 ? 1 :
- $idx % 10 == 4 ? 1 :
- $idx % 10 == 5 ? 0 : -1;
- flip = 1-mark*2;
- if (mark >= 0) {
- marklength = min(widths[i]/2, scales[i]*2);
- markwidth = marklength*0.4;
- translate([mark*scales[i], widths[i], 0]) {
- color(colors[1-$idx%2], alpha=alpha) {
- linear_extrude(height=thickness+scales[i]/100, convexity=2, center=true) {
- polygon(scale([flip*markwidth, marklength],p=[[0,0], [1, -1], [0,-0.9]]));
- }
- }
- }
- }
- if (labels && scales[i]/unit+EPSILON >= 1) {
- color(colors[($idx+1)%2], alpha=alpha) {
- linear_extrude(height=thickness+scales[i]/100, convexity=2, center=true) {
- back(scales[i]*.02) {
- text(text=str( $idx * scales[i] / unit), size=fontsize, halign="left", valign="baseline");
- }
- }
- }
- }
+ inchfactor = 25.4;
+ assert(depth<=5, "Cannot render scales smaller than depth=5");
+ assert(len(colors)==2, "colors must contain a list of exactly two colors.");
+ length = inch ? inchfactor * length : length;
+ unit = inch ? inchfactor*unit : unit;
+ maxscale = is_def(maxscale)? maxscale : floor(log(length/unit-EPSILON));
+ scales = unit * [for(logsize = [maxscale:-1:maxscale-depth+1]) pow(10,logsize)];
+ widthfactor = (1-pipscale) / (1-pow(pipscale,depth));
+ width = default(width, scales[0]);
+ widths = width * widthfactor * [for(logsize = [0:-1:-depth+1]) pow(pipscale,-logsize)];
+ offsets = concat([0],cumsum(widths));
+ attachable(anchor,spin,orient, size=[length,width,thickness]) {
+ translate([-length/2, -width/2, 0])
+ for(i=[0:1:len(scales)-1]) {
+ count = ceil(length/scales[i]);
+ fontsize = 0.5*min(widths[i], scales[i]/ceil(log(count*scales[i]/unit)));
+ back(offsets[i]) {
+ xcopies(scales[i], n=count, sp=[0,0,0]) union() {
+ actlen = ($idx0 ? quantup(widths[i],1/1024) : widths[i]; // What is the i>0 test supposed to do here?
+ cube([quantup(actlen,1/1024),quantup(w,1/1024),thickness], anchor=FRONT+LEFT);
+ }
+ mark =
+ i == 0 && $idx % 10 == 0 && $idx != 0 ? 0 :
+ i == 0 && $idx % 10 == 9 && $idx != count-1 ? 1 :
+ $idx % 10 == 4 ? 1 :
+ $idx % 10 == 5 ? 0 : -1;
+ flip = 1-mark*2;
+ if (mark >= 0) {
+ marklength = min(widths[i]/2, scales[i]*2);
+ markwidth = marklength*0.4;
+ translate([mark*scales[i], widths[i], 0]) {
+ color(colors[1-$idx%2], alpha=alpha) {
+ linear_extrude(height=thickness+scales[i]/100, convexity=2, center=true) {
+ polygon(scale([flip*markwidth, marklength],p=[[0,0], [1, -1], [0,-0.9]]));
+ }
+ }
+ }
+ }
+ if (labels && scales[i]/unit+EPSILON >= 1) {
+ color(colors[($idx+1)%2], alpha=alpha) {
+ linear_extrude(height=thickness+scales[i]/100, convexity=2, center=true) {
+ back(scales[i]*.02) {
+ text(text=str( $idx * scales[i] / unit), size=fontsize, halign="left", valign="baseline");
+ }
+ }
+ }
+ }
- }
- }
- }
- children();
- }
+ }
+ }
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/distributors.scad b/distributors.scad
index b008113..603e50d 100644
--- a/distributors.scad
+++ b/distributors.scad
@@ -33,12 +33,12 @@
// move_copies([[-25,-25,0], [25,-25,0], [0,0,50], [0,25,0]]) sphere(r=10);
module move_copies(a=[[0,0,0]])
{
- assert(is_list(a));
- for ($idx = idx(a)) {
- $pos = a[$idx];
- assert(is_vector($pos));
- translate($pos) children();
- }
+ assert(is_list(a));
+ for ($idx = idx(a)) {
+ $pos = a[$idx];
+ assert(is_vector($pos));
+ translate($pos) children();
+ }
}
@@ -80,30 +80,30 @@ module move_copies(a=[[0,0,0]])
// }
module line_of(p1, p2, spacing, l, n)
{
- ll = (
- !is_undef(l)? scalar_vec3(l, 0) :
- (!is_undef(spacing) && !is_undef(n))? (n * scalar_vec3(spacing, 0)) :
- (!is_undef(p1) && !is_undef(p2))? point3d(p2-p1) :
- undef
- );
- cnt = (
- !is_undef(n)? n :
- (!is_undef(spacing) && !is_undef(ll))? floor(norm(ll) / norm(scalar_vec3(spacing, 0)) + 1.000001) :
- 2
- );
- spc = (
- is_undef(spacing)? (ll/(cnt-1)) :
- is_num(spacing) && !is_undef(ll)? (ll/(cnt-1)) :
- scalar_vec3(spacing, 0)
- );
- assert(!is_undef(cnt), "Need two of `spacing`, 'l', 'n', or `p1`/`p2` arguments in `line_of()`.");
- spos = !is_undef(p1)? point3d(p1) : -(cnt-1)/2 * spc;
- for (i=[0:1:cnt-1]) {
- pos = i * spc + spos;
- $pos = pos;
- $idx = i;
- translate(pos) children();
- }
+ ll = (
+ !is_undef(l)? scalar_vec3(l, 0) :
+ (!is_undef(spacing) && !is_undef(n))? (n * scalar_vec3(spacing, 0)) :
+ (!is_undef(p1) && !is_undef(p2))? point3d(p2-p1) :
+ undef
+ );
+ cnt = (
+ !is_undef(n)? n :
+ (!is_undef(spacing) && !is_undef(ll))? floor(norm(ll) / norm(scalar_vec3(spacing, 0)) + 1.000001) :
+ 2
+ );
+ spc = (
+ is_undef(spacing)? (ll/(cnt-1)) :
+ is_num(spacing) && !is_undef(ll)? (ll/(cnt-1)) :
+ scalar_vec3(spacing, 0)
+ );
+ assert(!is_undef(cnt), "Need two of `spacing`, 'l', 'n', or `p1`/`p2` arguments in `line_of()`.");
+ spos = !is_undef(p1)? point3d(p1) : -(cnt-1)/2 * spc;
+ for (i=[0:1:cnt-1]) {
+ pos = i * spc + spos;
+ $pos = pos;
+ $idx = i;
+ translate(pos) children();
+ }
}
@@ -138,7 +138,7 @@ module line_of(p1, p2, spacing, l, n)
// }
module xcopies(spacing, n, l, sp)
{
- line_of(l=l*RIGHT, spacing=spacing*RIGHT, n=n, p1=sp) children();
+ line_of(l=l*RIGHT, spacing=spacing*RIGHT, n=n, p1=sp) children();
}
@@ -173,7 +173,7 @@ module xcopies(spacing, n, l, sp)
// }
module ycopies(spacing, n, l, sp)
{
- line_of(l=l*BACK, spacing=spacing*BACK, n=n, p1=sp) children();
+ line_of(l=l*BACK, spacing=spacing*BACK, n=n, p1=sp) children();
}
@@ -208,7 +208,7 @@ module ycopies(spacing, n, l, sp)
// }
module zcopies(spacing, n, l, sp)
{
- line_of(l=l*UP, spacing=spacing*UP, n=n, p1=sp) children();
+ line_of(l=l*UP, spacing=spacing*UP, n=n, p1=sp) children();
}
@@ -243,18 +243,18 @@ module zcopies(spacing, n, l, sp)
// }
module distribute(spacing=undef, sizes=undef, dir=RIGHT, l=undef)
{
- gaps = ($children < 2)? [0] :
- !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
- [for (i=[0:1:$children-2]) 0];
- spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
- gaps2 = [for (gap = gaps) gap+spc];
- spos = dir * -sum(gaps2)/2;
- for (i=[0:1:$children-1]) {
- totspc = sum(concat([0], slice(gaps2, 0, i)));
- $pos = spos + totspc * dir;
- $idx = i;
- translate($pos) children(i);
- }
+ gaps = ($children < 2)? [0] :
+ !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
+ [for (i=[0:1:$children-2]) 0];
+ spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
+ gaps2 = [for (gap = gaps) gap+spc];
+ spos = dir * -sum(gaps2)/2;
+ for (i=[0:1:$children-1]) {
+ totspc = sum(concat([0], slice(gaps2, 0, i)));
+ $pos = spos + totspc * dir;
+ $idx = i;
+ translate($pos) children(i);
+ }
}
@@ -287,19 +287,19 @@ module distribute(spacing=undef, sizes=undef, dir=RIGHT, l=undef)
// }
module xdistribute(spacing=10, sizes=undef, l=undef)
{
- dir = RIGHT;
- gaps = ($children < 2)? [0] :
- !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
- [for (i=[0:1:$children-2]) 0];
- spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
- gaps2 = [for (gap = gaps) gap+spc];
- spos = dir * -sum(gaps2)/2;
- for (i=[0:1:$children-1]) {
- totspc = sum(concat([0], slice(gaps2, 0, i)));
- $pos = spos + totspc * dir;
- $idx = i;
- translate($pos) children(i);
- }
+ dir = RIGHT;
+ gaps = ($children < 2)? [0] :
+ !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
+ [for (i=[0:1:$children-2]) 0];
+ spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
+ gaps2 = [for (gap = gaps) gap+spc];
+ spos = dir * -sum(gaps2)/2;
+ for (i=[0:1:$children-1]) {
+ totspc = sum(concat([0], slice(gaps2, 0, i)));
+ $pos = spos + totspc * dir;
+ $idx = i;
+ translate($pos) children(i);
+ }
}
@@ -332,19 +332,19 @@ module xdistribute(spacing=10, sizes=undef, l=undef)
// }
module ydistribute(spacing=10, sizes=undef, l=undef)
{
- dir = BACK;
- gaps = ($children < 2)? [0] :
- !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
- [for (i=[0:1:$children-2]) 0];
- spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
- gaps2 = [for (gap = gaps) gap+spc];
- spos = dir * -sum(gaps2)/2;
- for (i=[0:1:$children-1]) {
- totspc = sum(concat([0], slice(gaps2, 0, i)));
- $pos = spos + totspc * dir;
- $idx = i;
- translate($pos) children(i);
- }
+ dir = BACK;
+ gaps = ($children < 2)? [0] :
+ !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
+ [for (i=[0:1:$children-2]) 0];
+ spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
+ gaps2 = [for (gap = gaps) gap+spc];
+ spos = dir * -sum(gaps2)/2;
+ for (i=[0:1:$children-1]) {
+ totspc = sum(concat([0], slice(gaps2, 0, i)));
+ $pos = spos + totspc * dir;
+ $idx = i;
+ translate($pos) children(i);
+ }
}
@@ -377,19 +377,19 @@ module ydistribute(spacing=10, sizes=undef, l=undef)
// }
module zdistribute(spacing=10, sizes=undef, l=undef)
{
- dir = UP;
- gaps = ($children < 2)? [0] :
- !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
- [for (i=[0:1:$children-2]) 0];
- spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
- gaps2 = [for (gap = gaps) gap+spc];
- spos = dir * -sum(gaps2)/2;
- for (i=[0:1:$children-1]) {
- totspc = sum(concat([0], slice(gaps2, 0, i)));
- $pos = spos + totspc * dir;
- $idx = i;
- translate($pos) children(i);
- }
+ dir = UP;
+ gaps = ($children < 2)? [0] :
+ !is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
+ [for (i=[0:1:$children-2]) 0];
+ spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
+ gaps2 = [for (gap = gaps) gap+spc];
+ spos = dir * -sum(gaps2)/2;
+ for (i=[0:1:$children-1]) {
+ totspc = sum(concat([0], slice(gaps2, 0, i)));
+ $pos = spos + totspc * dir;
+ $idx = i;
+ translate($pos) children(i);
+ }
}
@@ -450,73 +450,73 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// }
module grid2d(spacing, n, size, stagger=false, inside=undef)
{
- assert(in_list(stagger, [false, true, "alt"]));
- bounds = is_undef(inside)? undef :
- is_path(inside)? pointlist_bounds(inside) :
- assert(is_region(inside))
- pointlist_bounds(flatten(inside));
- size = is_num(size)? [size, size] :
- is_vector(size)? assert(len(size)==2) size :
- bounds!=undef? [
- for (i=[0:1]) 2*max(abs(bounds[0][i]),bounds[1][i])
- ] : undef;
- spacing = is_num(spacing)? (
- stagger!=false? polar_to_xy(spacing,60) :
- [spacing,spacing]
- ) :
- is_vector(spacing)? assert(len(spacing)==2) spacing :
- size!=undef? (
- is_num(n)? vdiv(size,(n-1)*[1,1]) :
- is_vector(n)? assert(len(n)==2) vdiv(size,n-[1,1]) :
- vdiv(size,(stagger==false? [1,1] : [2,2]))
- ) :
- undef;
- n = is_num(n)? [n,n] :
- is_vector(n)? assert(len(n)==2) n :
- size!=undef && spacing!=undef? vfloor(vdiv(size,spacing))+[1,1] :
- [2,2];
- offset = vmul(spacing, n-[1,1])/2;
- if (stagger == false) {
- for (row = [0:1:n.y-1]) {
- for (col = [0:1:n.x-1]) {
- pos = vmul([col,row],spacing) - offset;
- if (
- is_undef(inside) ||
- (is_path(inside) && point_in_polygon(pos, inside)>=0) ||
- (is_region(inside) && point_in_region(pos, inside)>=0)
- ) {
- $col = col;
- $row = row;
- $pos = pos;
- translate(pos) children();
- }
- }
- }
- } else {
- // stagger == true or stagger == "alt"
- staggermod = (stagger == "alt")? 1 : 0;
- cols1 = ceil(n.x/2);
- cols2 = n.x - cols1;
- for (row = [0:1:n.y-1]) {
- rowcols = ((row%2) == staggermod)? cols1 : cols2;
- if (rowcols > 0) {
- for (col = [0:1:rowcols-1]) {
- rowdx = (row%2 != staggermod)? spacing.x : 0;
- pos = vmul([2*col,row],spacing) + [rowdx,0] - offset;
- if (
- is_undef(inside) ||
- (is_path(inside) && point_in_polygon(pos, inside)>=0) ||
- (is_region(inside) && point_in_region(pos, inside)>=0)
- ) {
- $col = col * 2 + ((row%2!=staggermod)? 1 : 0);
- $row = row;
- $pos = pos;
- translate(pos) children();
- }
- }
- }
- }
- }
+ assert(in_list(stagger, [false, true, "alt"]));
+ bounds = is_undef(inside)? undef :
+ is_path(inside)? pointlist_bounds(inside) :
+ assert(is_region(inside))
+ pointlist_bounds(flatten(inside));
+ size = is_num(size)? [size, size] :
+ is_vector(size)? assert(len(size)==2) size :
+ bounds!=undef? [
+ for (i=[0:1]) 2*max(abs(bounds[0][i]),bounds[1][i])
+ ] : undef;
+ spacing = is_num(spacing)? (
+ stagger!=false? polar_to_xy(spacing,60) :
+ [spacing,spacing]
+ ) :
+ is_vector(spacing)? assert(len(spacing)==2) spacing :
+ size!=undef? (
+ is_num(n)? vdiv(size,(n-1)*[1,1]) :
+ is_vector(n)? assert(len(n)==2) vdiv(size,n-[1,1]) :
+ vdiv(size,(stagger==false? [1,1] : [2,2]))
+ ) :
+ undef;
+ n = is_num(n)? [n,n] :
+ is_vector(n)? assert(len(n)==2) n :
+ size!=undef && spacing!=undef? vfloor(vdiv(size,spacing))+[1,1] :
+ [2,2];
+ offset = vmul(spacing, n-[1,1])/2;
+ if (stagger == false) {
+ for (row = [0:1:n.y-1]) {
+ for (col = [0:1:n.x-1]) {
+ pos = vmul([col,row],spacing) - offset;
+ if (
+ is_undef(inside) ||
+ (is_path(inside) && point_in_polygon(pos, inside)>=0) ||
+ (is_region(inside) && point_in_region(pos, inside)>=0)
+ ) {
+ $col = col;
+ $row = row;
+ $pos = pos;
+ translate(pos) children();
+ }
+ }
+ }
+ } else {
+ // stagger == true or stagger == "alt"
+ staggermod = (stagger == "alt")? 1 : 0;
+ cols1 = ceil(n.x/2);
+ cols2 = n.x - cols1;
+ for (row = [0:1:n.y-1]) {
+ rowcols = ((row%2) == staggermod)? cols1 : cols2;
+ if (rowcols > 0) {
+ for (col = [0:1:rowcols-1]) {
+ rowdx = (row%2 != staggermod)? spacing.x : 0;
+ pos = vmul([2*col,row],spacing) + [rowdx,0] - offset;
+ if (
+ is_undef(inside) ||
+ (is_path(inside) && point_in_polygon(pos, inside)>=0) ||
+ (is_region(inside) && point_in_region(pos, inside)>=0)
+ ) {
+ $col = col * 2 + ((row%2!=staggermod)? 1 : 0);
+ $row = row;
+ $pos = pos;
+ translate(pos) children();
+ }
+ }
+ }
+ }
+ }
}
@@ -554,24 +554,24 @@ module grid2d(spacing, n, size, stagger=false, inside=undef)
// grid3d(n=[10, 10, 10], spacing=50) color($idx/9) cube(50, center=true);
module grid3d(xa=[0], ya=[0], za=[0], n=undef, spacing=undef)
{
- n = scalar_vec3(n, 1);
- spacing = scalar_vec3(spacing, undef);
- if (!is_undef(n) && !is_undef(spacing)) {
- for (xi = [0:1:n.x-1]) {
- for (yi = [0:1:n.y-1]) {
- for (zi = [0:1:n.z-1]) {
- $idx = [xi,yi,zi];
- $pos = vmul(spacing, $idx - (n-[1,1,1])/2);
- translate($pos) children();
- }
- }
- }
- } else {
- for (xoff = xa, yoff = ya, zoff = za) {
- $pos = [xoff, yoff, zoff];
- translate($pos) children();
- }
- }
+ n = scalar_vec3(n, 1);
+ spacing = scalar_vec3(spacing, undef);
+ if (!is_undef(n) && !is_undef(spacing)) {
+ for (xi = [0:1:n.x-1]) {
+ for (yi = [0:1:n.y-1]) {
+ for (zi = [0:1:n.z-1]) {
+ $idx = [xi,yi,zi];
+ $pos = vmul(spacing, $idx - (n-[1,1,1])/2);
+ translate($pos) children();
+ }
+ }
+ }
+ } else {
+ for (xoff = xa, yoff = ya, zoff = za) {
+ $pos = [xoff, yoff, zoff];
+ translate($pos) children();
+ }
+ }
}
@@ -642,28 +642,28 @@ module grid3d(xa=[0], ya=[0], za=[0], n=undef, spacing=undef)
// color("red",0.333) yrot(90) cylinder(h=20, r1=5, r2=0);
module rot_copies(rots=[], v=undef, cp=[0,0,0], n=undef, sa=0, offset=0, delta=[0,0,0], subrot=true)
{
- sang = sa + offset;
- angs = !is_undef(n)?
- (n<=0? [] : [for (i=[0:1:n-1]) i/n*360+sang]) :
- rots==[]? [] :
- assert(!is_string(rots), "Argument rots must be an angle, a list of angles, or a range of angles.")
- assert(!is_undef(rots[0]), "Argument rots must be an angle, a list of angles, or a range of angles.")
- [for (a=rots) a];
- for ($idx = idx(angs)) {
- $ang = angs[$idx];
- $axis = v;
- translate(cp) {
- rotate(a=$ang, v=v) {
- translate(delta) {
- rot(a=(subrot? sang : $ang), v=v, reverse=true) {
- translate(-cp) {
- children();
- }
- }
- }
- }
- }
- }
+ sang = sa + offset;
+ angs = !is_undef(n)?
+ (n<=0? [] : [for (i=[0:1:n-1]) i/n*360+sang]) :
+ rots==[]? [] :
+ assert(!is_string(rots), "Argument rots must be an angle, a list of angles, or a range of angles.")
+ assert(!is_undef(rots[0]), "Argument rots must be an angle, a list of angles, or a range of angles.")
+ [for (a=rots) a];
+ for ($idx = idx(angs)) {
+ $ang = angs[$idx];
+ $axis = v;
+ translate(cp) {
+ rotate(a=$ang, v=v) {
+ translate(delta) {
+ rot(a=(subrot? sang : $ang), v=v, reverse=true) {
+ translate(-cp) {
+ children();
+ }
+ }
+ }
+ }
+ }
+ }
}
@@ -720,7 +720,7 @@ module rot_copies(rots=[], v=undef, cp=[0,0,0], n=undef, sa=0, offset=0, delta=[
// color("red",0.333) xrot(-90) cylinder(h=20, r1=5, r2=0, center=true);
module xrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
{
- rot_copies(rots=rots, v=RIGHT, cp=cp, n=n, sa=sa, delta=[0, r, 0], subrot=subrot) children();
+ rot_copies(rots=rots, v=RIGHT, cp=cp, n=n, sa=sa, delta=[0, r, 0], subrot=subrot) children();
}
@@ -777,7 +777,7 @@ module xrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
// color("red",0.333) yrot(-90) cylinder(h=20, r1=5, r2=0, center=true);
module yrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
{
- rot_copies(rots=rots, v=BACK, cp=cp, n=n, sa=sa, delta=[-r, 0, 0], subrot=subrot) children();
+ rot_copies(rots=rots, v=BACK, cp=cp, n=n, sa=sa, delta=[-r, 0, 0], subrot=subrot) children();
}
@@ -834,7 +834,7 @@ module yrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
// color("red",0.333) yrot(-90) cylinder(h=20, r1=5, r2=0, center=true);
module zrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
{
- rot_copies(rots=rots, v=UP, cp=cp, n=n, sa=sa, delta=[r, 0, 0], subrot=subrot) children();
+ rot_copies(rots=rots, v=UP, cp=cp, n=n, sa=sa, delta=[r, 0, 0], subrot=subrot) children();
}
@@ -880,27 +880,27 @@ module zrot_copies(rots=[], cp=[0,0,0], n=undef, sa=0, r=0, subrot=true)
// #cube(size=[10,3,3],center=true);
// arc_of(rx=20, ry=10, n=8) cube(size=[10,3,3],center=true);
module arc_of(
- n=6,
- r=undef, rx=undef, ry=undef,
- d=undef, dx=undef, dy=undef,
- sa=0, ea=360,
- rot=true
+ n=6,
+ r=undef, rx=undef, ry=undef,
+ d=undef, dx=undef, dy=undef,
+ sa=0, ea=360,
+ rot=true
) {
- rx = get_radius(r1=rx, r=r, d1=dx, d=d, dflt=1);
- ry = get_radius(r1=ry, r=r, d1=dy, d=d, dflt=1);
- sa = posmod(sa, 360);
- ea = posmod(ea, 360);
- n = (abs(ea-sa)<0.01)?(n+1):n;
- delt = (((ea<=sa)?360.0:0)+ea-sa)/(n-1);
- for ($idx = [0:1:n-1]) {
- $ang = sa + ($idx * delt);
- $pos =[rx*cos($ang), ry*sin($ang), 0];
- translate($pos) {
- zrot(rot? atan2(ry*sin($ang), rx*cos($ang)) : 0) {
- children();
- }
- }
- }
+ rx = get_radius(r1=rx, r=r, d1=dx, d=d, dflt=1);
+ ry = get_radius(r1=ry, r=r, d1=dy, d=d, dflt=1);
+ sa = posmod(sa, 360);
+ ea = posmod(ea, 360);
+ n = (abs(ea-sa)<0.01)?(n+1):n;
+ delt = (((ea<=sa)?360.0:0)+ea-sa)/(n-1);
+ for ($idx = [0:1:n-1]) {
+ $ang = sa + ($idx * delt);
+ $pos =[rx*cos($ang), ry*sin($ang), 0];
+ translate($pos) {
+ zrot(rot? atan2(ry*sin($ang), rx*cos($ang)) : 0) {
+ children();
+ }
+ }
+ }
}
@@ -938,29 +938,29 @@ module arc_of(
// cylinder(d=8, h=10, center=false);
module ovoid_spread(r=undef, d=undef, n=100, cone_ang=90, scale=[1,1,1], perp=true)
{
- r = get_radius(r=r, d=d, dflt=50);
- cnt = ceil(n / (cone_ang/180));
+ r = get_radius(r=r, d=d, dflt=50);
+ cnt = ceil(n / (cone_ang/180));
- // Calculate an array of [theta,phi] angles for `n` number of
- // points, almost evenly spaced across the surface of a sphere.
- // This approximation is based on the golden spiral method.
- theta_phis = [for (x=[0:1:n-1]) [180*(1+sqrt(5))*(x+0.5)%360, acos(1-2*(x+0.5)/cnt)]];
+ // Calculate an array of [theta,phi] angles for `n` number of
+ // points, almost evenly spaced across the surface of a sphere.
+ // This approximation is based on the golden spiral method.
+ theta_phis = [for (x=[0:1:n-1]) [180*(1+sqrt(5))*(x+0.5)%360, acos(1-2*(x+0.5)/cnt)]];
- for ($idx = idx(theta_phis)) {
- tp = theta_phis[$idx];
- xyz = spherical_to_xyz(r, tp[0], tp[1]);
- $pos = vmul(xyz,scale);
- $theta = tp[0];
- $phi = tp[1];
- $rad = r;
- translate($pos) {
- if (perp) {
- rot(from=UP, to=xyz) children();
- } else {
- children();
- }
- }
- }
+ for ($idx = idx(theta_phis)) {
+ tp = theta_phis[$idx];
+ xyz = spherical_to_xyz(r, tp[0], tp[1]);
+ $pos = vmul(xyz,scale);
+ $theta = tp[0];
+ $phi = tp[1];
+ $rad = r;
+ translate($pos) {
+ if (perp) {
+ rot(from=UP, to=xyz) children();
+ } else {
+ children();
+ }
+ }
+ }
}
@@ -1000,27 +1000,27 @@ module ovoid_spread(r=undef, d=undef, n=100, cone_ang=90, scale=[1,1,1], perp=tr
// color("blue",0.25) translate([0,-5,-5]) rot(from=UP, to=BACK+UP) cube([15,15,0.01], center=true);
module mirror_copy(v=[0,0,1], offset=0, cp)
{
- cp = is_vector(v,4)? plane_normal(v) * v[3] :
- is_vector(cp)? cp :
- is_num(cp)? cp*unit(v) :
- [0,0,0];
- nv = is_vector(v,4)? plane_normal(v) : unit(v);
- off = nv*offset;
- if (cp == [0,0,0]) {
- translate(off) {
- $orig = true;
- $idx = 0;
- children();
- }
- mirror(nv) translate(off) {
- $orig = false;
- $idx = 1;
- children();
- }
- } else {
- translate(off) children();
- translate(cp) mirror(nv) translate(-cp) translate(off) children();
- }
+ cp = is_vector(v,4)? plane_normal(v) * v[3] :
+ is_vector(cp)? cp :
+ is_num(cp)? cp*unit(v) :
+ [0,0,0];
+ nv = is_vector(v,4)? plane_normal(v) : unit(v);
+ off = nv*offset;
+ if (cp == [0,0,0]) {
+ translate(off) {
+ $orig = true;
+ $idx = 0;
+ children();
+ }
+ mirror(nv) translate(off) {
+ $orig = false;
+ $idx = 1;
+ children();
+ }
+ } else {
+ translate(off) children();
+ translate(cp) mirror(nv) translate(-cp) translate(off) children();
+ }
}
@@ -1053,7 +1053,7 @@ module mirror_copy(v=[0,0,1], offset=0, cp)
// color("blue",0.25) left(5) cube([0.01,15,15], center=true);
module xflip_copy(offset=0, x=0)
{
- mirror_copy(v=[1,0,0], offset=offset, cp=[x,0,0]) children();
+ mirror_copy(v=[1,0,0], offset=offset, cp=[x,0,0]) children();
}
@@ -1086,7 +1086,7 @@ module xflip_copy(offset=0, x=0)
// color("blue",0.25) fwd(5) cube([15,0.01,15], center=true);
module yflip_copy(offset=0, y=0)
{
- mirror_copy(v=[0,1,0], offset=offset, cp=[0,y,0]) children();
+ mirror_copy(v=[0,1,0], offset=offset, cp=[0,y,0]) children();
}
@@ -1119,9 +1119,9 @@ module yflip_copy(offset=0, y=0)
// color("blue",0.25) down(5) cube([15,15,0.01], center=true);
module zflip_copy(offset=0, z=0)
{
- mirror_copy(v=[0,0,1], offset=offset, cp=[0,0,z]) children();
+ mirror_copy(v=[0,0,1], offset=offset, cp=[0,0,z]) children();
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/edges.scad b/edges.scad
index c434455..2027151 100644
--- a/edges.scad
+++ b/edges.scad
@@ -68,34 +68,34 @@ function is_edge_array(v) = is_list(v) && is_vector(v[0]) && len(v)==3 && len(v[
function _edge_set(v) =
- is_edge_array(v)? v : [
- for (ax=[0:2]) [
- for (b=[-1,1], a=[-1,1]) let(
- v2=[[0,a,b],[a,0,b],[a,b,0]][ax]
- ) (
- is_string(v)? (
- v=="X"? (ax==0) : // Return all X axis aligned edges.
- v=="Y"? (ax==1) : // Return all Y axis aligned edges.
- v=="Z"? (ax==2) : // Return all Z axis aligned edges.
- v=="ALL"? true : // Return all edges.
- v=="NONE"? false : // Return no edges.
- let(valid_values = ["X", "Y", "Z", "ALL", "NONE"])
- assert(
- in_list(v, valid_values),
- str(v, " must be a vector, edge array, or one of ", valid_values)
- ) v
- ) :
- let(nonz = sum(vabs(v)))
- nonz==2? (v==v2) : // Edge: return matching edge.
- let(
- matches = count_true([
- for (i=[0:2]) v[i] && (v[i]==v2[i])
- ])
- )
- nonz==1? (matches==1) : // Face: return surrounding edges.
- (matches==2) // Corner: return touching edges.
- )? 1 : 0
- ]
+ is_edge_array(v)? v : [
+ for (ax=[0:2]) [
+ for (b=[-1,1], a=[-1,1]) let(
+ v2=[[0,a,b],[a,0,b],[a,b,0]][ax]
+ ) (
+ is_string(v)? (
+ v=="X"? (ax==0) : // Return all X axis aligned edges.
+ v=="Y"? (ax==1) : // Return all Y axis aligned edges.
+ v=="Z"? (ax==2) : // Return all Z axis aligned edges.
+ v=="ALL"? true : // Return all edges.
+ v=="NONE"? false : // Return no edges.
+ let(valid_values = ["X", "Y", "Z", "ALL", "NONE"])
+ assert(
+ in_list(v, valid_values),
+ str(v, " must be a vector, edge array, or one of ", valid_values)
+ ) v
+ ) :
+ let(nonz = sum(vabs(v)))
+ nonz==2? (v==v2) : // Edge: return matching edge.
+ let(
+ matches = count_true([
+ for (i=[0:2]) v[i] && (v[i]==v2[i])
+ ])
+ )
+ nonz==1? (matches==1) : // Face: return surrounding edges.
+ (matches==2) // Corner: return touching edges.
+ )? 1 : 0
+ ]
];
@@ -211,32 +211,32 @@ function normalize_edges(v) = [for (ax=v) [for (edge=ax) edge>0? 1 : 0]];
// Example: All edges, except Z-aligned edges on the front.
// edges("ALL", except=edges("Z", except=BACK))
function edges(v, except=[]) =
- (is_string(v) || is_vector(v) || is_edge_array(v))? edges([v], except=except) :
- (is_string(except) || is_vector(except) || is_edge_array(except))? edges(v, except=[except]) :
- except==[]? normalize_edges(sum([for (x=v) _edge_set(x)])) :
- normalize_edges(
- normalize_edges(sum([for (x=v) _edge_set(x)])) -
- sum([for (x=except) _edge_set(x)])
- );
+ (is_string(v) || is_vector(v) || is_edge_array(v))? edges([v], except=except) :
+ (is_string(except) || is_vector(except) || is_edge_array(except))? edges(v, except=[except]) :
+ except==[]? normalize_edges(sum([for (x=v) _edge_set(x)])) :
+ normalize_edges(
+ normalize_edges(sum([for (x=v) _edge_set(x)])) -
+ sum([for (x=except) _edge_set(x)])
+ );
EDGE_OFFSETS = [ // Array of XYZ offsets to the center of each edge.
- [
- [ 0,-1,-1],
- [ 0, 1,-1],
- [ 0,-1, 1],
- [ 0, 1, 1]
- ], [
- [-1, 0,-1],
- [ 1, 0,-1],
- [-1, 0, 1],
- [ 1, 0, 1]
- ], [
- [-1,-1, 0],
- [ 1,-1, 0],
- [-1, 1, 0],
- [ 1, 1, 0]
- ]
+ [
+ [ 0,-1,-1],
+ [ 0, 1,-1],
+ [ 0,-1, 1],
+ [ 0, 1, 1]
+ ], [
+ [-1, 0,-1],
+ [ 1, 0,-1],
+ [-1, 0, 1],
+ [ 1, 0, 1]
+ ], [
+ [-1,-1, 0],
+ [ 1,-1, 0],
+ [-1, 1, 0],
+ [ 1, 1, 0]
+ ]
];
@@ -267,21 +267,21 @@ function normalize_corners(v) = [for (x=v) x>0? 1 : 0];
function _corner_set(v) =
- is_corner_array(v)? v : [
- for (i=[0:7]) let(
- v2 = CORNER_OFFSETS[i]
- ) (
- is_string(v)? (
- v=="ALL"? true : // Return all corners.
- v=="NONE"? false : // Return no corners.
- let(valid_values = ["ALL", "NONE"])
- assert(
- in_list(v, valid_values),
- str(v, " must be a vector, corner array, or one of ", valid_values)
- ) v
- ) :
- all([for (i=[0:2]) !v[i] || (v[i]==v2[i])])
- )? 1 : 0
+ is_corner_array(v)? v : [
+ for (i=[0:7]) let(
+ v2 = CORNER_OFFSETS[i]
+ ) (
+ is_string(v)? (
+ v=="ALL"? true : // Return all corners.
+ v=="NONE"? false : // Return no corners.
+ let(valid_values = ["ALL", "NONE"])
+ assert(
+ in_list(v, valid_values),
+ str(v, " must be a vector, corner array, or one of ", valid_values)
+ ) v
+ ) :
+ all([for (i=[0:2]) !v[i] || (v[i]==v2[i])])
+ )? 1 : 0
];
@@ -370,18 +370,18 @@ function _corner_set(v) =
// Example: All corners around the bottom or front faces, except those on the bottom-front edge.
// corners([BOTTOM,FRONT], except=BOTTOM+FRONT)
function corners(v, except=[]) =
- (is_string(v) || is_vector(v) || is_corner_array(v))? corners([v], except=except) :
- (is_string(except) || is_vector(except) || is_corner_array(except))? corners(v, except=[except]) :
- except==[]? normalize_corners(sum([for (x=v) _corner_set(x)])) :
- let(
- a = normalize_corners(sum([for (x=v) _corner_set(x)])),
- b = normalize_corners(sum([for (x=except) _corner_set(x)]))
- ) normalize_corners(a - b);
+ (is_string(v) || is_vector(v) || is_corner_array(v))? corners([v], except=except) :
+ (is_string(except) || is_vector(except) || is_corner_array(except))? corners(v, except=[except]) :
+ except==[]? normalize_corners(sum([for (x=v) _corner_set(x)])) :
+ let(
+ a = normalize_corners(sum([for (x=v) _corner_set(x)])),
+ b = normalize_corners(sum([for (x=except) _corner_set(x)]))
+ ) normalize_corners(a - b);
CORNER_OFFSETS = [ // Array of XYZ offsets to each corner.
- [-1,-1,-1], [ 1,-1,-1], [-1, 1,-1], [ 1, 1,-1],
- [-1,-1, 1], [ 1,-1, 1], [-1, 1, 1], [ 1, 1, 1]
+ [-1,-1,-1], [ 1,-1,-1], [-1, 1,-1], [ 1, 1,-1],
+ [-1,-1, 1], [ 1,-1, 1], [-1, 1, 1], [ 1, 1, 1]
];
@@ -391,7 +391,7 @@ CORNER_OFFSETS = [ // Array of XYZ offsets to each corner.
// edges = Standard edges array.
// v = Vector pointing to the corner to count edge intersections at.
function corner_edge_count(edges, v) =
- let(u = (v+[1,1,1])/2) edges[0][u.y+u.z*2] + edges[1][u.x+u.z*2] + edges[2][u.x+u.y*2];
+ let(u = (v+[1,1,1])/2) edges[0][u.y+u.z*2] + edges[1][u.x+u.z*2] + edges[2][u.x+u.y*2];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/errors.scad b/errors.scad
index 4a3e009..8c174d9 100644
--- a/errors.scad
+++ b/errors.scad
@@ -35,11 +35,11 @@ module no_children(count) {
// msg = The message to print.
// pfx = The prefix to print before `msg`. Default: `ERROR`
module echo_error(msg, pfx="ERROR") {
- echo(str("", pfx, ": ", msg, "
"));
+ echo(str("", pfx, ": ", msg, "
"));
}
function echo_error(msg, pfx="ERROR") =
- echo(str("", pfx, ": ", msg, "
"));
+ echo(str("", pfx, ": ", msg, "
"));
// Function&Module: echo_warning()
@@ -52,11 +52,11 @@ function echo_error(msg, pfx="ERROR") =
// msg = The message to print.
// pfx = The prefix to print before `msg`. Default: `WARNING`
module echo_warning(msg, pfx="WARNING") {
- echo(str("", pfx, ": ", msg, "
"));
+ echo(str("", pfx, ": ", msg, "
"));
}
function echo_warning(msg, pfx="WARNING") =
- echo(str("", pfx, ": ", msg, "
"));
+ echo(str("", pfx, ": ", msg, "
"));
// Function&Module: deprecate()
@@ -69,25 +69,25 @@ function echo_warning(msg, pfx="WARNING") =
// name = The name of the module that is deprecated.
// suggest = If given, the module to recommend using instead.
module deprecate(name, suggest=undef) {
- echo_warning(pfx="DEPRECATED",
- str(
- "`", name, "
` is deprecated and should not be used.",
- is_undef(suggest)? "" : str(
- " You should use `", suggest, "
` instead."
- )
- )
- );
+ echo_warning(pfx="DEPRECATED",
+ str(
+ "`", name, "
` is deprecated and should not be used.",
+ is_undef(suggest)? "" : str(
+ " You should use `", suggest, "
` instead."
+ )
+ )
+ );
}
function deprecate(name, suggest=undef) =
- echo_warning(pfx="DEPRECATED",
- str(
- "`", name, "
` is deprecated and should not be used.",
- is_undef(suggest)? "" : str(
- " You should use `", suggest, "
` instead."
- )
- )
- );
+ echo_warning(pfx="DEPRECATED",
+ str(
+ "`", name, "
` is deprecated and should not be used.",
+ is_undef(suggest)? "" : str(
+ " You should use `", suggest, "
` instead."
+ )
+ )
+ );
// Function&Module: deprecate_argument()
@@ -101,26 +101,26 @@ function deprecate(name, suggest=undef) =
// arg = The name of the deprecated argument.
// suggest = If given, the argument to recommend using instead.
module deprecate_argument(name, arg, suggest=undef) {
- echo_warning(pfx="DEPRECATED ARG", str(
- "In `", name, "
`, ",
- "the argument `", arg, "
` ",
- "is deprecated and should not be used.",
- is_undef(suggest)? "" : str(
- " You should use `", suggest, "
` instead."
- )
- ));
+ echo_warning(pfx="DEPRECATED ARG", str(
+ "In `", name, "
`, ",
+ "the argument `", arg, "
` ",
+ "is deprecated and should not be used.",
+ is_undef(suggest)? "" : str(
+ " You should use `", suggest, "
` instead."
+ )
+ ));
}
function deprecate_argument(name, arg, suggest=undef) =
- echo_warning(pfx="DEPRECATED ARG", str(
- "In `", name, "
`, ",
- "the argument `", arg, "
` ",
- "is deprecated and should not be used.",
- is_undef(suggest)? "" : str(
- " You should use `", suggest, "
` instead."
- )
- ));
+ echo_warning(pfx="DEPRECATED ARG", str(
+ "In `", name, "
`, ",
+ "the argument `", arg, "
` ",
+ "is deprecated and should not be used.",
+ is_undef(suggest)? "" : str(
+ " You should use `", suggest, "
` instead."
+ )
+ ));
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/attachments.scad b/examples/attachments.scad
index 238b3c1..8c8a4e6 100644
--- a/examples/attachments.scad
+++ b/examples/attachments.scad
@@ -4,15 +4,15 @@ include
$fn=32;
cuboid([60,40,40], rounding=5, edges=edges("Z"), anchor=BOTTOM) {
- attach(TOP, BOTTOM) prismoid([60,40],[20,20], h=50, rounding1=5, rounding2=10) {
- attach(TOP) cylinder(d=20, h=30, center=false) {
- attach(TOP) cylinder(d1=50, d2=30, h=12, center=false);
- }
- attach([FRONT, BACK, LEFT, RIGHT]) cylinder(d1=14, d2=5, h=20) {
- attach(TOP, LEFT, overlap=5) prismoid([30,20], [20,20], h=10, shift=[-7,0]);
- }
- }
+ attach(TOP, BOTTOM) prismoid([60,40],[20,20], h=50, rounding1=5, rounding2=10) {
+ attach(TOP) cylinder(d=20, h=30, center=false) {
+ attach(TOP) cylinder(d1=50, d2=30, h=12, center=false);
+ }
+ attach([FRONT, BACK, LEFT, RIGHT]) cylinder(d1=14, d2=5, h=20) {
+ attach(TOP, LEFT, overlap=5) prismoid([30,20], [20,20], h=10, shift=[-7,0]);
+ }
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/bezier_patches.scad b/examples/bezier_patches.scad
index 03941e4..de7042b 100644
--- a/examples/bezier_patches.scad
+++ b/examples/bezier_patches.scad
@@ -3,75 +3,75 @@ include
function CR_corner(size, spin=0, orient=UP, trans=[0,0,0]) =
- let (
- // This patch might not yet correct for continuous rounding,
- // but it's a first approximation proof of concept.
- a = 0.68,
- b = 0.60,
- c = 0.24,
- patch = [
- [[0,1,1], [0,a,1], [0,c,1], [c,0,1], [a,0,1], [1,0,1]],
- [[0,1,a], [0,b,b], [0,0,b], [b,0,b], [1,0,a]],
- [[0,1,c], [0,b,0], [b,0,0], [1,0,c]],
- [[c,1,0], [b,b,0], [1,c,0]],
- [[a,1,0], [1,a,0]],
- [[1,1,0]],
- ]
- )
- translate(trans,
- p=rot(a=spin, from=UP, to=orient,
- p=scale(size, patch)
- )
- );
+ let (
+ // This patch might not yet correct for continuous rounding,
+ // but it's a first approximation proof of concept.
+ a = 0.68,
+ b = 0.60,
+ c = 0.24,
+ patch = [
+ [[0,1,1], [0,a,1], [0,c,1], [c,0,1], [a,0,1], [1,0,1]],
+ [[0,1,a], [0,b,b], [0,0,b], [b,0,b], [1,0,a]],
+ [[0,1,c], [0,b,0], [b,0,0], [1,0,c]],
+ [[c,1,0], [b,b,0], [1,c,0]],
+ [[a,1,0], [1,a,0]],
+ [[1,1,0]],
+ ]
+ )
+ translate(trans,
+ p=rot(a=spin, from=UP, to=orient,
+ p=scale(size, patch)
+ )
+ );
function CR_edge(size, spin=0, orient=UP, trans=[0,0,0]) =
- let (
- // This patch might not be correct for continuous rounding,
- // but it's a first approximation proof of concept.
- vvals = [1.00, 0.68, 0.24],
- xyvals = [
- for (x=vvals) [x,0],
- for (y=reverse(vvals)) [0,y]
- ],
- zvals = [-0.5:0.2:0.5],
- patch = [for (xy=xyvals) [for (z=zvals) [each xy, z]]]
- )
- translate(trans,
- p=rot(a=spin, from=UP, to=orient,
- p=scale(size, p=patch)
- )
- );
+ let (
+ // This patch might not be correct for continuous rounding,
+ // but it's a first approximation proof of concept.
+ vvals = [1.00, 0.68, 0.24],
+ xyvals = [
+ for (x=vvals) [x,0],
+ for (y=reverse(vvals)) [0,y]
+ ],
+ zvals = [-0.5:0.2:0.5],
+ patch = [for (xy=xyvals) [for (z=zvals) [each xy, z]]]
+ )
+ translate(trans,
+ p=rot(a=spin, from=UP, to=orient,
+ p=scale(size, p=patch)
+ )
+ );
module CR_cube(size=[100,100,100], r=10, splinesteps=8, debug=false)
{
- s = size-2*[r,r,r];
- h = size/2;
- corner_pat = CR_corner([r,r,r], trans=[-size.x/2, -size.y/2, -size.z/2]);
- edge_pat = CR_edge([r, r, s.z], trans=[-h.x, -h.y, 0]);
- face_pat = bezier_patch_flat([s.x, s.z], N=1, orient=FRONT, trans=[0, -h.y, 0]);
- corners = bezier_surface([
- for (yr=[0,180], zr=[0:90:270]) let(
- m = yrot(yr) * zrot(zr)
- ) [for (row=corner_pat) apply(m, row)]
- ], splinesteps=splinesteps);
- edges = bezier_surface([
- for (axr=[[0,0,0],[90,0,0],[0,90,0]],zr=[0:90:270]) let(
- m = rot(axr) * zrot(zr)
- ) [for (row=edge_pat) apply(m, row)]
- ], splinesteps=[splinesteps,1]);
- faces = bezier_surface([
- for (axr=[0,90,180,270,[-90,0,0],[90,0,0]]) let(
- m = rot(axr)
- ) [for (row=face_pat) apply(m, row)]
- ], splinesteps=1);
+ s = size-2*[r,r,r];
+ h = size/2;
+ corner_pat = CR_corner([r,r,r], trans=[-size.x/2, -size.y/2, -size.z/2]);
+ edge_pat = CR_edge([r, r, s.z], trans=[-h.x, -h.y, 0]);
+ face_pat = bezier_patch_flat([s.x, s.z], N=1, orient=FRONT, trans=[0, -h.y, 0]);
+ corners = bezier_surface([
+ for (yr=[0,180], zr=[0:90:270]) let(
+ m = yrot(yr) * zrot(zr)
+ ) [for (row=corner_pat) apply(m, row)]
+ ], splinesteps=splinesteps);
+ edges = bezier_surface([
+ for (axr=[[0,0,0],[90,0,0],[0,90,0]],zr=[0:90:270]) let(
+ m = rot(axr) * zrot(zr)
+ ) [for (row=edge_pat) apply(m, row)]
+ ], splinesteps=[splinesteps,1]);
+ faces = bezier_surface([
+ for (axr=[0,90,180,270,[-90,0,0],[90,0,0]]) let(
+ m = rot(axr)
+ ) [for (row=face_pat) apply(m, row)]
+ ], splinesteps=1);
- if (debug) {
- vnf_validate([edges, faces, corners], convexity=4);
- } else {
- vnf_polyhedron([edges, faces, corners], convexity=4);
- }
+ if (debug) {
+ vnf_validate([edges, faces, corners], convexity=4);
+ } else {
+ vnf_polyhedron([edges, faces, corners], convexity=4);
+ }
}
@@ -80,4 +80,4 @@ cube(1);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/boolean_geometry.scad b/examples/boolean_geometry.scad
index 23615d6..1e7190f 100644
--- a/examples/boolean_geometry.scad
+++ b/examples/boolean_geometry.scad
@@ -4,15 +4,15 @@ include
$fn = 36;
rgn1 = [
- square(100),
- move([50,50], p=circle(d=60)),
- [[35,35],[35,65],[65,65]]
+ square(100),
+ move([50,50], p=circle(d=60)),
+ [[35,35],[35,65],[65,65]]
];
rgn2 = [
- [[0,0], [100,100], [100,0]],
- [[27,10], [90,73], [90,10]],
- move([70,30], p=circle(d=25))
+ [[0,0], [100,100], [100,0]],
+ [[27,10], [90,73], [90,10]],
+ move([70,30], p=circle(d=25))
];
@@ -21,29 +21,29 @@ outlinecolor="black";
module showit(label, rgn, poly=polycolor, outline=outlinecolor, width=0.5) {
- move([-50,-50]) {
- if(outline) color(outline) linear_extrude(height=max(0.1,1-width)) for(path=rgn) stroke(path, width=width, closed=true);
- if(poly) color(poly) linear_extrude(height=0.1) region(rgn);
- color("black") right(50) fwd(7) linear_extrude(height=0.1) text(text=label, size=8, halign="center", valign="center");
- }
+ move([-50,-50]) {
+ if(outline) color(outline) linear_extrude(height=max(0.1,1-width)) for(path=rgn) stroke(path, width=width, closed=true);
+ if(poly) color(poly) linear_extrude(height=0.1) region(rgn);
+ color("black") right(50) fwd(7) linear_extrude(height=0.1) text(text=label, size=8, halign="center", valign="center");
+ }
}
ydistribute(-125) {
- xdistribute(120) {
- showit("Region A", rgn1, poly=[1,0,0,0.5]);
- showit("Region B", rgn2, poly=[0,0,1,0.5]);
- union() {
- showit("A and B Overlaid", rgn1, poly=[1,0,0,0.5]);
- showit("", rgn2, poly=[0,0,1,0.5]);
- }
- }
- xdistribute(120) {
- showit("Union A+B", union(rgn1, rgn2));
- showit("Difference A-B", difference(rgn1, rgn2));
- showit("Intersection A&B", intersection(rgn1, rgn2));
- showit("Exclusive OR A^B", exclusive_or(rgn1, rgn2));
- }
+ xdistribute(120) {
+ showit("Region A", rgn1, poly=[1,0,0,0.5]);
+ showit("Region B", rgn2, poly=[0,0,1,0.5]);
+ union() {
+ showit("A and B Overlaid", rgn1, poly=[1,0,0,0.5]);
+ showit("", rgn2, poly=[0,0,1,0.5]);
+ }
+ }
+ xdistribute(120) {
+ showit("Union A+B", union(rgn1, rgn2));
+ showit("Difference A-B", difference(rgn1, rgn2));
+ showit("Intersection A&B", intersection(rgn1, rgn2));
+ showit("Exclusive OR A^B", exclusive_or(rgn1, rgn2));
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/conical_anchors.scad b/examples/conical_anchors.scad
index 5067d4b..42e9de3 100644
--- a/examples/conical_anchors.scad
+++ b/examples/conical_anchors.scad
@@ -5,4 +5,4 @@ include
cylinder(h=30, d1=50, d2=30) show_anchors();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/cube_anchors.scad b/examples/cube_anchors.scad
index da4f242..db122de 100644
--- a/examples/cube_anchors.scad
+++ b/examples/cube_anchors.scad
@@ -5,4 +5,4 @@ include
cube(40, center=true) show_anchors();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/cubic_sphere_packing.scad b/examples/cubic_sphere_packing.scad
index a529250..3a782d0 100644
--- a/examples/cubic_sphere_packing.scad
+++ b/examples/cubic_sphere_packing.scad
@@ -6,8 +6,8 @@ include
s = 20;
s2 = s * sin(45);
zcopies(s2,n=8) union()
- grid2d([s2,s2],n=8,stagger=($idx%2)? true : "alt")
- sphere(d=s);
+ grid2d([s2,s2],n=8,stagger=($idx%2)? true : "alt")
+ sphere(d=s);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/cylinder_anchors.scad b/examples/cylinder_anchors.scad
index 6787502..1c3d605 100644
--- a/examples/cylinder_anchors.scad
+++ b/examples/cylinder_anchors.scad
@@ -5,4 +5,4 @@ include
cylinder(h=30, d=30) show_anchors();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/fractal_tree.scad b/examples/fractal_tree.scad
index 5ef423e..ea1f07d 100644
--- a/examples/fractal_tree.scad
+++ b/examples/fractal_tree.scad
@@ -1,17 +1,17 @@
include
module tree(l=1500, sc=0.7, depth=10)
- recolor("lightgray")
- cylinder(l=l, d1=l/5, d2=l/5*sc)
- attach(TOP)
- if (depth>0)
- zrot(90)
- zrot_copies(n=2)
- yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
- else
- recolor("springgreen")
- yscale(0.67)
- teardrop(d=l*3, l=1, anchor=BOT, spin=90);
+ recolor("lightgray")
+ cylinder(l=l, d1=l/5, d2=l/5*sc)
+ attach(TOP)
+ if (depth>0)
+ zrot(90)
+ zrot_copies(n=2)
+ yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
+ else
+ recolor("springgreen")
+ yscale(0.67)
+ teardrop(d=l*3, l=1, anchor=BOT, spin=90);
tree();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/hex_sphere_packing.scad b/examples/hex_sphere_packing.scad
index baa3983..c36d31e 100644
--- a/examples/hex_sphere_packing.scad
+++ b/examples/hex_sphere_packing.scad
@@ -7,9 +7,9 @@ s = 20;
xyr = adj_ang_to_hyp(s/2,30);
h = hyp_adj_to_opp(s,xyr);
zcopies(h,n=8) union()
- back(($idx%2)*xyr*cos(60))
- grid2d(s,n=[12,7],stagger=($idx%2)? "alt" : true)
- sphere(d=s);
+ back(($idx%2)*xyr*cos(60))
+ grid2d(s,n=[12,7],stagger=($idx%2)? "alt" : true)
+ sphere(d=s);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/lsystems.scad b/examples/lsystems.scad
index d9d9734..1d3dd1c 100644
--- a/examples/lsystems.scad
+++ b/examples/lsystems.scad
@@ -1,46 +1,46 @@
include
function _lsystem_recurse(s, rules, lev) =
- lev<=0? s : _lsystem_recurse([
- for (
- i = 0,
- slen = len(s),
- sout = "";
+ lev<=0? s : _lsystem_recurse([
+ for (
+ i = 0,
+ slen = len(s),
+ sout = "";
- i <= slen;
+ i <= slen;
- ch = s[i],
- found = search([ch], rules)[0],
- sout = str(sout, i==slen? "" : found==[]? ch : rules[found][1]),
- i = i + 1
- ) if (i==slen) sout
- ][0], rules, lev-1);
+ ch = s[i],
+ found = search([ch], rules)[0],
+ sout = str(sout, i==slen? "" : found==[]? ch : rules[found][1]),
+ i = i + 1
+ ) if (i==slen) sout
+ ][0], rules, lev-1);
function _lsystem_to_turtle(s, step=1, angle=90, startang=0) =
- concat(
- startang? ["left", startang] : [],
- ["angle", angle, "length", step],
- [
- for (
- i = 0,
- slen = len(s);
+ concat(
+ startang? ["left", startang] : [],
+ ["angle", angle, "length", step],
+ [
+ for (
+ i = 0,
+ slen = len(s);
- i <= slen;
+ i <= slen;
- ch = s[i],
- cmd = (ch=="A" || ch=="B" || ch=="F")? ["move"] :
- (ch=="+")? ["left"] :
- (ch=="-")? ["right"] :
- [],
- i=i+1
- ) if(i>0 && cmd!=[]) each cmd
- ]
- );
+ ch = s[i],
+ cmd = (ch=="A" || ch=="B" || ch=="F")? ["move"] :
+ (ch=="+")? ["left"] :
+ (ch=="-")? ["right"] :
+ [],
+ i=i+1
+ ) if(i>0 && cmd!=[]) each cmd
+ ]
+ );
function lsystem_turtle(basis, rules, levels=5, step=1, angle=90, startang=0) =
- turtle(_lsystem_to_turtle(_lsystem_recurse(basis, rules, levels), step=step, angle=angle, startang=startang));
+ turtle(_lsystem_to_turtle(_lsystem_recurse(basis, rules, levels), step=step, angle=angle, startang=startang));
function dragon_curve (levels=9, step=1) = lsystem_turtle(levels=levels, step=step, angle=90, "FX", [["X", "X+YF+"], ["Y", "-FX-Y"]]);
@@ -67,4 +67,4 @@ points = hilbert_curve(levels=5, step=100/pow(2,5));
stroke(points, width=1);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/orientations.scad b/examples/orientations.scad
index 2a55d6d..8e7b96a 100644
--- a/examples/orientations.scad
+++ b/examples/orientations.scad
@@ -18,10 +18,10 @@ module orient_cube(ang) {
color(axiscolors.z) back((20-1)/2+0.01) right((20-1)/2+0.01) cube([1,1,18], center=true);
for (axis=[0:2], neg=[0:1]) {
idx = axis + 3*neg;
- labels = [
- "RIGHT", "BACK", "UP",
- "LEFT", "FWD", "DOWN"
- ];
+ labels = [
+ "RIGHT", "BACK", "UP",
+ "LEFT", "FWD", "DOWN"
+ ];
rot(ang, from=UP, to=orientations[idx]) {
up(10) {
back(4) color("black") text3d(text=str("spin=",ang), size=2.5);
@@ -42,34 +42,34 @@ module text3d(text, h=0.01, size=3) {
module dottedline(l, d) for(y = [0:d*3:l]) up(y) sphere(d=d);
module orient_cubes() {
- // X axis
- color(axiscolors[0]) {
- yrot( 90) cylinder(h=axislen, d=axisdiam, center=false);
- right(axislbllen) rot([90,0,0]) text3d(text="X+");
- yrot(-90) dottedline(l=axislen, d=axisdiam);
- left(axislbllen) rot([90,0,180]) text3d(text="X-");
- }
- // Y axis
- color(axiscolors[1]) {
- xrot(-90) cylinder(h=axislen, d=axisdiam, center=false);
- back(axislbllen) rot([90,0,90]) text3d(text="Y+");
- xrot( 90) dottedline(l=axislen, d=axisdiam);
- fwd(axislbllen) rot([90,0,-90]) text3d(text="Y-");
- }
- // Z axis
- color(axiscolors[2]) {
- cylinder(h=axislen, d=axisdiam, center=false);
- up(axislbllen) rot([0,-90,90+$vpr[2]]) text3d(text="Z+");
- xrot(180) dottedline(l=axislen, d=axisdiam);
- down(axislbllen) rot([0,90,-90+$vpr[2]]) text3d(text="Z-");
- }
+ // X axis
+ color(axiscolors[0]) {
+ yrot( 90) cylinder(h=axislen, d=axisdiam, center=false);
+ right(axislbllen) rot([90,0,0]) text3d(text="X+");
+ yrot(-90) dottedline(l=axislen, d=axisdiam);
+ left(axislbllen) rot([90,0,180]) text3d(text="X-");
+ }
+ // Y axis
+ color(axiscolors[1]) {
+ xrot(-90) cylinder(h=axislen, d=axisdiam, center=false);
+ back(axislbllen) rot([90,0,90]) text3d(text="Y+");
+ xrot( 90) dottedline(l=axislen, d=axisdiam);
+ fwd(axislbllen) rot([90,0,-90]) text3d(text="Y-");
+ }
+ // Z axis
+ color(axiscolors[2]) {
+ cylinder(h=axislen, d=axisdiam, center=false);
+ up(axislbllen) rot([0,-90,90+$vpr[2]]) text3d(text="Z+");
+ xrot(180) dottedline(l=axislen, d=axisdiam);
+ down(axislbllen) rot([0,90,-90+$vpr[2]]) text3d(text="Z-");
+ }
- for (ang = [0:90:270]) {
- off = rot(p=40*BACK,ang);
- translate(off) {
- orient_cube(ang);
- }
- }
+ for (ang = [0:90:270]) {
+ off = rot(p=40*BACK,ang);
+ translate(off) {
+ orient_cube(ang);
+ }
+ }
}
@@ -77,4 +77,4 @@ orient_cubes();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/prismoid_anchors.scad b/examples/prismoid_anchors.scad
index 0adfe98..7bf4fc4 100644
--- a/examples/prismoid_anchors.scad
+++ b/examples/prismoid_anchors.scad
@@ -5,4 +5,4 @@ include
prismoid([60,40], [30,20], h=40) show_anchors();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/randomized_fractal_tree.scad b/examples/randomized_fractal_tree.scad
index c3d2592..5dd6f87 100644
--- a/examples/randomized_fractal_tree.scad
+++ b/examples/randomized_fractal_tree.scad
@@ -3,46 +3,46 @@ include
include
module leaf(s) {
- path = [
- [0,0], [1.5,-1],
- [2,1], [0,3], [-2,1],
- [-1.5,-1], [0,0]
- ];
- xrot(90)
- linear_sweep_bezier(
- path * s/2,
- height=0.02
- );
+ path = [
+ [0,0], [1.5,-1],
+ [2,1], [0,3], [-2,1],
+ [-1.5,-1], [0,0]
+ ];
+ xrot(90)
+ linear_sweep_bezier(
+ path * s/2,
+ height=0.02
+ );
}
module branches(minsize, s1, s2){
if(s2>minsize) {
- attach(TOP)
- zrot(gaussian_rands(90,20)[0])
- zrot_copies(n=floor(log_rands(2,5,4)[0]))
- zrot(gaussian_rands(0,5)[0])
- yrot(gaussian_rands(30,10)[0]) {
- sc = gaussian_rands(0.7,0.05)[0];
- cylinder(d1=s2, d2=s2*sc, l=s1)
- branches(minsize, s1*sc, s2*sc);
- }
- } else {
- recolor("springgreen")
- attach(TOP) zrot(90)
- leaf(gaussian_rands(100,5)[0]);
- }
+ attach(TOP)
+ zrot(gaussian_rands(90,20)[0])
+ zrot_copies(n=floor(log_rands(2,5,4)[0]))
+ zrot(gaussian_rands(0,5)[0])
+ yrot(gaussian_rands(30,10)[0]) {
+ sc = gaussian_rands(0.7,0.05)[0];
+ cylinder(d1=s2, d2=s2*sc, l=s1)
+ branches(minsize, s1*sc, s2*sc);
+ }
+ } else {
+ recolor("springgreen")
+ attach(TOP) zrot(90)
+ leaf(gaussian_rands(100,5)[0]);
+ }
}
module tree(h, d, minsize) {
- sc = gaussian_rands(0.7,0.05)[0];
- recolor("lightgray") {
- cylinder(d1=d, d2=d*sc, l=h) {
- branches(minsize, h, d*sc);
- }
- }
+ sc = gaussian_rands(0.7,0.05)[0];
+ recolor("lightgray") {
+ cylinder(d1=d, d2=d*sc, l=h) {
+ branches(minsize, h, d*sc);
+ }
+ }
}
tree(d=300, h=1500, minsize=10);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/screw_anchors.scad b/examples/screw_anchors.scad
index 1bb2164..76d4eff 100644
--- a/examples/screw_anchors.scad
+++ b/examples/screw_anchors.scad
@@ -10,4 +10,4 @@ metric_bolt(headtype="oval", size=10, l=15, shank=5, details=true, phillips="#2"
show_anchors(5, std=false);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/sphere_anchors.scad b/examples/sphere_anchors.scad
index 03dfe22..b1fc43a 100644
--- a/examples/sphere_anchors.scad
+++ b/examples/sphere_anchors.scad
@@ -5,4 +5,4 @@ include
spheroid(d=30) show_anchors();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/spherical_patch.scad b/examples/spherical_patch.scad
index de07293..8cc2307 100644
--- a/examples/spherical_patch.scad
+++ b/examples/spherical_patch.scad
@@ -8,13 +8,13 @@ p = s * d;
q = s * 0.55 * d;
u = s * 2.5 * UP;
patch1 = [
- [p[2], p[2]+q[3], p[3]+q[2], p[3] ],
- [p[2]+q[1], p[2]+q[2]+u, p[3]+q[3]+u, p[3]+q[0]],
- [p[1]+q[2], p[1]+q[1]+u, p[0]+q[0]+u, p[0]+q[3]],
- [p[1], p[1]+q[0], p[0]+q[1], p[0] ],
+ [p[2], p[2]+q[3], p[3]+q[2], p[3] ],
+ [p[2]+q[1], p[2]+q[2]+u, p[3]+q[3]+u, p[3]+q[0]],
+ [p[1]+q[2], p[1]+q[1]+u, p[0]+q[0]+u, p[0]+q[3]],
+ [p[1], p[1]+q[0], p[0]+q[1], p[0] ],
];
patch2 = patch_reverse(zflip(p=patch1));
trace_bezier_patches([patch1, patch2], splinesteps=16, style="quincunx");
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/tagged_diff.scad b/examples/tagged_diff.scad
index 23879d6..bbb41f0 100644
--- a/examples/tagged_diff.scad
+++ b/examples/tagged_diff.scad
@@ -3,13 +3,13 @@ include
diff("hole", "body pole")
sphere(d=100, $tags="body") {
- zcyl(d=55, h=100, $tags="pole"); // attach() not needed for center-to-center.
- tags("hole") {
- xcyl(d=55, h=101);
- ycyl(d=55, h=101);
- }
- zcyl(d=15, h=140, $tags="axle");
+ zcyl(d=55, h=100, $tags="pole"); // attach() not needed for center-to-center.
+ tags("hole") {
+ xcyl(d=55, h=101);
+ ycyl(d=55, h=101);
+ }
+ zcyl(d=15, h=140, $tags="axle");
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/geometry.scad b/geometry.scad
index 09882a7..b5f4c29 100644
--- a/geometry.scad
+++ b/geometry.scad
@@ -21,10 +21,10 @@
// edge = Array of two points forming the line segment to test against.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function point_on_segment2d(point, edge, eps=EPSILON) =
- approx(point,edge[0],eps=eps) || approx(point,edge[1],eps=eps) || // The point is an endpoint
- sign(edge[0].x-point.x)==sign(point.x-edge[1].x) // point is in between the
- && sign(edge[0].y-point.y)==sign(point.y-edge[1].y) // edge endpoints
- && approx(point_left_of_segment2d(point, edge),0,eps=eps); // and on the line defined by edge
+ approx(point,edge[0],eps=eps) || approx(point,edge[1],eps=eps) || // The point is an endpoint
+ sign(edge[0].x-point.x)==sign(point.x-edge[1].x) // point is in between the
+ && sign(edge[0].y-point.y)==sign(point.y-edge[1].y) // edge endpoints
+ && approx(point_left_of_segment2d(point, edge),0,eps=eps); // and on the line defined by edge
// Function: point_left_of_segment2d()
@@ -38,16 +38,16 @@ function point_on_segment2d(point, edge, eps=EPSILON) =
// point = The point to check position of.
// edge = Array of two points forming the line segment to test against.
function point_left_of_segment2d(point, edge) =
- (edge[1].x-edge[0].x) * (point.y-edge[0].y) - (point.x-edge[0].x) * (edge[1].y-edge[0].y);
+ (edge[1].x-edge[0].x) * (point.y-edge[0].y) - (point.x-edge[0].x) * (edge[1].y-edge[0].y);
// Internal non-exposed function.
function _point_above_below_segment(point, edge) =
- edge[0].y <= point.y? (
- (edge[1].y > point.y && point_left_of_segment2d(point, edge) > 0)? 1 : 0
- ) : (
- (edge[1].y <= point.y && point_left_of_segment2d(point, edge) < 0)? -1 : 0
- );
+ edge[0].y <= point.y? (
+ (edge[1].y > point.y && point_left_of_segment2d(point, edge) > 0)? 1 : 0
+ ) : (
+ (edge[1].y <= point.y && point_left_of_segment2d(point, edge) < 0)? -1 : 0
+ );
// Function: collinear()
@@ -61,8 +61,8 @@ function _point_above_below_segment(point, edge) =
// c = Third point.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function collinear(a, b, c, eps=EPSILON) =
- approx(a,b,eps=eps)? true :
- distance_from_line([a,b], c) < eps;
+ approx(a,b,eps=eps)? true :
+ distance_from_line([a,b], c) < eps;
// Function: collinear_indexed()
@@ -77,11 +77,11 @@ function collinear(a, b, c, eps=EPSILON) =
// c = Index in `points` of third point.
// eps = Acceptable max angle variance. Default: EPSILON (1e-9) degrees.
function collinear_indexed(points, a, b, c, eps=EPSILON) =
- let(
- p1=points[a],
- p2=points[b],
- p3=points[c]
- ) collinear(p1, p2, p3, eps);
+ let(
+ p1=points[a],
+ p2=points[b],
+ p3=points[c]
+ ) collinear(p1, p2, p3, eps);
// Function: points_are_collinear()
@@ -93,12 +93,12 @@ function collinear_indexed(points, a, b, c, eps=EPSILON) =
// points = The list of points to test.
// eps = How much variance is allowed in testing that each point is on the same line. Default: `EPSILON` (1e-9)
function points_are_collinear(points, eps=EPSILON) =
- let(
- a = furthest_point(points[0], points),
- b = furthest_point(points[a], points),
- pa = points[a],
- pb = points[b]
- ) all([for (pt = points) collinear(pa, pb, pt, eps=eps)]);
+ let(
+ a = furthest_point(points[0], points),
+ b = furthest_point(points[a], points),
+ pa = points[a],
+ pb = points[b]
+ ) all([for (pt = points) collinear(pa, pb, pt, eps=eps)]);
// Function: distance_from_line()
@@ -112,8 +112,8 @@ function points_are_collinear(points, eps=EPSILON) =
// Example:
// distance_from_line([[-10,0], [10,0]], [3,8]); // Returns: 8
function distance_from_line(line, pt) =
- let(a=line[0], n=unit(line[1]-a), d=a-pt)
- norm(d - ((d * n) * n));
+ let(a=line[0], n=unit(line[1]-a), d=a-pt)
+ norm(d - ((d * n) * n));
// Function: line_normal()
@@ -133,8 +133,8 @@ function distance_from_line(line, pt) =
// color("green") stroke([p1,p1+10*n], endcap2="arrow2");
// color("blue") move_copies([p1,p2]) circle(d=2, $fn=12);
function line_normal(p1,p2) =
- is_undef(p2)? line_normal(p1[0],p1[1]) :
- unit([p1.y-p2.y,p2.x-p1.x]);
+ is_undef(p2)? line_normal(p1[0],p1[1]) :
+ unit([p1.y-p2.y,p2.x-p1.x]);
// 2D Line intersection from two segments.
@@ -146,12 +146,12 @@ function line_normal(p1,p2) =
// the intersection lies on the segment. Otherwise it lies somewhere on
// the extension of the segment. Result is undef for coincident lines.
function _general_line_intersection(s1,s2,eps=EPSILON) =
- let(
- denominator = det2([s1[0],s2[0]]-[s1[1],s2[1]])
- ) approx(denominator,0,eps=eps)? [undef,undef,undef] : let(
- t = det2([s1[0],s2[0]]-s2) / denominator,
- u = det2([s1[0],s1[0]]-[s2[0],s1[1]]) / denominator
- ) [s1[0]+t*(s1[1]-s1[0]), t, u];
+ let(
+ denominator = det2([s1[0],s2[0]]-[s1[1],s2[1]])
+ ) approx(denominator,0,eps=eps)? [undef,undef,undef] : let(
+ t = det2([s1[0],s2[0]]-s2) / denominator,
+ u = det2([s1[0],s1[0]]-[s2[0],s1[1]]) / denominator
+ ) [s1[0]+t*(s1[1]-s1[0]), t, u];
// Function: line_intersection()
@@ -165,7 +165,7 @@ function _general_line_intersection(s1,s2,eps=EPSILON) =
// l2 = Second 2D line, given as a list of two 2D points on the line.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function line_intersection(l1,l2,eps=EPSILON) =
- let(isect = _general_line_intersection(l1,l2,eps=eps)) isect[0];
+ let(isect = _general_line_intersection(l1,l2,eps=eps)) isect[0];
// Function: line_ray_intersection()
@@ -179,9 +179,9 @@ function line_intersection(l1,l2,eps=EPSILON) =
// ray = The 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function line_ray_intersection(line,ray,eps=EPSILON) =
- let(
- isect = _general_line_intersection(line,ray,eps=eps)
- ) isect[2]<0-eps? undef : isect[0];
+ let(
+ isect = _general_line_intersection(line,ray,eps=eps)
+ ) isect[2]<0-eps? undef : isect[0];
// Function: line_segment_intersection()
@@ -195,9 +195,9 @@ function line_ray_intersection(line,ray,eps=EPSILON) =
// segment = The bounded 2D line segment, given as a list of the two 2D endpoints of the segment.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function line_segment_intersection(line,segment,eps=EPSILON) =
- let(
- isect = _general_line_intersection(line,segment,eps=eps)
- ) isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
+ let(
+ isect = _general_line_intersection(line,segment,eps=eps)
+ ) isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
// Function: ray_intersection()
@@ -211,9 +211,9 @@ function line_segment_intersection(line,segment,eps=EPSILON) =
// r2 = Second 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function ray_intersection(r1,r2,eps=EPSILON) =
- let(
- isect = _general_line_intersection(r1,r2,eps=eps)
- ) isect[1]<0-eps || isect[2]<0-eps? undef : isect[0];
+ let(
+ isect = _general_line_intersection(r1,r2,eps=eps)
+ ) isect[1]<0-eps || isect[2]<0-eps? undef : isect[0];
// Function: ray_segment_intersection()
@@ -227,9 +227,9 @@ function ray_intersection(r1,r2,eps=EPSILON) =
// segment = The bounded 2D line segment, given as a list of the two 2D endpoints of the segment.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function ray_segment_intersection(ray,segment,eps=EPSILON) =
- let(
- isect = _general_line_intersection(ray,segment,eps=eps)
- ) isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
+ let(
+ isect = _general_line_intersection(ray,segment,eps=eps)
+ ) isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
// Function: segment_intersection()
@@ -243,9 +243,9 @@ function ray_segment_intersection(ray,segment,eps=EPSILON) =
// s2 = Second 2D segment, given as a list of the two 2D endpoints of the line segment.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function segment_intersection(s1,s2,eps=EPSILON) =
- let(
- isect = _general_line_intersection(s1,s2,eps=eps)
- ) isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
+ let(
+ isect = _general_line_intersection(s1,s2,eps=eps)
+ ) isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[0];
// Function: line_closest_point()
@@ -257,10 +257,10 @@ function segment_intersection(s1,s2,eps=EPSILON) =
// line = A list of two points that are on the unbounded line.
// pt = The point to find the closest point on the line to.
function line_closest_point(line,pt) =
- let(
- n = line_normal(line),
- isect = _general_line_intersection(line,[pt,pt+n])
- ) isect[0];
+ let(
+ n = line_normal(line),
+ isect = _general_line_intersection(line,[pt,pt+n])
+ ) isect[0];
// Function: segment_closest_point()
@@ -272,14 +272,14 @@ function line_closest_point(line,pt) =
// 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.
function segment_closest_point(seg,pt) =
- let(
- n = line_normal(seg),
- isect = _general_line_intersection(seg,[pt,pt+n])
- )
- norm(n)==0? seg[0] :
- isect[1]<=0? seg[0] :
- isect[1]>=1? seg[1] :
- isect[0];
+ let(
+ n = line_normal(seg),
+ isect = _general_line_intersection(seg,[pt,pt+n])
+ )
+ norm(n)==0? seg[0] :
+ isect[1]<=0? seg[0] :
+ isect[1]>=1? seg[1] :
+ isect[0];
// Section: 2D Triangles
@@ -327,23 +327,23 @@ function segment_closest_point(seg,pt) =
// ang = tri_calc(adj=20,hyp=30)[3];
// ang2 = tri_calc(adj=20,hyp=40)[4];
function tri_calc(ang,ang2,adj,opp,hyp) =
- assert(ang==undef || ang2==undef,"You cannot specify both ang and ang2.")
- assert(num_defined([ang,ang2,adj,opp,hyp])==2, "You must specify exactly two arguments.")
- let(
- ang = ang!=undef? assert(ang>0&&ang<90) ang :
- ang2!=undef? (90-ang2) :
- adj==undef? asin(constrain(opp/hyp,-1,1)) :
- opp==undef? acos(constrain(adj/hyp,-1,1)) :
- atan2(opp,adj),
- ang2 = ang2!=undef? assert(ang2>0&&ang2<90) ang2 : (90-ang),
- adj = adj!=undef? assert(adj>0) adj :
- (opp!=undef? (opp/tan(ang)) : (hyp*cos(ang))),
- opp = opp!=undef? assert(opp>0) opp :
- (adj!=undef? (adj*tan(ang)) : (hyp*sin(ang))),
- hyp = hyp!=undef? assert(hyp>0) assert(adj0&&ang<90) ang :
+ ang2!=undef? (90-ang2) :
+ adj==undef? asin(constrain(opp/hyp,-1,1)) :
+ opp==undef? acos(constrain(adj/hyp,-1,1)) :
+ atan2(opp,adj),
+ ang2 = ang2!=undef? assert(ang2>0&&ang2<90) ang2 : (90-ang),
+ adj = adj!=undef? assert(adj>0) adj :
+ (opp!=undef? (opp/tan(ang)) : (hyp*cos(ang))),
+ opp = opp!=undef? assert(opp>0) opp :
+ (adj!=undef? (adj*tan(ang)) : (hyp*sin(ang))),
+ hyp = hyp!=undef? assert(hyp>0) assert(adj=0)
- assert(is_num(opp)&&opp>=0)
- sqrt(hyp*hyp-opp*opp);
+ assert(is_num(hyp)&&hyp>=0)
+ assert(is_num(opp)&&opp>=0)
+ sqrt(hyp*hyp-opp*opp);
// Function: hyp_ang_to_adj()
@@ -375,9 +375,9 @@ function hyp_opp_to_adj(hyp,opp) =
// Example:
// adj = hyp_ang_to_adj(8,60); // Returns: 4
function hyp_ang_to_adj(hyp,ang) =
- assert(is_num(hyp)&&hyp>=0)
- assert(is_num(ang)&&ang>0&&ang<90)
- hyp*cos(ang);
+ assert(is_num(hyp)&&hyp>=0)
+ assert(is_num(ang)&&ang>0&&ang<90)
+ hyp*cos(ang);
// Function: opp_ang_to_adj()
@@ -392,9 +392,9 @@ function hyp_ang_to_adj(hyp,ang) =
// Example:
// adj = opp_ang_to_adj(8,30); // Returns: 4
function opp_ang_to_adj(opp,ang) =
- assert(is_num(opp)&&opp>=0)
- assert(is_num(ang)&&ang>0&&ang<90)
- opp/tan(ang);
+ assert(is_num(opp)&&opp>=0)
+ assert(is_num(ang)&&ang>0&&ang<90)
+ opp/tan(ang);
// Function: hyp_adj_to_opp()
@@ -408,9 +408,9 @@ function opp_ang_to_adj(opp,ang) =
// Example:
// opp = hyp_adj_to_opp(5,4); // Returns: 3
function hyp_adj_to_opp(hyp,adj) =
- assert(is_num(hyp)&&hyp>=0)
- assert(is_num(adj)&&adj>=0)
- sqrt(hyp*hyp-adj*adj);
+ assert(is_num(hyp)&&hyp>=0)
+ assert(is_num(adj)&&adj>=0)
+ sqrt(hyp*hyp-adj*adj);
// Function: hyp_ang_to_opp()
@@ -424,9 +424,9 @@ function hyp_adj_to_opp(hyp,adj) =
// Example:
// opp = hyp_ang_to_opp(8,30); // Returns: 4
function hyp_ang_to_opp(hyp,ang) =
- assert(is_num(hyp)&&hyp>=0)
- assert(is_num(ang)&&ang>0&&ang<90)
- hyp*sin(ang);
+ assert(is_num(hyp)&&hyp>=0)
+ assert(is_num(ang)&&ang>0&&ang<90)
+ hyp*sin(ang);
// Function: adj_ang_to_opp()
@@ -440,9 +440,9 @@ function hyp_ang_to_opp(hyp,ang) =
// Example:
// opp = adj_ang_to_opp(8,45); // Returns: 8
function adj_ang_to_opp(adj,ang) =
- assert(is_num(adj)&&adj>=0)
- assert(is_num(ang)&&ang>0&&ang<90)
- adj*tan(ang);
+ assert(is_num(adj)&&adj>=0)
+ assert(is_num(ang)&&ang>0&&ang<90)
+ adj*tan(ang);
// Function: adj_opp_to_hyp()
@@ -456,9 +456,9 @@ function adj_ang_to_opp(adj,ang) =
// Example:
// hyp = adj_opp_to_hyp(3,4); // Returns: 5
function adj_opp_to_hyp(adj,opp) =
- assert(is_num(adj)&&adj>=0)
- assert(is_num(opp)&&opp>=0)
- norm([opp,adj]);
+ assert(is_num(adj)&&adj>=0)
+ assert(is_num(opp)&&opp>=0)
+ norm([opp,adj]);
// Function: adj_ang_to_hyp()
@@ -472,9 +472,9 @@ function adj_opp_to_hyp(adj,opp) =
// Example:
// hyp = adj_ang_to_hyp(4,60); // Returns: 8
function adj_ang_to_hyp(adj,ang) =
- assert(is_num(adj)&&adj>=0)
- assert(is_num(ang)&&ang>=0&&ang<90)
- adj/cos(ang);
+ assert(is_num(adj)&&adj>=0)
+ assert(is_num(ang)&&ang>=0&&ang<90)
+ adj/cos(ang);
// Function: opp_ang_to_hyp()
@@ -488,9 +488,9 @@ function adj_ang_to_hyp(adj,ang) =
// Example:
// hyp = opp_ang_to_hyp(4,30); // Returns: 8
function opp_ang_to_hyp(opp,ang) =
- assert(is_num(opp)&&opp>=0)
- assert(is_num(ang)&&ang>0&&ang<=90)
- opp/sin(ang);
+ assert(is_num(opp)&&opp>=0)
+ assert(is_num(ang)&&ang>0&&ang<=90)
+ opp/sin(ang);
// Function: hyp_adj_to_ang()
@@ -504,9 +504,9 @@ function opp_ang_to_hyp(opp,ang) =
// Example:
// ang = hyp_adj_to_ang(8,4); // Returns: 60 degrees
function hyp_adj_to_ang(hyp,adj) =
- assert(is_num(hyp)&&hyp>0)
- assert(is_num(adj)&&adj>=0)
- acos(adj/hyp);
+ assert(is_num(hyp)&&hyp>0)
+ assert(is_num(adj)&&adj>=0)
+ acos(adj/hyp);
// Function: hyp_opp_to_ang()
@@ -520,9 +520,9 @@ function hyp_adj_to_ang(hyp,adj) =
// Example:
// ang = hyp_opp_to_ang(8,4); // Returns: 30 degrees
function hyp_opp_to_ang(hyp,opp) =
- assert(is_num(hyp)&&hyp>0)
- assert(is_num(opp)&&opp>=0)
- asin(opp/hyp);
+ assert(is_num(hyp)&&hyp>0)
+ assert(is_num(opp)&&opp>=0)
+ asin(opp/hyp);
// Function: adj_opp_to_ang()
@@ -536,9 +536,9 @@ function hyp_opp_to_ang(hyp,opp) =
// Example:
// ang = adj_opp_to_ang(sqrt(3)/2,0.5); // Returns: 30 degrees
function adj_opp_to_ang(adj,opp) =
- assert(is_num(adj)&&adj>=0)
- assert(is_num(opp)&&opp>=0)
- atan2(opp,adj);
+ assert(is_num(adj)&&adj>=0)
+ assert(is_num(opp)&&opp>=0)
+ atan2(opp,adj);
// Function: triangle_area()
@@ -551,11 +551,11 @@ function adj_opp_to_ang(adj,opp) =
// triangle_area([0,0], [5,10], [10,0]); // Returns -50
// triangle_area([10,0], [5,10], [0,0]); // Returns 50
function triangle_area(a,b,c) =
- len(a)==3? 0.5*norm(cross(c-a,c-b)) : (
- a.x * (b.y - c.y) +
- b.x * (c.y - a.y) +
- c.x * (a.y - b.y)
- ) / 2;
+ len(a)==3? 0.5*norm(cross(c-a,c-b)) : (
+ a.x * (b.y - c.y) +
+ b.x * (c.y - a.y) +
+ c.x * (a.y - b.y)
+ ) / 2;
@@ -572,12 +572,12 @@ function triangle_area(a,b,c) =
// p2 = The second point on the plane.
// p3 = The third point on the plane.
function plane3pt(p1, p2, p3) =
- let(
- p1=point3d(p1),
- p2=point3d(p2),
- p3=point3d(p3),
- normal = unit(cross(p3-p1, p2-p1))
- ) concat(normal, [normal*p1]);
+ let(
+ p1=point3d(p1),
+ p2=point3d(p2),
+ p3=point3d(p3),
+ normal = unit(cross(p3-p1, p2-p1))
+ ) concat(normal, [normal*p1]);
// Function: plane3pt_indexed()
@@ -594,11 +594,11 @@ function plane3pt(p1, p2, p3) =
// i2 = The index into `points` of the second point on the plane.
// i3 = The index into `points` of the third point on the plane.
function plane3pt_indexed(points, i1, i2, i3) =
- let(
- p1 = points[i1],
- p2 = points[i2],
- p3 = points[i3]
- ) plane3pt(p1,p2,p3);
+ let(
+ p1 = points[i1],
+ p2 = points[i2],
+ p3 = points[i3]
+ ) plane3pt(p1,p2,p3);
// Function: plane_from_normal()
@@ -632,17 +632,17 @@ function plane_from_normal(normal, pt=[0,0,0]) =
// cp = centroid(xyzpath);
// move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow();
function plane_from_points(points, fast=false, eps=EPSILON) =
- let(
- points = deduplicate(points),
- indices = sort(find_noncollinear_points(points)),
- p1 = points[indices[0]],
- p2 = points[indices[1]],
- p3 = points[indices[2]],
- plane = plane3pt(p1,p2,p3),
- all_coplanar = fast || all([
- for (pt = points) coplanar(plane,pt,eps=eps)
- ])
- ) all_coplanar? plane : undef;
+ let(
+ points = deduplicate(points),
+ indices = sort(find_noncollinear_points(points)),
+ p1 = points[indices[0]],
+ p2 = points[indices[1]],
+ p3 = points[indices[2]],
+ plane = plane3pt(p1,p2,p3),
+ all_coplanar = fast || all([
+ for (pt = points) coplanar(plane,pt,eps=eps)
+ ])
+ ) all_coplanar? plane : undef;
// Function: plane_from_polygon()
@@ -665,17 +665,17 @@ function plane_from_points(points, fast=false, eps=EPSILON) =
// cp = centroid(xyzpath);
// move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow();
function plane_from_polygon(poly, fast=false, eps=EPSILON) =
- let(
- poly = deduplicate(poly),
- n = polygon_normal(poly),
- plane = [n.x, n.y, n.z, n*poly[0]]
- ) fast? plane : let(
- all_coplanar = [
- for (pt = poly)
- if (!coplanar(plane,pt,eps=eps)) 1
- ] == []
- ) all_coplanar? plane :
- undef;
+ let(
+ poly = deduplicate(poly),
+ n = polygon_normal(poly),
+ plane = [n.x, n.y, n.z, n*poly[0]]
+ ) fast? plane : let(
+ all_coplanar = [
+ for (pt = poly)
+ if (!coplanar(plane,pt,eps=eps)) 1
+ ] == []
+ ) all_coplanar? plane :
+ undef;
// Function: plane_normal()
@@ -713,10 +713,10 @@ function plane_offset(plane) = plane[3];
// #stroke(xyzpath,closed=true);
// stroke(xypath,closed=true);
function plane_transform(plane) =
- let(
- n = plane_normal(plane),
- cp = n * plane[3]
- ) rot(from=n, to=UP) * move(-cp);
+ let(
+ n = plane_normal(plane),
+ cp = n * plane[3]
+ ) rot(from=n, to=UP) * move(-cp);
// Function: plane_point_nearest_origin()
@@ -725,7 +725,7 @@ function plane_transform(plane) =
// Description:
// Returns the point on the plane that is closest to the origin.
function plane_point_nearest_origin(plane) =
- plane_normal(plane) * plane[3];
+ plane_normal(plane) * plane[3];
// Function: distance_from_plane()
@@ -742,7 +742,7 @@ function plane_point_nearest_origin(plane) =
// plane = The [A,B,C,D] values for the equation of the plane.
// point = The point to test.
function distance_from_plane(plane, point) =
- [plane.x, plane.y, plane.z] * point3d(point) - plane[3];
+ [plane.x, plane.y, plane.z] * point3d(point) - plane[3];
// Function: closest_point_on_plane()
@@ -755,31 +755,31 @@ function distance_from_plane(plane, point) =
// plane = The [A,B,C,D] values for the equation of the plane.
// point = The 3D point to find the closest point to.
function closest_point_on_plane(plane, point) =
- let(
- n = unit(plane_normal(plane)),
- d = distance_from_plane(plane, point)
- ) point - n*d;
+ let(
+ n = unit(plane_normal(plane)),
+ d = distance_from_plane(plane, point)
+ ) point - n*d;
// Returns [POINT, U] if line intersects plane at one point.
// Returns [LINE, undef] if the line is on the plane.
// Returns undef if line is parallel to, but not on the given plane.
function _general_plane_line_intersection(plane, line, eps=EPSILON) =
- let(
- p0 = line[0],
- p1 = line[1],
- n = plane_normal(plane),
- u = p1 - p0,
- d = n * u
- ) abs(d)1? undef :
- res[0];
+ assert(is_vector(plane)&&len(plane)==4, "Invalid plane value.")
+ assert(is_path(line)&&len(line)==2, "Invalid line value.")
+ assert(!approx(line[0],line[1]), "The two points defining the line must not be the same point.")
+ let(
+ bounded = is_list(bounded)? bounded : [bounded, bounded],
+ res = _general_plane_line_intersection(plane, line, eps=eps)
+ )
+ is_undef(res)? undef :
+ is_undef(res[1])? res[0] :
+ bounded[0]&&res[1]<0? undef :
+ bounded[1]&&res[1]>1? undef :
+ res[0];
// Function: polygon_line_intersection()
@@ -839,47 +839,47 @@ function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) =
// bounded = If false, the line is considered unbounded. If true, it is treated as a bounded line segment. If given as `[true, false]` or `[false, true]`, the boundedness of the points are specified individually, allowing the line to be treated as a half-bounded ray. Default: false (unbounded)
// eps = The epsilon error value to determine whether the line is too close to parallel to the plane. Default: `EPSILON` (1e-9)
function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) =
- assert(is_path(poly))
- assert(is_path(line)&&len(line)==2)
- let(
- bounded = is_list(bounded)? bounded : [bounded, bounded],
- poly = deduplicate(poly),
- indices = sort(find_noncollinear_points(poly)),
- p1 = poly[indices[0]],
- p2 = poly[indices[1]],
- p3 = poly[indices[2]],
- plane = plane3pt(p1,p2,p3),
- res = _general_plane_line_intersection(plane, line, eps=eps)
- )
- is_undef(res)? undef :
- is_undef(res[1])? (
- let(
- // Line is on polygon plane.
- linevec = unit(line[1] - line[0]),
- lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec,
- lp2 = line[1] + (bounded[1]? 0 : 1000000) * linevec,
- poly2d = clockwise_polygon(project_plane(poly, p1, p2, p3)),
- line2d = project_plane([lp1,lp2], p1, p2, p3),
- parts = split_path_at_region_crossings(line2d, [poly2d], closed=false),
- inside = [
- for (part = parts)
- if (point_in_polygon(mean(part), poly2d)>0) part
- ]
- ) !inside? undef :
- let(
- isegs = [
- for (seg = inside)
- lift_plane(seg, p1, p2, p3)
- ]
- ) isegs
- ) :
- bounded[0]&&res[1]<0? undef :
- bounded[1]&&res[1]>1? undef :
- let(
- proj = clockwise_polygon(project_plane(poly, p1, p2, p3)),
- pt = project_plane(res[0], p1, p2, p3)
- ) point_in_polygon(pt, proj) < 0? undef :
- res[0];
+ assert(is_path(poly))
+ assert(is_path(line)&&len(line)==2)
+ let(
+ bounded = is_list(bounded)? bounded : [bounded, bounded],
+ poly = deduplicate(poly),
+ indices = sort(find_noncollinear_points(poly)),
+ p1 = poly[indices[0]],
+ p2 = poly[indices[1]],
+ p3 = poly[indices[2]],
+ plane = plane3pt(p1,p2,p3),
+ res = _general_plane_line_intersection(plane, line, eps=eps)
+ )
+ is_undef(res)? undef :
+ is_undef(res[1])? (
+ let(
+ // Line is on polygon plane.
+ linevec = unit(line[1] - line[0]),
+ lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec,
+ lp2 = line[1] + (bounded[1]? 0 : 1000000) * linevec,
+ poly2d = clockwise_polygon(project_plane(poly, p1, p2, p3)),
+ line2d = project_plane([lp1,lp2], p1, p2, p3),
+ parts = split_path_at_region_crossings(line2d, [poly2d], closed=false),
+ inside = [
+ for (part = parts)
+ if (point_in_polygon(mean(part), poly2d)>0) part
+ ]
+ ) !inside? undef :
+ let(
+ isegs = [
+ for (seg = inside)
+ lift_plane(seg, p1, p2, p3)
+ ]
+ ) isegs
+ ) :
+ bounded[0]&&res[1]<0? undef :
+ bounded[1]&&res[1]>1? undef :
+ let(
+ proj = clockwise_polygon(project_plane(poly, p1, p2, p3)),
+ pt = project_plane(res[0], p1, p2, p3)
+ ) point_in_polygon(pt, proj) < 0? undef :
+ res[0];
// Function: plane_intersection()
@@ -891,19 +891,19 @@ function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) =
// is returned as a list of two points on the line of intersection. If any of the input planes are parallel
// then returns undef.
function plane_intersection(plane1,plane2,plane3) =
- is_def(plane3)? let(
- matrix = [for(p=[plane1,plane2,plane3]) select(p,0,2)],
- rhs = [for(p=[plane1,plane2,plane3]) p[3]]
- ) linear_solve(matrix,rhs) :
- let(
- normal = cross(plane_normal(plane1), plane_normal(plane2))
- ) approx(norm(normal),0) ? undef :
- let(
- matrix = [for(p=[plane1,plane2]) select(p,0,2)],
- rhs = [for(p=[plane1,plane2]) p[3]],
- point = linear_solve(matrix,rhs)
- ) is_undef(point)? undef :
- [point, point+normal];
+ is_def(plane3)? let(
+ matrix = [for(p=[plane1,plane2,plane3]) select(p,0,2)],
+ rhs = [for(p=[plane1,plane2,plane3]) p[3]]
+ ) linear_solve(matrix,rhs) :
+ let(
+ normal = cross(plane_normal(plane1), plane_normal(plane2))
+ ) approx(norm(normal),0) ? undef :
+ let(
+ matrix = [for(p=[plane1,plane2]) select(p,0,2)],
+ rhs = [for(p=[plane1,plane2]) p[3]],
+ point = linear_solve(matrix,rhs)
+ ) is_undef(point)? undef :
+ [point, point+normal];
// Function: coplanar()
@@ -918,7 +918,7 @@ function plane_intersection(plane1,plane2,plane3) =
// point = The point to test.
// eps = How much variance is allowed in testing that each point is on the same plane. Default: `EPSILON` (1e-9)
function coplanar(plane, point, eps=EPSILON) =
- abs(distance_from_plane(plane, point)) <= eps;
+ abs(distance_from_plane(plane, point)) <= eps;
// Function: points_are_coplanar()
@@ -930,10 +930,10 @@ function coplanar(plane, point, eps=EPSILON) =
// points = The list of points to test.
// eps = How much variance is allowed in testing that each point is on the same plane. Default: `EPSILON` (1e-9)
function points_are_coplanar(points, eps=EPSILON) =
- points_are_collinear(points, eps=eps)? true :
- let(
- plane = plane_from_points(points, fast=true, eps=eps)
- ) all([for (pt = points) coplanar(plane, pt, eps=eps)]);
+ points_are_collinear(points, eps=eps)? true :
+ let(
+ plane = plane_from_points(points, fast=true, eps=eps)
+ ) all([for (pt = points) coplanar(plane, pt, eps=eps)]);
@@ -949,7 +949,7 @@ function points_are_coplanar(points, eps=EPSILON) =
// plane = The [A,B,C,D] values for the equation of the plane.
// point = The point to test.
function in_front_of_plane(plane, point) =
- distance_from_plane(plane, point) > EPSILON;
+ distance_from_plane(plane, point) > EPSILON;
@@ -995,27 +995,27 @@ function in_front_of_plane(plane, point) =
// labels = [[pts[0], "pt1"], [pts[1],"pt2"], [pts[2],"pt3"], [circ[0], "CP"], [circ[0]+[cos(315),sin(315)]*rad*0.7, "r"]];
// for(l=labels) translate(l[0]+[0,2]) color("black") text(text=l[1], size=2.5, halign="center");
function find_circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
- let(r = get_radius(r=r, d=d, dflt=undef))
- assert(r!=undef, "Must specify either r or d.")
- (is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_2tangents(pt1[0], pt1[1], pt1[2], r=r) :
- collinear(pt1, pt2, pt3)? undef :
- let(
- v1 = unit(pt1 - pt2),
- v2 = unit(pt3 - pt2),
- vmid = unit(mean([v1, v2])),
- n = vector_axis(v1, v2),
- a = vector_angle(v1, v2),
- hyp = r / sin(a/2),
- cp = pt2 + hyp * vmid
- ) !tangents? [cp, n] :
- let(
- x = hyp * cos(a/2),
- tp1 = pt2 + x * v1,
- tp2 = pt2 + x * v2,
- fff=echo(tp1=tp1,cp=cp,pt2=pt2),
- dang1 = vector_angle(tp1-cp,pt2-cp),
- dang2 = vector_angle(tp2-cp,pt2-cp)
- ) [cp, n, tp1, tp2, dang1, dang2];
+ let(r = get_radius(r=r, d=d, dflt=undef))
+ assert(r!=undef, "Must specify either r or d.")
+ (is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_2tangents(pt1[0], pt1[1], pt1[2], r=r) :
+ collinear(pt1, pt2, pt3)? undef :
+ let(
+ v1 = unit(pt1 - pt2),
+ v2 = unit(pt3 - pt2),
+ vmid = unit(mean([v1, v2])),
+ n = vector_axis(v1, v2),
+ a = vector_angle(v1, v2),
+ hyp = r / sin(a/2),
+ cp = pt2 + hyp * vmid
+ ) !tangents? [cp, n] :
+ let(
+ x = hyp * cos(a/2),
+ tp1 = pt2 + x * v1,
+ tp2 = pt2 + x * v2,
+ fff=echo(tp1=tp1,cp=cp,pt2=pt2),
+ dang1 = vector_angle(tp1-cp,pt2-cp),
+ dang2 = vector_angle(tp2-cp,pt2-cp)
+ ) [cp, n, tp1, tp2, dang1, dang2];
// Function: find_circle_3points()
@@ -1039,34 +1039,34 @@ function find_circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
// translate(circ[0]) color("red") circle(d=3, $fn=12);
// move_copies(pts) color("blue") circle(d=3, $fn=12);
function find_circle_3points(pt1, pt2, pt3) =
- (is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_3points(pt1[0], pt1[1], pt1[2]) :
- collinear(pt1,pt2,pt3)? [undef,undef,undef] :
- let(
- v1 = pt1-pt2,
- v2 = pt3-pt2,
- n = vector_axis(v1,v2),
- n2 = n.z<0? -n : n
- ) len(pt1)+len(pt2)+len(pt3)>6? (
- let(
- a = project_plane(pt1, pt1, pt2, pt3),
- b = project_plane(pt2, pt1, pt2, pt3),
- c = project_plane(pt3, pt1, pt2, pt3),
- res = find_circle_3points(a, b, c)
- ) res[0]==undef? [undef,undef,undef] : let(
- cp = lift_plane(res[0], pt1, pt2, pt3),
- r = norm(pt2-cp)
- ) [cp, r, n2]
- ) : let(
- mp1 = pt2 + v1/2,
- mp2 = pt2 + v2/2,
- mpv1 = rot(90, v=n, p=v1),
- mpv2 = rot(90, v=n, p=v2),
- l1 = [mp1, mp1+mpv1],
- l2 = [mp2, mp2+mpv2],
- isect = line_intersection(l1,l2)
- ) is_undef(isect)? [undef,undef,undef] : let(
- r = norm(pt2-isect)
- ) [isect, r, n2];
+ (is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_3points(pt1[0], pt1[1], pt1[2]) :
+ collinear(pt1,pt2,pt3)? [undef,undef,undef] :
+ let(
+ v1 = pt1-pt2,
+ v2 = pt3-pt2,
+ n = vector_axis(v1,v2),
+ n2 = n.z<0? -n : n
+ ) len(pt1)+len(pt2)+len(pt3)>6? (
+ let(
+ a = project_plane(pt1, pt1, pt2, pt3),
+ b = project_plane(pt2, pt1, pt2, pt3),
+ c = project_plane(pt3, pt1, pt2, pt3),
+ res = find_circle_3points(a, b, c)
+ ) res[0]==undef? [undef,undef,undef] : let(
+ cp = lift_plane(res[0], pt1, pt2, pt3),
+ r = norm(pt2-cp)
+ ) [cp, r, n2]
+ ) : let(
+ mp1 = pt2 + v1/2,
+ mp2 = pt2 + v2/2,
+ mpv1 = rot(90, v=n, p=v1),
+ mpv2 = rot(90, v=n, p=v2),
+ l1 = [mp1, mp1+mpv1],
+ l2 = [mp2, mp2+mpv2],
+ isect = line_intersection(l1,l2)
+ ) is_undef(isect)? [undef,undef,undef] : let(
+ r = norm(pt2-isect)
+ ) [isect, r, n2];
@@ -1089,20 +1089,20 @@ function find_circle_3points(pt1, pt2, pt3) =
// color("red") move_copies(tanpts) circle(d=3,$fn=12);
// color("blue") move_copies([cp,pt]) circle(d=3,$fn=12);
function circle_point_tangents(r, d, cp, pt) =
- assert(is_num(r) || is_num(d))
- assert(is_vector(cp))
- assert(is_vector(pt))
- let(
- r = get_radius(r=r, d=d, dflt=1),
- delta = pt - cp,
- dist = norm(delta),
- baseang = atan2(delta.y,delta.x)
- ) dist < r? [] :
- approx(dist,r)? [[baseang, pt]] :
- let(
- relang = acos(r/dist),
- angs = [baseang + relang, baseang - relang]
- ) [for (ang=angs) [ang, cp + r*[cos(ang),sin(ang)]]];
+ assert(is_num(r) || is_num(d))
+ assert(is_vector(cp))
+ assert(is_vector(pt))
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ delta = pt - cp,
+ dist = norm(delta),
+ baseang = atan2(delta.y,delta.x)
+ ) dist < r? [] :
+ approx(dist,r)? [[baseang, pt]] :
+ let(
+ relang = acos(r/dist),
+ angs = [baseang + relang, baseang - relang]
+ ) [for (ang=angs) [ang, cp + r*[cos(ang),sin(ang)]]];
@@ -1192,7 +1192,7 @@ function circle_circle_tangents(c1,r1,c2,r2,d1,d2) =
// i2 = The second point.
// points = The list of points to find a non-collinear point from.
function first_noncollinear(i1, i2, points) =
- [for (j = idx(points)) if (j!=i1 && j!=i2 && !collinear_indexed(points,i1,i2,j)) j][0];
+ [for (j = idx(points)) if (j!=i1 && j!=i2 && !collinear_indexed(points,i1,i2,j)) j][0];
// Function: find_noncollinear_points()
@@ -1201,20 +1201,20 @@ function first_noncollinear(i1, i2, points) =
// Description:
// Finds the indices of three good non-collinear points from the points list `points`.
function find_noncollinear_points(points) =
- let(
- a = 0,
- b = furthest_point(points[a], points),
- pa = points[a],
- pb = points[b],
- c = max_index([
- for (p=points)
- (approx(p,pa) || approx(p,pb))? 0 :
- sin(vector_angle(points[a]-p,points[b]-p)) *
- norm(p-points[a]) * norm(p-points[b])
- ])
- )
- assert(c!=a && c!=b, "Cannot find three noncollinear points in pointlist.")
- [a, b, c];
+ let(
+ a = 0,
+ b = furthest_point(points[a], points),
+ pa = points[a],
+ pb = points[b],
+ c = max_index([
+ for (p=points)
+ (approx(p,pa) || approx(p,pb))? 0 :
+ sin(vector_angle(points[a]-p,points[b]-p)) *
+ norm(p-points[a]) * norm(p-points[b])
+ ])
+ )
+ assert(c!=a && c!=b, "Cannot find three noncollinear points in pointlist.")
+ [a, b, c];
// Function: pointlist_bounds()
@@ -1226,8 +1226,8 @@ function find_noncollinear_points(points) =
// Arguments:
// pts = List of points.
function pointlist_bounds(pts) = [
- [for (a=[0:2]) min([ for (x=pts) point3d(x)[a] ]) ],
- [for (a=[0:2]) max([ for (x=pts) point3d(x)[a] ]) ]
+ [for (a=[0:2]) min([ for (x=pts) point3d(x)[a] ]) ],
+ [for (a=[0:2]) max([ for (x=pts) point3d(x)[a] ]) ]
];
@@ -1240,7 +1240,7 @@ function pointlist_bounds(pts) = [
// pt = The point to find the closest point to.
// points = The list of points to search.
function closest_point(pt, points) =
- min_index([for (p=points) norm(p-pt)]);
+ min_index([for (p=points) norm(p-pt)]);
// Function: furthest_point()
@@ -1252,7 +1252,7 @@ function closest_point(pt, points) =
// pt = The point to find the farthest point from.
// points = The list of points to search.
function furthest_point(pt, points) =
- max_index([for (p=points) norm(p-pt)]);
+ max_index([for (p=points) norm(p-pt)]);
@@ -1264,16 +1264,16 @@ function furthest_point(pt, points) =
// Description:
// Given a 2D or 3D planar polygon, returns the area of that polygon. If the polygon is self-crossing, the results are undefined.
function polygon_area(poly) =
- len(poly)<3? 0 :
- len(poly[0])==2? 0.5*sum([for(i=[0:1:len(poly)-1]) det2(select(poly,i,i+1))]) :
- let(
- plane = plane_from_points(poly)
- ) plane==undef? undef :
- let(
- n = unit(plane_normal(plane)),
- total = sum([for (i=[0:1:len(poly)-1]) cross(poly[i], select(poly,i+1))]),
- res = abs(total * n) / 2
- ) res;
+ len(poly)<3? 0 :
+ len(poly[0])==2? 0.5*sum([for(i=[0:1:len(poly)-1]) det2(select(poly,i,i+1))]) :
+ let(
+ plane = plane_from_points(poly)
+ ) plane==undef? undef :
+ let(
+ n = unit(plane_normal(plane)),
+ total = sum([for (i=[0:1:len(poly)-1]) cross(poly[i], select(poly,i+1))]),
+ res = abs(total * n) / 2
+ ) res;
// Function: polygon_is_convex()
@@ -1287,12 +1287,12 @@ function polygon_area(poly) =
// spiral = [for (i=[0:36]) let(a=-i*10) (10+i)*[cos(a),sin(a)]];
// polygon_is_convex(spiral); // Returns: false
function polygon_is_convex(poly) =
- let(
- l = len(poly),
- c = [for (i=idx(poly)) cross(poly[(i+1)%l]-poly[i],poly[(i+2)%l]-poly[(i+1)%l])]
- )
- len([for (x=c) if(x>0) 1])==0 ||
- len([for (x=c) if(x<0) 1])==0;
+ let(
+ l = len(poly),
+ c = [for (i=idx(poly)) cross(poly[(i+1)%l]-poly[i],poly[(i+2)%l]-poly[(i+1)%l])]
+ )
+ len([for (x=c) if(x>0) 1])==0 ||
+ len([for (x=c) if(x<0) 1])==0;
// Function: polygon_shift()
@@ -1306,7 +1306,7 @@ function polygon_is_convex(poly) =
// Example:
// polygon_shift([[3,4], [8,2], [0,2], [-4,0]], 2); // Returns [[0,2], [-4,0], [3,4], [8,2]]
function polygon_shift(poly, i) =
- list_rotate(cleanup_path(poly), i);
+ list_rotate(cleanup_path(poly), i);
// Function: polygon_shift_to_closest_point()
@@ -1315,11 +1315,11 @@ function polygon_shift(poly, i) =
// Description:
// Given a polygon `path`, rotates the point ordering so that the first point in the path is the one closest to the given point `pt`.
function polygon_shift_to_closest_point(path, pt) =
- let(
- path = cleanup_path(path),
- dists = [for (p=path) norm(p-pt)],
- closest = min_index(dists)
- ) select(path,closest,closest+len(path)-1);
+ let(
+ path = cleanup_path(path),
+ dists = [for (p=path) norm(p-pt)],
+ closest = min_index(dists)
+ ) select(path,closest,closest+len(path)-1);
// Function: reindex_polygon()
@@ -1352,30 +1352,30 @@ function polygon_shift_to_closest_point(path, pt) =
// color("red") move_copies([pent[0],circ[0]]) circle(r=.1,$fn=32);
// color("blue") translate(reindexed[0])circle(r=.1,$fn=32);
function reindex_polygon(reference, poly, return_error=false) =
- assert(is_path(reference) && is_path(poly))
- assert(len(reference)==len(poly), "Polygons must be the same length in reindex_polygon")
- let(
- dim = len(reference[0]),
- N = len(reference),
- fixpoly = dim != 2? poly :
- polygon_is_clockwise(reference)? clockwise_polygon(poly) :
- ccw_polygon(poly),
- dist = [
- // Matrix of all pairwise distances
- for (p1=reference) [
- for (p2=fixpoly) norm(p1-p2)
- ]
- ],
- // Compute the sum of all distance pairs for a each shift
- sums = [
- for(shift=[0:1:N-1]) sum([
- for(i=[0:1:N-1]) dist[i][(i+shift)%N]
- ])
- ],
- optimal_poly = polygon_shift(fixpoly,min_index(sums))
- )
- return_error? [optimal_poly, min(sums)] :
- optimal_poly;
+ assert(is_path(reference) && is_path(poly))
+ assert(len(reference)==len(poly), "Polygons must be the same length in reindex_polygon")
+ let(
+ dim = len(reference[0]),
+ N = len(reference),
+ fixpoly = dim != 2? poly :
+ polygon_is_clockwise(reference)? clockwise_polygon(poly) :
+ ccw_polygon(poly),
+ dist = [
+ // Matrix of all pairwise distances
+ for (p1=reference) [
+ for (p2=fixpoly) norm(p1-p2)
+ ]
+ ],
+ // Compute the sum of all distance pairs for a each shift
+ sums = [
+ for(shift=[0:1:N-1]) sum([
+ for(i=[0:1:N-1]) dist[i][(i+shift)%N]
+ ])
+ ],
+ optimal_poly = polygon_shift(fixpoly,min_index(sums))
+ )
+ return_error? [optimal_poly, min(sums)] :
+ optimal_poly;
// Function: align_polygon()
@@ -1398,19 +1398,19 @@ function reindex_polygon(reference, poly, return_error=false) =
// color("red") move_copies(scale(1.4,p=align_polygon(pentagon,hexagon,[0:10:359]))) circle(r=.1);
// move_copies(concat(pentagon,hexagon))circle(r=.1);
function align_polygon(reference, poly, angles, cp) =
- assert(is_path(reference) && is_path(poly))
- assert(len(reference)==len(poly), "Polygons must be the same length to be aligned in align_polygon")
- assert(is_num(angles[0]), "The `angle` parameter to align_polygon must be a range or vector")
- let( // alignments is a vector of entries of the form: [polygon, error]
- alignments = [
- for(angle=angles) reindex_polygon(
- reference,
- zrot(angle,p=poly,cp=cp),
- return_error=true
- )
- ],
- best = min_index(subindex(alignments,1))
- ) alignments[best][0];
+ assert(is_path(reference) && is_path(poly))
+ assert(len(reference)==len(poly), "Polygons must be the same length to be aligned in align_polygon")
+ assert(is_num(angles[0]), "The `angle` parameter to align_polygon must be a range or vector")
+ let( // alignments is a vector of entries of the form: [polygon, error]
+ alignments = [
+ for(angle=angles) reindex_polygon(
+ reference,
+ zrot(angle,p=poly,cp=cp),
+ return_error=true
+ )
+ ],
+ best = min_index(subindex(alignments,1))
+ ) alignments[best][0];
// Function: centroid()
@@ -1421,22 +1421,22 @@ function align_polygon(reference, poly, angles, cp) =
// Given a simple 3D planar polygon, returns the 3D coordinates of the polygon's centroid.
// If the polygon is self-intersecting, the results are undefined.
function centroid(poly) =
- len(poly[0])==2? (
- sum([
- for(i=[0:len(poly)-1])
- let(segment=select(poly,i,i+1))
- det2(segment)*sum(segment)
- ]) / 6 / polygon_area(poly)
- ) : (
- let(
- n = plane_normal(plane_from_points(poly)),
- p1 = vector_angle(n,UP)>15? vector_axis(n,UP) : vector_axis(n,RIGHT),
- p2 = vector_axis(n,p1),
- cp = mean(poly),
- proj = project_plane(poly,cp,cp+p1,cp+p2),
- cxy = centroid(proj)
- ) lift_plane(cxy,cp,cp+p1,cp+p2)
- );
+ len(poly[0])==2? (
+ sum([
+ for(i=[0:len(poly)-1])
+ let(segment=select(poly,i,i+1))
+ det2(segment)*sum(segment)
+ ]) / 6 / polygon_area(poly)
+ ) : (
+ let(
+ n = plane_normal(plane_from_points(poly)),
+ p1 = vector_angle(n,UP)>15? vector_axis(n,UP) : vector_axis(n,RIGHT),
+ p2 = vector_axis(n,p1),
+ cp = mean(poly),
+ proj = project_plane(poly,cp,cp+p1,cp+p2),
+ cxy = centroid(proj)
+ ) lift_plane(cxy,cp,cp+p1,cp+p2)
+ );
// Function: point_in_polygon()
@@ -1457,11 +1457,11 @@ function centroid(poly) =
// path = The list of 2D path points forming the perimeter of the polygon.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function point_in_polygon(point, path, eps=EPSILON) =
- // Original algorithm from http://geomalgorithms.com/a03-_inclusion.html
- // Does the point lie on any edges? If so return 0.
- sum([for(i=[0:1:len(path)-1]) let(seg=select(path,i,i+1)) if(!approx(seg[0],seg[1],eps=eps)) point_on_segment2d(point, seg, eps=eps)?1:0]) > 0? 0 :
- // Otherwise compute winding number and return 1 for interior, -1 for exterior
- sum([for(i=[0:1:len(path)-1]) let(seg=select(path,i,i+1)) if(!approx(seg[0],seg[1],eps=eps)) _point_above_below_segment(point, seg)]) != 0? 1 : -1;
+ // Original algorithm from http://geomalgorithms.com/a03-_inclusion.html
+ // Does the point lie on any edges? If so return 0.
+ sum([for(i=[0:1:len(path)-1]) let(seg=select(path,i,i+1)) if(!approx(seg[0],seg[1],eps=eps)) point_on_segment2d(point, seg, eps=eps)?1:0]) > 0? 0 :
+ // Otherwise compute winding number and return 1 for interior, -1 for exterior
+ sum([for(i=[0:1:len(path)-1]) let(seg=select(path,i,i+1)) if(!approx(seg[0],seg[1],eps=eps)) _point_above_below_segment(point, seg)]) != 0? 1 : -1;
// Function: polygon_is_clockwise()
@@ -1473,15 +1473,15 @@ function point_in_polygon(point, path, eps=EPSILON) =
// Arguments:
// path = The list of 2D path points for the perimeter of the polygon.
function polygon_is_clockwise(path) =
- assert(is_path(path) && len(path[0])==2, "Input must be a 2d path")
- let(
- minx = min(subindex(path,0)),
- lowind = search(minx, path, 0, 0),
- lowpts = select(path, lowind),
- miny = min(subindex(lowpts, 1)),
- extreme_sub = search(miny, lowpts, 1, 1)[0],
- extreme = select(lowind,extreme_sub)
- ) det2([select(path,extreme+1)-path[extreme], select(path, extreme-1)-path[extreme]])<0;
+ assert(is_path(path) && len(path[0])==2, "Input must be a 2d path")
+ let(
+ minx = min(subindex(path,0)),
+ lowind = search(minx, path, 0, 0),
+ lowpts = select(path, lowind),
+ miny = min(subindex(lowpts, 1)),
+ extreme_sub = search(miny, lowpts, 1, 1)[0],
+ extreme = select(lowind,extreme_sub)
+ ) det2([select(path,extreme+1)-path[extreme], select(path, extreme-1)-path[extreme]])<0;
// Function: clockwise_polygon()
@@ -1490,7 +1490,7 @@ function polygon_is_clockwise(path) =
// Description:
// Given a 2D polygon path, returns the clockwise winding version of that path.
function clockwise_polygon(path) =
- polygon_is_clockwise(path)? path : reverse_polygon(path);
+ polygon_is_clockwise(path)? path : reverse_polygon(path);
// Function: ccw_polygon()
@@ -1499,7 +1499,7 @@ function clockwise_polygon(path) =
// Description:
// Given a 2D polygon path, returns the counter-clockwise winding version of that path.
function ccw_polygon(path) =
- polygon_is_clockwise(path)? reverse_polygon(path) : path;
+ polygon_is_clockwise(path)? reverse_polygon(path) : path;
// Function: reverse_polygon()
@@ -1508,7 +1508,7 @@ function ccw_polygon(path) =
// Description:
// Reverses a polygon's winding direction, while still using the same start point.
function reverse_polygon(poly) =
- let(lp=len(poly)) [for (i=idx(poly)) poly[(lp-i)%lp]];
+ let(lp=len(poly)) [for (i=idx(poly)) poly[(lp-i)%lp]];
// Function: polygon_normal()
@@ -1518,101 +1518,101 @@ function reverse_polygon(poly) =
// Given a 3D planar polygon, returns a unit-length normal vector for the
// clockwise orientation of the polygon.
function polygon_normal(poly) =
- let(
- poly = path3d(cleanup_path(poly)),
- p0 = poly[0],
- n = sum([
- for (i=[1:1:len(poly)-2])
- cross(poly[i+1]-p0, poly[i]-p0)
- ])
- ) unit(n);
+ let(
+ poly = path3d(cleanup_path(poly)),
+ p0 = poly[0],
+ n = sum([
+ for (i=[1:1:len(poly)-2])
+ cross(poly[i+1]-p0, poly[i]-p0)
+ ])
+ ) unit(n);
function _split_polygon_at_x(poly, x) =
- let(
- xs = subindex(poly,0)
- ) (min(xs) >= x || max(xs) <= x)? [poly] :
- let(
- poly2 = [
- for (p = pair_wrap(poly)) each [
- p[0],
- if(
- (p[0].x < x && p[1].x > x) ||
- (p[1].x < x && p[0].x > x)
- ) let(
- u = (x - p[0].x) / (p[1].x - p[0].x)
- ) [
- x, // Important for later exact match tests
- u*(p[1].y-p[0].y)+p[0].y,
- u*(p[1].z-p[0].z)+p[0].z,
- ]
- ]
- ],
- out1 = [for (p = poly2) if(p.x <= x) p],
- out2 = [for (p = poly2) if(p.x >= x) p],
- out = [
- if (len(out1)>=3) out1,
- if (len(out2)>=3) out2,
- ]
- ) out;
+ let(
+ xs = subindex(poly,0)
+ ) (min(xs) >= x || max(xs) <= x)? [poly] :
+ let(
+ poly2 = [
+ for (p = pair_wrap(poly)) each [
+ p[0],
+ if(
+ (p[0].x < x && p[1].x > x) ||
+ (p[1].x < x && p[0].x > x)
+ ) let(
+ u = (x - p[0].x) / (p[1].x - p[0].x)
+ ) [
+ x, // Important for later exact match tests
+ u*(p[1].y-p[0].y)+p[0].y,
+ u*(p[1].z-p[0].z)+p[0].z,
+ ]
+ ]
+ ],
+ out1 = [for (p = poly2) if(p.x <= x) p],
+ out2 = [for (p = poly2) if(p.x >= x) p],
+ out = [
+ if (len(out1)>=3) out1,
+ if (len(out2)>=3) out2,
+ ]
+ ) out;
function _split_polygon_at_y(poly, y) =
- let(
- ys = subindex(poly,1)
- ) (min(ys) >= y || max(ys) <= y)? [poly] :
- let(
- poly2 = [
- for (p = pair_wrap(poly)) each [
- p[0],
- if(
- (p[0].y < y && p[1].y > y) ||
- (p[1].y < y && p[0].y > y)
- ) let(
- u = (y - p[0].y) / (p[1].y - p[0].y)
- ) [
- u*(p[1].x-p[0].x)+p[0].x,
- y, // Important for later exact match tests
- u*(p[1].z-p[0].z)+p[0].z,
- ]
- ]
- ],
- out1 = [for (p = poly2) if(p.y <= y) p],
- out2 = [for (p = poly2) if(p.y >= y) p],
- out = [
- if (len(out1)>=3) out1,
- if (len(out2)>=3) out2,
- ]
- ) out;
+ let(
+ ys = subindex(poly,1)
+ ) (min(ys) >= y || max(ys) <= y)? [poly] :
+ let(
+ poly2 = [
+ for (p = pair_wrap(poly)) each [
+ p[0],
+ if(
+ (p[0].y < y && p[1].y > y) ||
+ (p[1].y < y && p[0].y > y)
+ ) let(
+ u = (y - p[0].y) / (p[1].y - p[0].y)
+ ) [
+ u*(p[1].x-p[0].x)+p[0].x,
+ y, // Important for later exact match tests
+ u*(p[1].z-p[0].z)+p[0].z,
+ ]
+ ]
+ ],
+ out1 = [for (p = poly2) if(p.y <= y) p],
+ out2 = [for (p = poly2) if(p.y >= y) p],
+ out = [
+ if (len(out1)>=3) out1,
+ if (len(out2)>=3) out2,
+ ]
+ ) out;
function _split_polygon_at_z(poly, z) =
- let(
- zs = subindex(poly,2)
- ) (min(zs) >= z || max(zs) <= z)? [poly] :
- let(
- poly2 = [
- for (p = pair_wrap(poly)) each [
- p[0],
- if(
- (p[0].z < z && p[1].z > z) ||
- (p[1].z < z && p[0].z > z)
- ) let(
- u = (z - p[0].z) / (p[1].z - p[0].z)
- ) [
- u*(p[1].x-p[0].x)+p[0].x,
- u*(p[1].y-p[0].y)+p[0].y,
- z, // Important for later exact match tests
- ]
- ]
- ],
- out1 = [for (p = poly2) if(p.z <= z) p],
- out2 = [for (p = poly2) if(p.z >= z) p],
- out = [
- if (len(out1)>=3) out1,
- if (len(out2)>=3) out2,
- ]
- ) out;
+ let(
+ zs = subindex(poly,2)
+ ) (min(zs) >= z || max(zs) <= z)? [poly] :
+ let(
+ poly2 = [
+ for (p = pair_wrap(poly)) each [
+ p[0],
+ if(
+ (p[0].z < z && p[1].z > z) ||
+ (p[1].z < z && p[0].z > z)
+ ) let(
+ u = (z - p[0].z) / (p[1].z - p[0].z)
+ ) [
+ u*(p[1].x-p[0].x)+p[0].x,
+ u*(p[1].y-p[0].y)+p[0].y,
+ z, // Important for later exact match tests
+ ]
+ ]
+ ],
+ out1 = [for (p = poly2) if(p.z <= z) p],
+ out2 = [for (p = poly2) if(p.z >= z) p],
+ out = [
+ if (len(out1)>=3) out1,
+ if (len(out2)>=3) out2,
+ ]
+ ) out;
// Function: split_polygons_at_each_x()
@@ -1624,13 +1624,13 @@ function _split_polygon_at_z(poly, z) =
// polys = A list of 3D polygons to split.
// xs = A list of scalar X values to split at.
function split_polygons_at_each_x(polys, xs, _i=0) =
- _i>=len(xs)? polys :
- split_polygons_at_each_x(
- [
- for (poly = polys)
- each _split_polygon_at_x(poly, xs[_i])
- ], xs, _i=_i+1
- );
+ _i>=len(xs)? polys :
+ split_polygons_at_each_x(
+ [
+ for (poly = polys)
+ each _split_polygon_at_x(poly, xs[_i])
+ ], xs, _i=_i+1
+ );
// Function: split_polygons_at_each_y()
@@ -1642,13 +1642,13 @@ function split_polygons_at_each_x(polys, xs, _i=0) =
// polys = A list of 3D polygons to split.
// ys = A list of scalar Y values to split at.
function split_polygons_at_each_y(polys, ys, _i=0) =
- _i>=len(ys)? polys :
- split_polygons_at_each_y(
- [
- for (poly = polys)
- each _split_polygon_at_y(poly, ys[_i])
- ], ys, _i=_i+1
- );
+ _i>=len(ys)? polys :
+ split_polygons_at_each_y(
+ [
+ for (poly = polys)
+ each _split_polygon_at_y(poly, ys[_i])
+ ], ys, _i=_i+1
+ );
// Function: split_polygons_at_each_z()
@@ -1660,14 +1660,14 @@ function split_polygons_at_each_y(polys, ys, _i=0) =
// polys = A list of 3D polygons to split.
// zs = A list of scalar Z values to split at.
function split_polygons_at_each_z(polys, zs, _i=0) =
- _i>=len(zs)? polys :
- split_polygons_at_each_z(
- [
- for (poly = polys)
- each _split_polygon_at_z(poly, zs[_i])
- ], zs, _i=_i+1
- );
+ _i>=len(zs)? polys :
+ split_polygons_at_each_z(
+ [
+ for (poly = polys)
+ each _split_polygon_at_z(poly, zs[_i])
+ ], zs, _i=_i+1
+ );
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/hingesnaps.scad b/hingesnaps.scad
index 5c00f9f..de6f3c6 100644
--- a/hingesnaps.scad
+++ b/hingesnaps.scad
@@ -29,13 +29,13 @@
// folding_hinge_mask(l=100, thick=3, foldangle=60);
module folding_hinge_mask(l, thick, layerheight=0.2, foldangle=90, hingegap=undef, anchor=CENTER, spin=0, orient=UP)
{
- hingegap = default(hingegap, layerheight)+2*$slop;
- size = [l, hingegap, 2*thick];
- size2 = [l, hingegap+2*thick*tan(foldangle/2)];
- attachable(anchor,spin,orient, size=size, size2=size2) {
- up(layerheight*2) prismoid([l,hingegap], [l, hingegap+2*thick/tan(foldangle/2)], h=thick, anchor=BOT);
- children();
- }
+ hingegap = default(hingegap, layerheight)+2*$slop;
+ size = [l, hingegap, 2*thick];
+ size2 = [l, hingegap+2*thick*tan(foldangle/2)];
+ attachable(anchor,spin,orient, size=size, size2=size2) {
+ up(layerheight*2) prismoid([l,hingegap], [l, hingegap+2*thick/tan(foldangle/2)], h=thick, anchor=BOT);
+ children();
+ }
}
@@ -58,18 +58,18 @@ module folding_hinge_mask(l, thick, layerheight=0.2, foldangle=90, hingegap=unde
// snap_lock(thick=3, foldangle=60);
module snap_lock(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90, hingegap=undef, anchor=CENTER, spin=0, orient=UP)
{
- hingegap = default(hingegap, layerheight)+2*$slop;
- snap_x = (snapdiam/2) / tan(foldangle/2) + (thick-2*layerheight)/tan(foldangle/2) + hingegap/2;
- size = [snaplen, snapdiam, 2*thick];
- attachable(anchor,spin,orient, size=size) {
- back(snap_x) {
- cube([snaplen, snapdiam, snapdiam/2+thick], anchor=BOT) {
- attach(TOP) xcyl(l=snaplen, d=snapdiam, $fn=16);
- attach(TOP) xcopies(snaplen-snapdiam/4/3) xscale(0.333) sphere(d=snapdiam*0.8, $fn=12);
- }
- }
- children();
- }
+ hingegap = default(hingegap, layerheight)+2*$slop;
+ snap_x = (snapdiam/2) / tan(foldangle/2) + (thick-2*layerheight)/tan(foldangle/2) + hingegap/2;
+ size = [snaplen, snapdiam, 2*thick];
+ attachable(anchor,spin,orient, size=size) {
+ back(snap_x) {
+ cube([snaplen, snapdiam, snapdiam/2+thick], anchor=BOT) {
+ attach(TOP) xcyl(l=snaplen, d=snapdiam, $fn=16);
+ attach(TOP) xcopies(snaplen-snapdiam/4/3) xscale(0.333) sphere(d=snapdiam*0.8, $fn=12);
+ }
+ }
+ children();
+ }
}
@@ -92,21 +92,21 @@ module snap_lock(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90, hi
// snap_socket(thick=3, foldangle=60);
module snap_socket(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90, hingegap=undef, anchor=CENTER, spin=0, orient=UP)
{
- hingegap = default(hingegap, layerheight)+2*$slop;
- snap_x = (snapdiam/2) / tan(foldangle/2) + (thick-2*layerheight)/tan(foldangle/2) + hingegap/2;
- size = [snaplen, snapdiam, 2*thick];
- attachable(anchor,spin,orient, size=size) {
- fwd(snap_x) {
- zrot_copies([0,180], r=snaplen+$slop) {
- diff("divot")
- cube([snaplen, snapdiam, snapdiam/2+thick], anchor=BOT) {
- attach(TOP) xcyl(l=snaplen, d=snapdiam, $fn=16);
- attach(TOP) left((snaplen+snapdiam/4/3)/2) xscale(0.333) sphere(d=snapdiam*0.8, $fn=12, $tags="divot");
- }
- }
- }
- children();
- }
+ hingegap = default(hingegap, layerheight)+2*$slop;
+ snap_x = (snapdiam/2) / tan(foldangle/2) + (thick-2*layerheight)/tan(foldangle/2) + hingegap/2;
+ size = [snaplen, snapdiam, 2*thick];
+ attachable(anchor,spin,orient, size=size) {
+ fwd(snap_x) {
+ zrot_copies([0,180], r=snaplen+$slop) {
+ diff("divot")
+ cube([snaplen, snapdiam, snapdiam/2+thick], anchor=BOT) {
+ attach(TOP) xcyl(l=snaplen, d=snapdiam, $fn=16);
+ attach(TOP) left((snaplen+snapdiam/4/3)/2) xscale(0.333) sphere(d=snapdiam*0.8, $fn=12, $tags="divot");
+ }
+ }
+ }
+ children();
+ }
}
@@ -157,37 +157,37 @@ module snap_socket(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90,
// }
module apply_folding_hinges_and_snaps(thick, foldangle=90, hinges=[], snaps=[], sockets=[], snaplen=5, snapdiam=5, hingegap=undef, layerheight=0.2)
{
- hingegap = default(hingegap, layerheight)+2*$slop;
- difference() {
- children();
- for (hinge = hinges) {
- translate(hinge[1]) {
- folding_hinge_mask(
- l=hinge[0], thick=thick, layerheight=layerheight,
- foldangle=foldangle, hingegap=hingegap, spin=hinge[2]
- );
- }
- }
- }
- for (snap = snaps) {
- translate(snap[0]) {
- snap_lock(
- thick=thick, snaplen=snaplen, snapdiam=snapdiam,
- layerheight=layerheight, foldangle=foldangle,
- hingegap=hingegap, spin=snap[1]
- );
- }
- }
- for (socket = sockets) {
- translate(socket[0]) {
- snap_socket(
- thick=thick, snaplen=snaplen, snapdiam=snapdiam,
- layerheight=layerheight, foldangle=foldangle,
- hingegap=hingegap, spin=socket[1]
- );
- }
- }
+ hingegap = default(hingegap, layerheight)+2*$slop;
+ difference() {
+ children();
+ for (hinge = hinges) {
+ translate(hinge[1]) {
+ folding_hinge_mask(
+ l=hinge[0], thick=thick, layerheight=layerheight,
+ foldangle=foldangle, hingegap=hingegap, spin=hinge[2]
+ );
+ }
+ }
+ }
+ for (snap = snaps) {
+ translate(snap[0]) {
+ snap_lock(
+ thick=thick, snaplen=snaplen, snapdiam=snapdiam,
+ layerheight=layerheight, foldangle=foldangle,
+ hingegap=hingegap, spin=snap[1]
+ );
+ }
+ }
+ for (socket = sockets) {
+ translate(socket[0]) {
+ snap_socket(
+ thick=thick, snaplen=snaplen, snapdiam=snapdiam,
+ layerheight=layerheight, foldangle=foldangle,
+ hingegap=hingegap, spin=socket[1]
+ );
+ }
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/hull.scad b/hull.scad
index a9295bb..1855ce0 100644
--- a/hull.scad
+++ b/hull.scad
@@ -48,29 +48,29 @@ function hull(points) = let(two_d = len(points[0]) == 2) two_d? hull2d_path(poin
// pts = [for (phi = [30:60:150], theta = [0:60:359]) spherical_to_xyz(10, theta, phi)];
// hull_points(pts);
module hull_points(points, fast=false) {
- assert(is_list(points));
- if (points) {
- assert(is_list(points[0]));
- if (fast) {
- if (len(points[0]) == 2) {
- hull() polygon(points=points);
- } else {
- extra = len(points)%3;
- faces = concat(
- [[for(i=[0:1:extra+2])i]],
- [for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]
- );
- hull() polyhedron(points=points, faces=faces);
- }
- } else {
- perim = hull(points);
- if (is_num(perim[0])) {
- polygon(points=points, paths=[perim]);
- } else {
- polyhedron(points=points, faces=perim);
- }
- }
- }
+ assert(is_list(points));
+ if (points) {
+ assert(is_list(points[0]));
+ if (fast) {
+ if (len(points[0]) == 2) {
+ hull() polygon(points=points);
+ } else {
+ extra = len(points)%3;
+ faces = concat(
+ [[for(i=[0:1:extra+2])i]],
+ [for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]
+ );
+ hull() polyhedron(points=points, faces=faces);
+ }
+ } else {
+ perim = hull(points);
+ if (is_num(perim[0])) {
+ polygon(points=points, paths=[perim]);
+ } else {
+ polyhedron(points=points, faces=perim);
+ }
+ }
+ }
}
@@ -86,62 +86,62 @@ module hull_points(points, fast=false) {
// move_copies(pts) color("red") sphere(1);
// polygon(points=pts, paths=[path]);
function hull2d_path(points) =
- (len(points) < 3)? [] : let(
- a=0, b=1,
- c = first_noncollinear(a, b, points)
- ) (c == len(points))? _hull2d_collinear(points) : let(
- remaining = [ for (i = [2:1:len(points)-1]) if (i != c) i ],
- ccw = triangle_area(points[a], points[b], points[c]) > 0,
- polygon = ccw? [a,b,c] : [a,c,b]
- ) _hull2d_iterative(points, polygon, remaining);
+ (len(points) < 3)? [] : let(
+ a=0, b=1,
+ c = first_noncollinear(a, b, points)
+ ) (c == len(points))? _hull2d_collinear(points) : let(
+ remaining = [ for (i = [2:1:len(points)-1]) if (i != c) i ],
+ ccw = triangle_area(points[a], points[b], points[c]) > 0,
+ polygon = ccw? [a,b,c] : [a,c,b]
+ ) _hull2d_iterative(points, polygon, remaining);
// Adds the remaining points one by one to the convex hull
function _hull2d_iterative(points, polygon, remaining, _i=0) =
- (_i >= len(remaining))? polygon : let (
- // pick a point
- i = remaining[_i],
- // find the segments that are in conflict with the point (point not inside)
- conflicts = _find_conflicting_segments(points, polygon, points[i])
- // no conflicts, skip point and move on
- ) (len(conflicts) == 0)? _hull2d_iterative(points, polygon, remaining, _i+1) : let(
- // find the first conflicting segment and the first not conflicting
- // conflict will be sorted, if not wrapping around, do it the easy way
- polygon = _remove_conflicts_and_insert_point(polygon, conflicts, i)
- ) _hull2d_iterative(points, polygon, remaining, _i+1);
+ (_i >= len(remaining))? polygon : let (
+ // pick a point
+ i = remaining[_i],
+ // find the segments that are in conflict with the point (point not inside)
+ conflicts = _find_conflicting_segments(points, polygon, points[i])
+ // no conflicts, skip point and move on
+ ) (len(conflicts) == 0)? _hull2d_iterative(points, polygon, remaining, _i+1) : let(
+ // find the first conflicting segment and the first not conflicting
+ // conflict will be sorted, if not wrapping around, do it the easy way
+ polygon = _remove_conflicts_and_insert_point(polygon, conflicts, i)
+ ) _hull2d_iterative(points, polygon, remaining, _i+1);
function _hull2d_collinear(points) =
- let(
- a = points[0],
- n = points[1] - a,
- points1d = [ for(p = points) (p-a)*n ],
- min_i = min_index(points1d),
- max_i = max_index(points1d)
- ) [min_i, max_i];
+ let(
+ a = points[0],
+ n = points[1] - a,
+ points1d = [ for(p = points) (p-a)*n ],
+ min_i = min_index(points1d),
+ max_i = max_index(points1d)
+ ) [min_i, max_i];
function _find_conflicting_segments(points, polygon, point) = [
- for (i = [0:1:len(polygon)-1]) let(
- j = (i+1) % len(polygon),
- p1 = points[polygon[i]],
- p2 = points[polygon[j]],
- area = triangle_area(p1, p2, point)
- ) if (area < 0) i
+ for (i = [0:1:len(polygon)-1]) let(
+ j = (i+1) % len(polygon),
+ p1 = points[polygon[i]],
+ p2 = points[polygon[j]],
+ area = triangle_area(p1, p2, point)
+ ) if (area < 0) i
];
// remove the conflicting segments from the polygon
function _remove_conflicts_and_insert_point(polygon, conflicts, point) =
- (conflicts[0] == 0)? let(
- nonconflicting = [ for(i = [0:1:len(polygon)-1]) if (!in_list(i, conflicts)) i ],
- new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
- polygon = concat([ for (i = new_indices) polygon[i] ], point)
- ) polygon : let(
- before_conflicts = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
- after_conflicts = (max(conflicts) >= (len(polygon)-1))? [] : [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
- polygon = concat(before_conflicts, point, after_conflicts)
- ) polygon;
+ (conflicts[0] == 0)? let(
+ nonconflicting = [ for(i = [0:1:len(polygon)-1]) if (!in_list(i, conflicts)) i ],
+ new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
+ polygon = concat([ for (i = new_indices) polygon[i] ], point)
+ ) polygon : let(
+ before_conflicts = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
+ after_conflicts = (max(conflicts) >= (len(polygon)-1))? [] : [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
+ polygon = concat(before_conflicts, point, after_conflicts)
+ ) polygon;
@@ -159,83 +159,83 @@ function _remove_conflicts_and_insert_point(polygon, conflicts, point) =
// move_copies(pts) color("red") sphere(1);
// %polyhedron(points=pts, faces=faces);
function hull3d_faces(points) =
- (len(points) < 3)? list_range(len(points)) : let (
- // start with a single non-collinear triangle
- a = 0,
- b = 1,
- c = first_noncollinear(a, b, points)
- ) (c == len(points))? _hull2d_collinear(points) : let(
- plane = plane3pt_indexed(points, a, b, c),
- d = _find_first_noncoplanar(plane, points, 3)
- ) (d == len(points))? /* all coplanar*/ let (
- pts2d = [ for (p = points) project_plane(p, points[a], points[b], points[c]) ],
- hull2d = hull2d_path(pts2d)
- ) hull2d : let(
- remaining = [for (i = [3:1:len(points)-1]) if (i != d) i],
- // Build an initial tetrahedron.
- // Swap b, c if d is in front of triangle t.
- ifop = in_front_of_plane(plane, points[d]),
- bc = ifop? [c,b] : [b,c],
- b = bc[0],
- c = bc[1],
- triangles = [
- [a,b,c],
- [d,b,a],
- [c,d,a],
- [b,d,c]
- ],
- // calculate the plane equations
- planes = [ for (t = triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
- ) _hull3d_iterative(points, triangles, planes, remaining);
+ (len(points) < 3)? list_range(len(points)) : let (
+ // start with a single non-collinear triangle
+ a = 0,
+ b = 1,
+ c = first_noncollinear(a, b, points)
+ ) (c == len(points))? _hull2d_collinear(points) : let(
+ plane = plane3pt_indexed(points, a, b, c),
+ d = _find_first_noncoplanar(plane, points, 3)
+ ) (d == len(points))? /* all coplanar*/ let (
+ pts2d = [ for (p = points) project_plane(p, points[a], points[b], points[c]) ],
+ hull2d = hull2d_path(pts2d)
+ ) hull2d : let(
+ remaining = [for (i = [3:1:len(points)-1]) if (i != d) i],
+ // Build an initial tetrahedron.
+ // Swap b, c if d is in front of triangle t.
+ ifop = in_front_of_plane(plane, points[d]),
+ bc = ifop? [c,b] : [b,c],
+ b = bc[0],
+ c = bc[1],
+ triangles = [
+ [a,b,c],
+ [d,b,a],
+ [c,d,a],
+ [b,d,c]
+ ],
+ // calculate the plane equations
+ planes = [ for (t = triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
+ ) _hull3d_iterative(points, triangles, planes, remaining);
// Adds the remaining points one by one to the convex hull
function _hull3d_iterative(points, triangles, planes, remaining, _i=0) =
- _i >= len(remaining) ? triangles :
- let (
- // pick a point
- i = remaining[_i],
- // find the triangles that are in conflict with the point (point not inside)
- conflicts = _find_conflicts(points[i], planes),
- // for all triangles that are in conflict, collect their halfedges
- halfedges = [
- for(c = conflicts, i = [0:2]) let(
- j = (i+1)%3
- ) [triangles[c][i], triangles[c][j]]
- ],
- // find the outer perimeter of the set of conflicting triangles
- horizon = _remove_internal_edges(halfedges),
- // generate a new triangle for each horizon halfedge together with the picked point i
- new_triangles = [ for (h = horizon) concat(h,i) ],
- // calculate the corresponding plane equations
- new_planes = [ for (t = new_triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
- ) _hull3d_iterative(
- points,
- // remove the conflicting triangles and add the new ones
- concat(list_remove(triangles, conflicts), new_triangles),
- concat(list_remove(planes, conflicts), new_planes),
- remaining,
- _i+1
- );
+ _i >= len(remaining) ? triangles :
+ let (
+ // pick a point
+ i = remaining[_i],
+ // find the triangles that are in conflict with the point (point not inside)
+ conflicts = _find_conflicts(points[i], planes),
+ // for all triangles that are in conflict, collect their halfedges
+ halfedges = [
+ for(c = conflicts, i = [0:2]) let(
+ j = (i+1)%3
+ ) [triangles[c][i], triangles[c][j]]
+ ],
+ // find the outer perimeter of the set of conflicting triangles
+ horizon = _remove_internal_edges(halfedges),
+ // generate a new triangle for each horizon halfedge together with the picked point i
+ new_triangles = [ for (h = horizon) concat(h,i) ],
+ // calculate the corresponding plane equations
+ new_planes = [ for (t = new_triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
+ ) _hull3d_iterative(
+ points,
+ // remove the conflicting triangles and add the new ones
+ concat(list_remove(triangles, conflicts), new_triangles),
+ concat(list_remove(planes, conflicts), new_planes),
+ remaining,
+ _i+1
+ );
function _remove_internal_edges(halfedges) = [
- for (h = halfedges)
- if (!in_list(reverse(h), halfedges))
- h
+ for (h = halfedges)
+ if (!in_list(reverse(h), halfedges))
+ h
];
function _find_conflicts(point, planes) = [
- for (i = [0:1:len(planes)-1])
- if (in_front_of_plane(planes[i], point))
- i
+ for (i = [0:1:len(planes)-1])
+ if (in_front_of_plane(planes[i], point))
+ i
];
function _find_first_noncoplanar(plane, points, i) =
- (i >= len(points) || !coplanar(plane, points[i]))? i :
- _find_first_noncoplanar(plane, points, i+1);
+ (i >= len(points) || !coplanar(plane, points[i]))? i :
+ _find_first_noncoplanar(plane, points, i+1);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/involute_gears.scad b/involute_gears.scad
index 8b080d9..f614868 100644
--- a/involute_gears.scad
+++ b/involute_gears.scad
@@ -78,7 +78,7 @@ function adendum(pitch=5) = module_value(pitch);
// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
// clearance = If given, sets the clearance between meshing teeth.
function dedendum(pitch=5, clearance=undef) =
- (clearance==undef)? (1.25 * module_value(pitch)) : (module_value(pitch) + clearance);
+ (clearance==undef)? (1.25 * module_value(pitch)) : (module_value(pitch) + clearance);
// Function: pitch_radius()
@@ -87,7 +87,7 @@ function dedendum(pitch=5, clearance=undef) =
// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
// teeth = The number of teeth on the gear.
function pitch_radius(pitch=5, teeth=11) =
- pitch * teeth / PI / 2;
+ pitch * teeth / PI / 2;
// Function: outer_radius()
@@ -99,8 +99,8 @@ function pitch_radius(pitch=5, teeth=11) =
// clearance = If given, sets the clearance between meshing teeth.
// interior = If true, calculate for an interior gear.
function outer_radius(pitch=5, teeth=11, clearance=undef, interior=false) =
- pitch_radius(pitch, teeth) +
- (interior? dedendum(pitch, clearance) : adendum(pitch));
+ pitch_radius(pitch, teeth) +
+ (interior? dedendum(pitch, clearance) : adendum(pitch));
// Function: root_radius()
@@ -112,8 +112,8 @@ function outer_radius(pitch=5, teeth=11, clearance=undef, interior=false) =
// clearance = If given, sets the clearance between meshing teeth.
// interior = If true, calculate for an interior gear.
function root_radius(pitch=5, teeth=11, clearance=undef, interior=false) =
- pitch_radius(pitch, teeth) -
- (interior? adendum(pitch) : dedendum(pitch, clearance));
+ pitch_radius(pitch, teeth) -
+ (interior? adendum(pitch) : dedendum(pitch, clearance));
// Function: base_radius()
@@ -123,7 +123,7 @@ function root_radius(pitch=5, teeth=11, clearance=undef, interior=false) =
// teeth = The number of teeth on the gear.
// PA = Pressure angle in degrees. Controls how straight or bulged the tooth sides are.
function base_radius(pitch=5, teeth=11, PA=28) =
- pitch_radius(pitch, teeth) * cos(PA);
+ pitch_radius(pitch, teeth) * cos(PA);
// Function bevel_pitch_angle()
@@ -137,7 +137,7 @@ function base_radius(pitch=5, teeth=11, PA=28) =
// mate_teeth = Number of teeth that the matching gear has.
// drive_angle = Angle between the drive shafts of each gear. Usually 90º.
function bevel_pitch_angle(teeth, mate_teeth, drive_angle=90) =
- atan(sin(drive_angle)/((mate_teeth/teeth)+cos(drive_angle)));
+ atan(sin(drive_angle)/((mate_teeth/teeth)+cos(drive_angle)));
function _gear_polar(r,t) = r*[sin(t),cos(t)];
@@ -166,63 +166,63 @@ function _gear_q7(f,r,b,r2,t,s) = _gear_q6(b,s,t,(1-f)*max(b,r)+f*r2); //
// Example(2D):
// gear_tooth_profile(pitch=5, teeth=20, PA=20, valleys=true);
function gear_tooth_profile(
- pitch = 3,
- teeth = 11,
- PA = 28,
- backlash = 0.0,
- clearance = undef,
- interior = false,
- valleys = true
+ pitch = 3,
+ teeth = 11,
+ PA = 28,
+ backlash = 0.0,
+ clearance = undef,
+ interior = false,
+ valleys = true
) = let(
- p = pitch_radius(pitch, teeth),
- c = outer_radius(pitch, teeth, clearance, interior),
- r = root_radius(pitch, teeth, clearance, interior),
- b = base_radius(pitch, teeth, PA),
- t = pitch/2-backlash/2, //tooth thickness at pitch circle
- k = -_gear_iang(b, p) - t/2/p/PI*180, //angle to where involute meets base circle on each side of tooth
- kk = r0? [[0,0]] : []
- )
+ pr = pitch_radius(pitch=pitch, teeth=teeth),
+ pts = concat(
+ [for (tooth = [0:1:teeth-hide-1])
+ each rot(tooth*360/teeth,
+ planar=true,
+ p=gear_tooth_profile(
+ pitch = pitch,
+ teeth = teeth,
+ PA = PA,
+ clearance = clearance,
+ backlash = backlash,
+ interior = interior,
+ valleys = false
+ )
+ )
+ ],
+ hide>0? [[0,0]] : []
+ )
) reorient(anchor,spin, two_d=true, r=pr, p=pts);
module gear2d(
- pitch = 3,
- teeth = 11,
- hide = 0,
- PA = 28,
- clearance = undef,
- backlash = 0.0,
- interior = false,
- anchor = CENTER,
- spin = 0
+ pitch = 3,
+ teeth = 11,
+ hide = 0,
+ PA = 28,
+ clearance = undef,
+ backlash = 0.0,
+ interior = false,
+ anchor = CENTER,
+ spin = 0
) {
- path = gear2d(
- pitch = pitch,
- teeth = teeth,
- hide = hide,
- PA = PA,
- clearance = clearance,
- backlash = backlash,
- interior = interior
- );
- pr = pitch_radius(pitch=pitch, teeth=teeth);
- attachable(anchor,spin, two_d=true, r=pr) {
- polygon(path);
- children();
- }
+ path = gear2d(
+ pitch = pitch,
+ teeth = teeth,
+ hide = hide,
+ PA = PA,
+ clearance = clearance,
+ backlash = backlash,
+ interior = interior
+ );
+ pr = pitch_radius(pitch=pitch, teeth=teeth);
+ attachable(anchor,spin, two_d=true, r=pr) {
+ polygon(path);
+ children();
+ }
}
@@ -362,44 +362,44 @@ module gear2d(
// Example: Beveled Gear
// gear(pitch=5, teeth=20, thickness=10, shaft_diam=5, helical=-30, slices=12, $fa=1, $fs=1);
module gear(
- pitch = 3,
- teeth = 11,
- PA = 28,
- thickness = 6,
- hide = 0,
- shaft_diam = 3,
- clearance = undef,
- backlash = 0.0,
- helical = 0,
- slices = 2,
- interior = false,
- anchor = CENTER,
- spin = 0,
- orient = UP
+ pitch = 3,
+ teeth = 11,
+ PA = 28,
+ thickness = 6,
+ hide = 0,
+ shaft_diam = 3,
+ clearance = undef,
+ backlash = 0.0,
+ helical = 0,
+ slices = 2,
+ interior = false,
+ anchor = CENTER,
+ spin = 0,
+ orient = UP
) {
- p = pitch_radius(pitch, teeth);
- c = outer_radius(pitch, teeth, clearance, interior);
- r = root_radius(pitch, teeth, clearance, interior);
- twist = atan2(thickness*tan(helical),p);
- attachable(anchor,spin,orient, r=p, l=thickness) {
- difference() {
- linear_extrude(height=thickness, center=true, convexity=10, twist=twist) {
- gear2d(
- pitch = pitch,
- teeth = teeth,
- PA = PA,
- hide = hide,
- clearance = clearance,
- backlash = backlash,
- interior = interior
- );
- }
- if (shaft_diam > 0) {
- cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
- }
- }
- children();
- }
+ p = pitch_radius(pitch, teeth);
+ c = outer_radius(pitch, teeth, clearance, interior);
+ r = root_radius(pitch, teeth, clearance, interior);
+ twist = atan2(thickness*tan(helical),p);
+ attachable(anchor,spin,orient, r=p, l=thickness) {
+ difference() {
+ linear_extrude(height=thickness, center=true, convexity=10, twist=twist) {
+ gear2d(
+ pitch = pitch,
+ teeth = teeth,
+ PA = PA,
+ hide = hide,
+ clearance = clearance,
+ backlash = backlash,
+ interior = interior
+ );
+ }
+ if (shaft_diam > 0) {
+ cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
+ }
+ }
+ children();
+ }
}
@@ -457,131 +457,131 @@ module gear(
// Example: Beveled Gear
// bevel_gear(pitch=5, teeth=36, face_width=10, shaft_diam=5, spiral_rad=-20, spiral_ang=35, bevelang=45, slices=12, $fa=1, $fs=1);
module bevel_gear(
- pitch = 3,
- teeth = 11,
- PA = 20,
- face_width = 6,
- bevelang = 45,
- hide = 0,
- shaft_diam = 3,
- clearance = undef,
- backlash = 0.0,
- spiral_rad = 0,
- spiral_ang = 0,
- slices = 2,
- interior = false,
- anchor = CENTER,
- spin = 0,
- orient = UP
+ pitch = 3,
+ teeth = 11,
+ PA = 20,
+ face_width = 6,
+ bevelang = 45,
+ hide = 0,
+ shaft_diam = 3,
+ clearance = undef,
+ backlash = 0.0,
+ spiral_rad = 0,
+ spiral_ang = 0,
+ slices = 2,
+ interior = false,
+ anchor = CENTER,
+ spin = 0,
+ orient = UP
) {
- thickness = face_width * cos(bevelang);
- slices = spiral_rad==0? 1 : slices;
- spiral_rad = spiral_rad==0? 10000 : spiral_rad;
- p1 = pitch_radius(pitch, teeth);
- r1 = root_radius(pitch, teeth, clearance, interior);
- c1 = outer_radius(pitch, teeth, clearance, interior);
- dx = thickness * tan(bevelang);
- dy = (p1-r1) * sin(bevelang);
- scl = (p1-dx)/p1;
- p2 = pitch_radius(pitch*scl, teeth);
- r2 = root_radius(pitch*scl, teeth, clearance, interior);
- c2 = outer_radius(pitch*scl, teeth, clearance, interior);
- slice_u = 1/slices;
- Rm = (p1+p2)/2;
- H = spiral_rad * cos(spiral_ang);
- V = Rm - abs(spiral_rad) * sin(spiral_ang);
- spiral_cp = [H,V,0];
- S = norm(spiral_cp);
- theta_r = acos((S*S+spiral_rad*spiral_rad-p1*p1)/(2*S*spiral_rad)) - acos((S*S+spiral_rad*spiral_rad-p2*p2)/(2*S*spiral_rad));
- theta_ro = acos((S*S+spiral_rad*spiral_rad-p1*p1)/(2*S*spiral_rad)) - acos((S*S+spiral_rad*spiral_rad-Rm*Rm)/(2*S*spiral_rad));
- theta_ri = theta_r - theta_ro;
- extent_u = 2*(p2-r2)*tan(bevelang) / thickness;
- slice_us = concat(
- [for (u = [0:slice_u:1+extent_u]) u]
- );
- lsus = len(slice_us);
- vertices = concat(
- [
- for (u=slice_us, tooth=[0:1:teeth-1]) let(
- p = lerp(p1,p2,u),
- r = lerp(r1,r2,u),
- theta = lerp(-theta_ro, theta_ri, u),
- profile = gear_tooth_profile(
- pitch = pitch*(p/p1),
- teeth = teeth,
- PA = PA,
- clearance = clearance,
- backlash = backlash,
- interior = interior,
- valleys = false
- ),
- pp = rot(theta, cp=spiral_cp, p=[0,Rm,0]),
- ang = atan2(pp.y,pp.x)-90,
- pts = apply_list(
- path3d(profile), [
- move([0,-p,0]),
- rot([0,ang,0]),
- rot([bevelang,0,0]),
- move(pp),
- rot(tooth*360/teeth),
- move([0,0,thickness*u])
- ]
- )
- ) each pts
- ], [
- [0,0,-dy], [0,0,thickness]
- ]
- );
- lcnt = (len(vertices)-2)/lsus/teeth;
- function _gv(layer,tooth,i) = ((layer*teeth)+(tooth%teeth))*lcnt+(i%lcnt);
- function _lv(layer,i) = layer*teeth*lcnt+(i%(teeth*lcnt));
- faces = concat(
- [
- for (sl=[0:1:lsus-2], i=[0:1:lcnt*teeth-1]) each [
- [_lv(sl,i), _lv(sl+1,i), _lv(sl,i+1)],
- [_lv(sl+1,i), _lv(sl+1,i+1), _lv(sl,i+1)]
- ]
- ], [
- for (tooth=[0:1:teeth-1], i=[0:1:lcnt/2-1]) each [
- [_gv(0,tooth,i), _gv(0,tooth,i+1), _gv(0,tooth,lcnt-1-(i+1))],
- [_gv(0,tooth,i), _gv(0,tooth,lcnt-1-(i+1)), _gv(0,tooth,lcnt-1-i)],
- [_gv(lsus-1,tooth,i), _gv(lsus-1,tooth,lcnt-1-(i+1)), _gv(lsus-1,tooth,i+1)],
- [_gv(lsus-1,tooth,i), _gv(lsus-1,tooth,lcnt-1-i), _gv(lsus-1,tooth,lcnt-1-(i+1))],
- ]
- ], [
- for (tooth=[0:1:teeth-1]) each [
- [len(vertices)-2, _gv(0,tooth,0), _gv(0,tooth,lcnt-1)],
- [len(vertices)-2, _gv(0,tooth,lcnt-1), _gv(0,tooth+1,0)],
- [len(vertices)-1, _gv(lsus-1,tooth,lcnt-1), _gv(lsus-1,tooth,0)],
- [len(vertices)-1, _gv(lsus-1,tooth+1,0), _gv(lsus-1,tooth,lcnt-1)],
- ]
- ]
- );
- attachable(anchor,spin,orient, r1=p1, r2=p2, l=thickness) {
- union() {
- difference() {
- down(thickness/2) {
- polyhedron(points=vertices, faces=faces, convexity=floor(teeth/2));
- }
- if (shaft_diam > 0) {
- cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
- }
- if (bevelang != 0) {
- h = (c1-r1)/tan(45);
- down(thickness/2+dy) {
- difference() {
- cube([2*c1/cos(45),2*c1/cos(45),2*h], center=true);
- cylinder(h=h, r1=r1-0.5, r2=c1-0.5, center=false, $fn=teeth*4);
- }
- }
- up(thickness/2-0.01) {
- cylinder(h=(c2-r2)/tan(45)*5, r1=r2-0.5, r2=lerp(r2-0.5,c2-0.5,5), center=false, $fn=teeth*4);
- }
- }
- }
- }
- children();
- }
+ thickness = face_width * cos(bevelang);
+ slices = spiral_rad==0? 1 : slices;
+ spiral_rad = spiral_rad==0? 10000 : spiral_rad;
+ p1 = pitch_radius(pitch, teeth);
+ r1 = root_radius(pitch, teeth, clearance, interior);
+ c1 = outer_radius(pitch, teeth, clearance, interior);
+ dx = thickness * tan(bevelang);
+ dy = (p1-r1) * sin(bevelang);
+ scl = (p1-dx)/p1;
+ p2 = pitch_radius(pitch*scl, teeth);
+ r2 = root_radius(pitch*scl, teeth, clearance, interior);
+ c2 = outer_radius(pitch*scl, teeth, clearance, interior);
+ slice_u = 1/slices;
+ Rm = (p1+p2)/2;
+ H = spiral_rad * cos(spiral_ang);
+ V = Rm - abs(spiral_rad) * sin(spiral_ang);
+ spiral_cp = [H,V,0];
+ S = norm(spiral_cp);
+ theta_r = acos((S*S+spiral_rad*spiral_rad-p1*p1)/(2*S*spiral_rad)) - acos((S*S+spiral_rad*spiral_rad-p2*p2)/(2*S*spiral_rad));
+ theta_ro = acos((S*S+spiral_rad*spiral_rad-p1*p1)/(2*S*spiral_rad)) - acos((S*S+spiral_rad*spiral_rad-Rm*Rm)/(2*S*spiral_rad));
+ theta_ri = theta_r - theta_ro;
+ extent_u = 2*(p2-r2)*tan(bevelang) / thickness;
+ slice_us = concat(
+ [for (u = [0:slice_u:1+extent_u]) u]
+ );
+ lsus = len(slice_us);
+ vertices = concat(
+ [
+ for (u=slice_us, tooth=[0:1:teeth-1]) let(
+ p = lerp(p1,p2,u),
+ r = lerp(r1,r2,u),
+ theta = lerp(-theta_ro, theta_ri, u),
+ profile = gear_tooth_profile(
+ pitch = pitch*(p/p1),
+ teeth = teeth,
+ PA = PA,
+ clearance = clearance,
+ backlash = backlash,
+ interior = interior,
+ valleys = false
+ ),
+ pp = rot(theta, cp=spiral_cp, p=[0,Rm,0]),
+ ang = atan2(pp.y,pp.x)-90,
+ pts = apply_list(
+ path3d(profile), [
+ move([0,-p,0]),
+ rot([0,ang,0]),
+ rot([bevelang,0,0]),
+ move(pp),
+ rot(tooth*360/teeth),
+ move([0,0,thickness*u])
+ ]
+ )
+ ) each pts
+ ], [
+ [0,0,-dy], [0,0,thickness]
+ ]
+ );
+ lcnt = (len(vertices)-2)/lsus/teeth;
+ function _gv(layer,tooth,i) = ((layer*teeth)+(tooth%teeth))*lcnt+(i%lcnt);
+ function _lv(layer,i) = layer*teeth*lcnt+(i%(teeth*lcnt));
+ faces = concat(
+ [
+ for (sl=[0:1:lsus-2], i=[0:1:lcnt*teeth-1]) each [
+ [_lv(sl,i), _lv(sl+1,i), _lv(sl,i+1)],
+ [_lv(sl+1,i), _lv(sl+1,i+1), _lv(sl,i+1)]
+ ]
+ ], [
+ for (tooth=[0:1:teeth-1], i=[0:1:lcnt/2-1]) each [
+ [_gv(0,tooth,i), _gv(0,tooth,i+1), _gv(0,tooth,lcnt-1-(i+1))],
+ [_gv(0,tooth,i), _gv(0,tooth,lcnt-1-(i+1)), _gv(0,tooth,lcnt-1-i)],
+ [_gv(lsus-1,tooth,i), _gv(lsus-1,tooth,lcnt-1-(i+1)), _gv(lsus-1,tooth,i+1)],
+ [_gv(lsus-1,tooth,i), _gv(lsus-1,tooth,lcnt-1-i), _gv(lsus-1,tooth,lcnt-1-(i+1))],
+ ]
+ ], [
+ for (tooth=[0:1:teeth-1]) each [
+ [len(vertices)-2, _gv(0,tooth,0), _gv(0,tooth,lcnt-1)],
+ [len(vertices)-2, _gv(0,tooth,lcnt-1), _gv(0,tooth+1,0)],
+ [len(vertices)-1, _gv(lsus-1,tooth,lcnt-1), _gv(lsus-1,tooth,0)],
+ [len(vertices)-1, _gv(lsus-1,tooth+1,0), _gv(lsus-1,tooth,lcnt-1)],
+ ]
+ ]
+ );
+ attachable(anchor,spin,orient, r1=p1, r2=p2, l=thickness) {
+ union() {
+ difference() {
+ down(thickness/2) {
+ polyhedron(points=vertices, faces=faces, convexity=floor(teeth/2));
+ }
+ if (shaft_diam > 0) {
+ cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
+ }
+ if (bevelang != 0) {
+ h = (c1-r1)/tan(45);
+ down(thickness/2+dy) {
+ difference() {
+ cube([2*c1/cos(45),2*c1/cos(45),2*h], center=true);
+ cylinder(h=h, r1=r1-0.5, r2=c1-0.5, center=false, $fn=teeth*4);
+ }
+ }
+ up(thickness/2-0.01) {
+ cylinder(h=(c2-r2)/tan(45)*5, r1=r2-0.5, r2=lerp(r2-0.5,c2-0.5,5), center=false, $fn=teeth*4);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -614,57 +614,57 @@ module bevel_gear(
// Example:
// rack(pitch=5, teeth=10, thickness=5, height=5, PA=20);
module rack(
- pitch = 5,
- teeth = 20,
- thickness = 5,
- height = 10,
- PA = 28,
- backlash = 0.0,
- clearance = undef,
- anchor = CENTER,
- spin = 0,
- orient = UP
+ pitch = 5,
+ teeth = 20,
+ thickness = 5,
+ height = 10,
+ PA = 28,
+ backlash = 0.0,
+ clearance = undef,
+ anchor = CENTER,
+ spin = 0,
+ orient = UP
) {
- a = adendum(pitch);
- d = dedendum(pitch, clearance);
- xa = a * sin(PA);
- xd = d * sin(PA);
- l = teeth * pitch;
- anchors = [
- anchorpt("adendum", [0,a,0], BACK),
- anchorpt("adendum-left", [-l/2,a,0], LEFT),
- anchorpt("adendum-right", [l/2,a,0], RIGHT),
- anchorpt("adendum-top", [0,a,thickness/2], UP),
- anchorpt("adendum-bottom", [0,a,-thickness/2], DOWN),
- anchorpt("dedendum", [0,-d,0], BACK),
- anchorpt("dedendum-left", [-l/2,-d,0], LEFT),
- anchorpt("dedendum-right", [l/2,-d,0], RIGHT),
- anchorpt("dedendum-top", [0,-d,thickness/2], UP),
- anchorpt("dedendum-bottom", [0,-d,-thickness/2], DOWN),
- ];
- attachable(anchor,spin,orient, size=[l, 2*abs(a-height), thickness], anchors=anchors) {
- left((teeth-1)*pitch/2) {
- linear_extrude(height = thickness, center = true, convexity = 10) {
- for (i = [0:1:teeth-1] ) {
- translate([i*pitch,0,0]) {
- polygon(
- points=[
- [-1/2 * pitch - 0.01, a-height],
- [-1/2 * pitch, -d],
- [-1/4 * pitch + backlash - xd, -d],
- [-1/4 * pitch + backlash + xa, a],
- [ 1/4 * pitch - backlash - xa, a],
- [ 1/4 * pitch - backlash + xd, -d],
- [ 1/2 * pitch, -d],
- [ 1/2 * pitch + 0.01, a-height],
- ]
- );
- }
- }
- }
- }
- children();
- }
+ a = adendum(pitch);
+ d = dedendum(pitch, clearance);
+ xa = a * sin(PA);
+ xd = d * sin(PA);
+ l = teeth * pitch;
+ anchors = [
+ anchorpt("adendum", [0,a,0], BACK),
+ anchorpt("adendum-left", [-l/2,a,0], LEFT),
+ anchorpt("adendum-right", [l/2,a,0], RIGHT),
+ anchorpt("adendum-top", [0,a,thickness/2], UP),
+ anchorpt("adendum-bottom", [0,a,-thickness/2], DOWN),
+ anchorpt("dedendum", [0,-d,0], BACK),
+ anchorpt("dedendum-left", [-l/2,-d,0], LEFT),
+ anchorpt("dedendum-right", [l/2,-d,0], RIGHT),
+ anchorpt("dedendum-top", [0,-d,thickness/2], UP),
+ anchorpt("dedendum-bottom", [0,-d,-thickness/2], DOWN),
+ ];
+ attachable(anchor,spin,orient, size=[l, 2*abs(a-height), thickness], anchors=anchors) {
+ left((teeth-1)*pitch/2) {
+ linear_extrude(height = thickness, center = true, convexity = 10) {
+ for (i = [0:1:teeth-1] ) {
+ translate([i*pitch,0,0]) {
+ polygon(
+ points=[
+ [-1/2 * pitch - 0.01, a-height],
+ [-1/2 * pitch, -d],
+ [-1/4 * pitch + backlash - xd, -d],
+ [-1/4 * pitch + backlash + xa, a],
+ [ 1/4 * pitch - backlash - xa, a],
+ [ 1/4 * pitch - backlash + xd, -d],
+ [ 1/2 * pitch, -d],
+ [ 1/2 * pitch + 0.01, a-height],
+ ]
+ );
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -698,5 +698,5 @@ translate([(-floor(n5/2)-floor(n1/2)+$t+n1/2-1/2)*9, -d1+0.0, 0]) rotate([0,0,0]
*/
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/joiners.scad b/joiners.scad
index 2613a77..a8afb4d 100644
--- a/joiners.scad
+++ b/joiners.scad
@@ -34,29 +34,29 @@ include
// half_joiner_clear(spin=-90);
module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
{
- dmnd_height = h*1.0;
- dmnd_width = dmnd_height*tan(a);
- guide_size = w/3;
- guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
+ dmnd_height = h*1.0;
+ dmnd_width = dmnd_height*tan(a);
+ guide_size = w/3;
+ guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
- attachable(anchor,spin,orient, size=[w, guide_width, h]) {
- union() {
- ycopies(overlap, n=overlap>0? 2 : 1) {
- difference() {
- // Diamonds.
- scale([w+clearance, dmnd_width/2, dmnd_height/2]) {
- xrot(45) cube(size=[1,sqrt(2),sqrt(2)], center=true);
- }
- // Blunt point of tab.
- ycopies(guide_width+4) {
- cube(size=[(w+clearance)*1.05, 4, h*0.99], center=true);
- }
- }
- }
- if (overlap>0) cube([w+clearance, overlap+0.001, h], center=true);
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[w, guide_width, h]) {
+ union() {
+ ycopies(overlap, n=overlap>0? 2 : 1) {
+ difference() {
+ // Diamonds.
+ scale([w+clearance, dmnd_width/2, dmnd_height/2]) {
+ xrot(45) cube(size=[1,sqrt(2),sqrt(2)], center=true);
+ }
+ // Blunt point of tab.
+ ycopies(guide_width+4) {
+ cube(size=[(w+clearance)*1.05, 4, h*0.99], center=true);
+ }
+ }
+ }
+ if (overlap>0) cube([w+clearance, overlap+0.001, h], center=true);
+ }
+ children();
+ }
}
@@ -81,60 +81,60 @@ module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, anchor=CEN
// half_joiner(screwsize=3, spin=-90);
module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
{
- dmnd_height = h*1.0;
- dmnd_width = dmnd_height*tan(a);
- guide_size = w/3;
- guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
+ dmnd_height = h*1.0;
+ dmnd_width = dmnd_height*tan(a);
+ guide_size = w/3;
+ guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
- render(convexity=12)
- attachable(anchor,spin,orient, size=[w, 2*l, h]) {
- difference() {
- union() {
- // Make base.
- difference() {
- // Solid backing base.
- fwd(l/2) cube(size=[w, l, h], center=true);
+ render(convexity=12)
+ attachable(anchor,spin,orient, size=[w, 2*l, h]) {
+ difference() {
+ union() {
+ // Make base.
+ difference() {
+ // Solid backing base.
+ fwd(l/2) cube(size=[w, l, h], center=true);
- // Clear diamond for tab
- xcopies(2*w*2/3) {
- half_joiner_clear(h=h+0.01, w=w, clearance=$slop*2, a=a);
- }
- }
+ // Clear diamond for tab
+ xcopies(2*w*2/3) {
+ half_joiner_clear(h=h+0.01, w=w, clearance=$slop*2, a=a);
+ }
+ }
- difference() {
- // Make tab
- scale([w/3-$slop*2, dmnd_width/2, dmnd_height/2]) xrot(45)
- cube(size=[1,sqrt(2),sqrt(2)], center=true);
+ difference() {
+ // Make tab
+ scale([w/3-$slop*2, dmnd_width/2, dmnd_height/2]) xrot(45)
+ cube(size=[1,sqrt(2),sqrt(2)], center=true);
- // Blunt point of tab.
- back(guide_width/2+2)
- cube(size=[w*0.99,4,guide_size*2], center=true);
- }
+ // Blunt point of tab.
+ back(guide_width/2+2)
+ cube(size=[w*0.99,4,guide_size*2], center=true);
+ }
- // Guide ridges.
- if (guides == true) {
- xcopies(w/3-$slop*2) {
- // Guide ridge.
- fwd(0.05/2) {
- scale([0.75, 1, 2]) yrot(45)
- cube(size=[guide_size/sqrt(2), guide_width+0.05, guide_size/sqrt(2)], center=true);
- }
+ // Guide ridges.
+ if (guides == true) {
+ xcopies(w/3-$slop*2) {
+ // Guide ridge.
+ fwd(0.05/2) {
+ scale([0.75, 1, 2]) yrot(45)
+ cube(size=[guide_size/sqrt(2), guide_width+0.05, guide_size/sqrt(2)], center=true);
+ }
- // Snap ridge.
- scale([0.25, 0.5, 1]) zrot(45)
- cube(size=[guide_size/sqrt(2), guide_size/sqrt(2), dmnd_width], center=true);
- }
- }
- }
+ // Snap ridge.
+ scale([0.25, 0.5, 1]) zrot(45)
+ cube(size=[guide_size/sqrt(2), guide_size/sqrt(2), dmnd_width], center=true);
+ }
+ }
+ }
- // Make screwholes, if needed.
- if (screwsize != undef) {
- yrot(90) cylinder(r=screwsize*1.1/2, h=w+1, center=true, $fn=12);
- }
- }
- children();
- }
+ // Make screwholes, if needed.
+ if (screwsize != undef) {
+ yrot(90) cylinder(r=screwsize*1.1/2, h=w+1, center=true, $fn=12);
+ }
+ }
+ children();
+ }
}
//half_joiner(screwsize=3);
@@ -159,29 +159,29 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=
// half_joiner2(screwsize=3, spin=-90);
module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
{
- dmnd_height = h*1.0;
- dmnd_width = dmnd_height*tan(a);
- guide_size = w/3;
- guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
+ dmnd_height = h*1.0;
+ dmnd_width = dmnd_height*tan(a);
+ guide_size = w/3;
+ guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
- render(convexity=12)
- attachable(anchor,spin,orient, size=[w, 2*l, h]) {
- difference() {
- union () {
- fwd(l/2) cube(size=[w, l, h], center=true);
- cube([w, guide_width, h], center=true);
- }
+ render(convexity=12)
+ attachable(anchor,spin,orient, size=[w, 2*l, h]) {
+ difference() {
+ union () {
+ fwd(l/2) cube(size=[w, l, h], center=true);
+ cube([w, guide_width, h], center=true);
+ }
- // Subtract mated half_joiner.
- zrot(180) half_joiner(h=h+0.01, w=w+0.01, l=guide_width+0.01, a=a, screwsize=undef, guides=guides, $slop=0.0);
+ // Subtract mated half_joiner.
+ zrot(180) half_joiner(h=h+0.01, w=w+0.01, l=guide_width+0.01, a=a, screwsize=undef, guides=guides, $slop=0.0);
- // Make screwholes, if needed.
- if (screwsize != undef) {
- xcyl(r=screwsize*1.1/2, l=w+1, $fn=12);
- }
- }
- children();
- }
+ // Make screwholes, if needed.
+ if (screwsize != undef) {
+ xcyl(r=screwsize*1.1/2, l=w+1, $fn=12);
+ }
+ }
+ children();
+ }
}
@@ -207,18 +207,18 @@ module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor
// joiner_clear(spin=-90);
module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
{
- dmnd_height = h*0.5;
- dmnd_width = dmnd_height*tan(a);
- guide_size = w/3;
- guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
+ dmnd_height = h*0.5;
+ dmnd_width = dmnd_height*tan(a);
+ guide_size = w/3;
+ guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
- attachable(anchor,spin,orient, size=[w, guide_width, h]) {
- union() {
- up(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=clearance);
- down(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=-0.01);
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[w, guide_width, h]) {
+ union() {
+ up(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=clearance);
+ down(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=-0.01);
+ }
+ children();
+ }
}
@@ -244,13 +244,13 @@ module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER,
// joiner(w=10, l=10, h=40, spin=-90) cuboid([10, 10*2, 40], anchor=RIGHT);
module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
{
- attachable(anchor,spin,orient, size=[w, 2*l, h]) {
- union() {
- up(h/4) half_joiner(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
- down(h/4) half_joiner2(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[w, 2*l, h]) {
+ union() {
+ up(h/4) half_joiner(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
+ down(h/4) half_joiner2(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
+ }
+ children();
+ }
}
@@ -279,17 +279,17 @@ module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTE
// joiner_pair_clear(spacing=50, n=3);
module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
{
- dmnd_height = h*0.5;
- dmnd_width = dmnd_height*tan(a);
- guide_size = w/3;
- guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
+ dmnd_height = h*0.5;
+ dmnd_width = dmnd_height*tan(a);
+ guide_size = w/3;
+ guide_width = 2*(dmnd_height/2-guide_size)*tan(a);
- attachable(anchor,spin,orient, size=[spacing+w, guide_width, h]) {
- xcopies(spacing, n=n) {
- joiner_clear(h=h, w=w, a=a, clearance=clearance, overlap=overlap);
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[spacing+w, guide_width, h]) {
+ xcopies(spacing, n=n) {
+ joiner_clear(h=h, w=w, a=a, clearance=clearance, overlap=overlap);
+ }
+ children();
+ }
}
@@ -321,18 +321,18 @@ module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overla
// joiner_pair(spacing=50, l=10, n=3, alternate="alt", spin=-90);
module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
{
- attachable(anchor,spin,orient, size=[spacing+w, 2*l, h]) {
- left((n-1)*spacing/2) {
- for (i=[0:1:n-1]) {
- right(i*spacing) {
- yrot(180 + (alternate? (i*180+(alternate=="alt"?180:0))%360 : 0)) {
- joiner(h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
- }
- }
- }
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[spacing+w, 2*l, h]) {
+ left((n-1)*spacing/2) {
+ for (i=[0:1:n-1]) {
+ right(i*spacing) {
+ yrot(180 + (alternate? (i*180+(alternate=="alt"?180:0))%360 : 0)) {
+ joiner(h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -362,16 +362,16 @@ module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, scr
// joiner_quad_clear(spacing1=50, spacing2=50, n=3);
module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing2=undef, n=2, h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
{
- spacing1 = first_defined([spacing1, xspacing, 100]);
- spacing2 = first_defined([spacing2, yspacing, 50]);
- attachable(anchor,spin,orient, size=[w+spacing1, spacing2, h]) {
- zrot_copies(n=2) {
- back(spacing2/2) {
- joiner_pair_clear(spacing=spacing1, n=n, h=h, w=w, a=a, clearance=clearance, overlap=overlap);
- }
- }
- children();
- }
+ spacing1 = first_defined([spacing1, xspacing, 100]);
+ spacing2 = first_defined([spacing2, yspacing, 50]);
+ attachable(anchor,spin,orient, size=[w+spacing1, spacing2, h]) {
+ zrot_copies(n=2) {
+ back(spacing2/2) {
+ joiner_pair_clear(spacing=spacing1, n=n, h=h, w=w, a=a, clearance=clearance, overlap=overlap);
+ }
+ }
+ children();
+ }
}
@@ -403,16 +403,16 @@ module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing
// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate="alt", spin=-90);
module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=undef, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
{
- spacing1 = first_defined([spacing1, xspacing, 100]);
- spacing2 = first_defined([spacing2, yspacing, 50]);
- attachable(anchor,spin,orient, size=[w+spacing1, spacing2, h]) {
- zrot_copies(n=2) {
- back(spacing2/2) {
- joiner_pair(spacing=spacing1, n=n, h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
- }
- }
- children();
- }
+ spacing1 = first_defined([spacing1, xspacing, 100]);
+ spacing2 = first_defined([spacing2, yspacing, 50]);
+ attachable(anchor,spin,orient, size=[w+spacing1, spacing2, h]) {
+ zrot_copies(n=2) {
+ back(spacing2/2) {
+ joiner_pair(spacing=spacing1, n=n, h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
+ }
+ }
+ children();
+ }
}
@@ -497,70 +497,70 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde
// position(TOP+BACK) xcopies(10,5) dovetail("female", length=10, width=7, taper=4, height=4, $tags="remove",anchor=BOTTOM+FRONT,spin=180);
module dovetail(gender, length, l, width, w, height, h, angle, slope, taper, back_width, chamfer, extra=0.01, r, radius, round=false, anchor=BOTTOM, spin=0, orient)
{
- radius = get_radius(r1=radius,r2=r);
- lcount = num_defined([l,length]);
- hcount = num_defined([h,height]);
- wcount = num_defined([w,width]);
- assert(lcount==1, "Must define exactly one of l and length");
- assert(wcount==1, "Must define exactly one of w and width");
- assert(hcount==1, "Must define exactly one of h and height");
- h = first_defined([h,height]);
- w = first_defined([w,width]);
- length = first_defined([l,length]);
- orient = is_def(orient) ? orient :
- gender == "female" ? DOWN : UP;
- count = num_defined([angle,slope]);
- assert(count<=1, "Do not specify both angle and slope");
- count2 = num_defined([taper,back_width]);
- assert(count2<=1, "Do not specify both taper and back_width");
- count3 = num_defined([chamfer, radius]);
- assert(count3<=1 || (radius==0 && chamfer==0), "Do not specify both chamfer and radius");
- slope = is_def(slope) ? slope :
- is_def(angle) ? 1/tan(angle) : 6;
- width = gender == "male" ? w : w + 2*$slop;
- height = h + (gender == "female" ? 2*$slop : 0);
+ radius = get_radius(r1=radius,r2=r);
+ lcount = num_defined([l,length]);
+ hcount = num_defined([h,height]);
+ wcount = num_defined([w,width]);
+ assert(lcount==1, "Must define exactly one of l and length");
+ assert(wcount==1, "Must define exactly one of w and width");
+ assert(hcount==1, "Must define exactly one of h and height");
+ h = first_defined([h,height]);
+ w = first_defined([w,width]);
+ length = first_defined([l,length]);
+ orient = is_def(orient) ? orient :
+ gender == "female" ? DOWN : UP;
+ count = num_defined([angle,slope]);
+ assert(count<=1, "Do not specify both angle and slope");
+ count2 = num_defined([taper,back_width]);
+ assert(count2<=1, "Do not specify both taper and back_width");
+ count3 = num_defined([chamfer, radius]);
+ assert(count3<=1 || (radius==0 && chamfer==0), "Do not specify both chamfer and radius");
+ slope = is_def(slope) ? slope :
+ is_def(angle) ? 1/tan(angle) : 6;
+ width = gender == "male" ? w : w + 2*$slop;
+ height = h + (gender == "female" ? 2*$slop : 0);
- front_offset = is_def(taper) ? -extra * tan(taper) :
- is_def(back_width) ? extra * (back_width-width)/length/2 : 0;
+ front_offset = is_def(taper) ? -extra * tan(taper) :
+ is_def(back_width) ? extra * (back_width-width)/length/2 : 0;
- size = is_def(chamfer) && chamfer>0 ? chamfer :
- is_def(radius) && radius>0 ? radius : 0;
- type = is_def(chamfer) && chamfer>0 ? "chamfer" : "circle";
+ size = is_def(chamfer) && chamfer>0 ? chamfer :
+ is_def(radius) && radius>0 ? radius : 0;
+ type = is_def(chamfer) && chamfer>0 ? "chamfer" : "circle";
- fullsize = round ? [size,size] :
- gender == "male" ? [size,0] : [0,size];
+ fullsize = round ? [size,size] :
+ gender == "male" ? [size,0] : [0,size];
- smallend_half = round_corners(
- move(
- [0,-length/2-extra,0],
- p=[
- [0 , 0, height],
- [width/2-front_offset , 0, height],
- [width/2 - height/slope - front_offset, 0, 0 ],
- [width/2 - front_offset + height, 0, 0]
- ]
- ),
- method=type, cut = fullsize, closed=false
- );
- smallend_points = concat(select(smallend_half, 1, -2), [down(extra,p=select(smallend_half, -2))]);
- offset = is_def(taper) ? -(length+extra) * tan(taper) :
- is_def(back_width) ? (back_width-width) / 2 : 0;
- bigend_points = move([offset,length+2*extra,0], p=smallend_points);
+ smallend_half = round_corners(
+ move(
+ [0,-length/2-extra,0],
+ p=[
+ [0 , 0, height],
+ [width/2-front_offset , 0, height],
+ [width/2 - height/slope - front_offset, 0, 0 ],
+ [width/2 - front_offset + height, 0, 0]
+ ]
+ ),
+ method=type, cut = fullsize, closed=false
+ );
+ smallend_points = concat(select(smallend_half, 1, -2), [down(extra,p=select(smallend_half, -2))]);
+ offset = is_def(taper) ? -(length+extra) * tan(taper) :
+ is_def(back_width) ? (back_width-width) / 2 : 0;
+ bigend_points = move([offset,length+2*extra,0], p=smallend_points);
- adjustment = gender == "male" ? -0.01 : 0.01; // Adjustment for default overlap in attach()
+ adjustment = gender == "male" ? -0.01 : 0.01; // Adjustment for default overlap in attach()
- attachable(anchor,spin,orient, size=[width+2*offset, length, height]) {
- down(height/2+adjustment) {
- skin(
- [
- reverse(concat(smallend_points, xflip(p=reverse(smallend_points)))),
- reverse(concat(bigend_points, xflip(p=reverse(bigend_points))))
- ],
- slices=0, convexity=4
- );
- }
- children();
- }
+ attachable(anchor,spin,orient, size=[width+2*offset, length, height]) {
+ down(height/2+adjustment) {
+ skin(
+ [
+ reverse(concat(smallend_points, xflip(p=reverse(smallend_points)))),
+ reverse(concat(bigend_points, xflip(p=reverse(bigend_points))))
+ ],
+ slices=0, convexity=4
+ );
+ }
+ children();
+ }
}
@@ -781,4 +781,4 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/knurling.scad b/knurling.scad
index bcf44a5..c2c6f52 100644
--- a/knurling.scad
+++ b/knurling.scad
@@ -48,79 +48,79 @@
// knurled_cylinder(l=30, r=20, count=30, profile=90, helix=30);
// knurled_cylinder(l=30, r=20, count=20, profile=120, helix=30);
module knurled_cylinder(
- l=20,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- count=30, profile=120, helix=30,
- chamfer=undef, chamfer1=undef, chamfer2=undef,
- chamfang=undef, chamfang1=undef, chamfang2=undef,
- from_end=false,
- rounding=undef, rounding1=undef, rounding2=undef,
- anchor=CENTER, spin=0, orient=UP
+ l=20,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ count=30, profile=120, helix=30,
+ chamfer=undef, chamfer1=undef, chamfer2=undef,
+ chamfang=undef, chamfang1=undef, chamfang2=undef,
+ from_end=false,
+ rounding=undef, rounding1=undef, rounding2=undef,
+ anchor=CENTER, spin=0, orient=UP
) {
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
- inset = r1 * sin(180/count) / tan(profile/2);
- twist = 360*l*tan(helix)/(r1*2*PI);
- c1 = circle(r=r1,$fn=count);
- c2 = rot(-180/count,p=circle(r=r1-inset,$fn=count));
- path = [for (i=idx(c1)) each [c1[i],c2[i]]];
- knob_w = 2*PI*r1/count;
- knob_h = knob_w / tan(helix);
- layers = ceil(l/knob_h);
- plen = len(path);
- vertices = concat(
- [
- for (layer = [0:1:layers], pt=path)
- (layer%2)? [pt.x, pt.y, layer*knob_h-layers*knob_h/2] :
- rot(180/count, p=[pt.x, pt.y, layer*knob_h-layers*knob_h/2])
- ], [
- [0,0,-layers*knob_h/2],
- [0,0, layers*knob_h/2]
- ]
- );
- faces = concat(
- [
- for (layer = [0:1:layers-1], i=idx(path)) let(
- loff = (layer%2)? 2 : 0,
- i1 = layer*plen+((i+1)%plen),
- i2 = layer*plen+((i+2)%plen),
- i3 = (layer+1)*plen+posmod(i+1+loff,plen),
- i4 = (layer+1)*plen+posmod(i+2+loff,plen),
- i5 = (layer+1)*plen+posmod(i-0+loff,plen),
- i6 = (layer+1)*plen+posmod(i-1+loff,plen)
- ) each [
- [i1, i2, ((i%2)? i5 : i3)],
- [i3, i5, ((i%2)? i2 : i1)]
- ]
- ], [
- for (i=[0:1:count-1]) let(
- i1 = posmod(i*2+1,plen),
- i2 = posmod(i*2+2,plen),
- i3 = posmod(i*2+3,plen),
- loff = layers*plen
- ) each [
- [i1,i3,i2],
- [i1+loff,i2+loff,i3+loff],
- [i3,i1,len(vertices)-2],
- [i1+loff,i3+loff,len(vertices)-1]
- ]
- ]
- );
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- intersection() {
- polyhedron(points=vertices, faces=faces, convexity=2*layers);
- cyl(
- r1=r1, r2=r2, l=l,
- chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
- chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
- from_end=from_end,
- rounding=rounding, rounding1=rounding1, rounding2=rounding2,
- $fn=count*2
- );
- }
- children();
- }
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
+ inset = r1 * sin(180/count) / tan(profile/2);
+ twist = 360*l*tan(helix)/(r1*2*PI);
+ c1 = circle(r=r1,$fn=count);
+ c2 = rot(-180/count,p=circle(r=r1-inset,$fn=count));
+ path = [for (i=idx(c1)) each [c1[i],c2[i]]];
+ knob_w = 2*PI*r1/count;
+ knob_h = knob_w / tan(helix);
+ layers = ceil(l/knob_h);
+ plen = len(path);
+ vertices = concat(
+ [
+ for (layer = [0:1:layers], pt=path)
+ (layer%2)? [pt.x, pt.y, layer*knob_h-layers*knob_h/2] :
+ rot(180/count, p=[pt.x, pt.y, layer*knob_h-layers*knob_h/2])
+ ], [
+ [0,0,-layers*knob_h/2],
+ [0,0, layers*knob_h/2]
+ ]
+ );
+ faces = concat(
+ [
+ for (layer = [0:1:layers-1], i=idx(path)) let(
+ loff = (layer%2)? 2 : 0,
+ i1 = layer*plen+((i+1)%plen),
+ i2 = layer*plen+((i+2)%plen),
+ i3 = (layer+1)*plen+posmod(i+1+loff,plen),
+ i4 = (layer+1)*plen+posmod(i+2+loff,plen),
+ i5 = (layer+1)*plen+posmod(i-0+loff,plen),
+ i6 = (layer+1)*plen+posmod(i-1+loff,plen)
+ ) each [
+ [i1, i2, ((i%2)? i5 : i3)],
+ [i3, i5, ((i%2)? i2 : i1)]
+ ]
+ ], [
+ for (i=[0:1:count-1]) let(
+ i1 = posmod(i*2+1,plen),
+ i2 = posmod(i*2+2,plen),
+ i3 = posmod(i*2+3,plen),
+ loff = layers*plen
+ ) each [
+ [i1,i3,i2],
+ [i1+loff,i2+loff,i3+loff],
+ [i3,i1,len(vertices)-2],
+ [i1+loff,i3+loff,len(vertices)-1]
+ ]
+ ]
+ );
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ intersection() {
+ polyhedron(points=vertices, faces=faces, convexity=2*layers);
+ cyl(
+ r1=r1, r2=r2, l=l,
+ chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
+ chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
+ from_end=from_end,
+ rounding=rounding, rounding1=rounding1, rounding2=rounding2,
+ $fn=count*2
+ );
+ }
+ children();
+ }
}
@@ -149,22 +149,22 @@ module knurled_cylinder(
// knurled_cylinder_mask(l=30, r=20, overage=5, profile=120, helix=30);
// knurled_cylinder_mask(l=30, r=20, overage=10, profile=120, helix=30);
module knurled_cylinder_mask(
- l=10, overage=5,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- count=30, profile=120, helix=30,
- anchor=CENTER, spin=0, orient=UP
+ l=10, overage=5,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ count=30, profile=120, helix=30,
+ anchor=CENTER, spin=0, orient=UP
) {
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- difference() {
- cylinder(r1=r1+overage, r2=r2+overage, h=l, center=true);
- knurled_cylinder(r1=r1, r2=r2, l=l+0.01);
- }
- children();
- }
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ difference() {
+ cylinder(r1=r1+overage, r2=r2+overage, h=l, center=true);
+ knurled_cylinder(r1=r1, r2=r2, l=l+0.01);
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/linear_bearings.scad b/linear_bearings.scad
index a0848e1..fe039f2 100644
--- a/linear_bearings.scad
+++ b/linear_bearings.scad
@@ -20,24 +20,24 @@ include
// Arguments:
// size = Inner size of lmXuu bearing, in mm.
function get_lmXuu_bearing_diam(size) = lookup(size, [
- [ 4.0, 8.0],
- [ 5.0, 10.0],
- [ 6.0, 12.0],
- [ 8.0, 15.0],
- [ 10.0, 19.0],
- [ 12.0, 21.0],
- [ 13.0, 23.0],
- [ 16.0, 28.0],
- [ 20.0, 32.0],
- [ 25.0, 40.0],
- [ 30.0, 45.0],
- [ 35.0, 52.0],
- [ 40.0, 60.0],
- [ 50.0, 80.0],
- [ 60.0, 90.0],
- [ 80.0, 120.0],
- [100.0, 150.0]
- ]);
+ [ 4.0, 8.0],
+ [ 5.0, 10.0],
+ [ 6.0, 12.0],
+ [ 8.0, 15.0],
+ [ 10.0, 19.0],
+ [ 12.0, 21.0],
+ [ 13.0, 23.0],
+ [ 16.0, 28.0],
+ [ 20.0, 32.0],
+ [ 25.0, 40.0],
+ [ 30.0, 45.0],
+ [ 35.0, 52.0],
+ [ 40.0, 60.0],
+ [ 50.0, 80.0],
+ [ 60.0, 90.0],
+ [ 80.0, 120.0],
+ [100.0, 150.0]
+ ]);
// Function: get_lmXuu_bearing_length()
@@ -45,24 +45,24 @@ function get_lmXuu_bearing_diam(size) = lookup(size, [
// Arguments:
// size = Inner size of lmXuu bearing, in mm.
function get_lmXuu_bearing_length(size) = lookup(size, [
- [ 4.0, 12.0],
- [ 5.0, 15.0],
- [ 6.0, 19.0],
- [ 8.0, 24.0],
- [ 10.0, 29.0],
- [ 12.0, 30.0],
- [ 13.0, 32.0],
- [ 16.0, 37.0],
- [ 20.0, 42.0],
- [ 25.0, 59.0],
- [ 30.0, 64.0],
- [ 35.0, 70.0],
- [ 40.0, 80.0],
- [ 50.0, 100.0],
- [ 60.0, 110.0],
- [ 80.0, 140.0],
- [100.0, 175.0]
- ]);
+ [ 4.0, 12.0],
+ [ 5.0, 15.0],
+ [ 6.0, 19.0],
+ [ 8.0, 24.0],
+ [ 10.0, 29.0],
+ [ 12.0, 30.0],
+ [ 13.0, 32.0],
+ [ 16.0, 37.0],
+ [ 20.0, 42.0],
+ [ 25.0, 59.0],
+ [ 30.0, 64.0],
+ [ 35.0, 70.0],
+ [ 40.0, 80.0],
+ [ 50.0, 100.0],
+ [ 60.0, 110.0],
+ [ 80.0, 140.0],
+ [100.0, 175.0]
+ ]);
// Module: linear_bearing_housing()
@@ -83,45 +83,45 @@ function get_lmXuu_bearing_length(size) = lookup(size, [
// linear_bearing_housing(d=19, l=29, wall=2, tab=6, screwsize=2.5);
module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, anchor=BOTTOM, spin=0, orient=UP)
{
- od = d+2*wall;
- ogap = gap+2*tabwall;
- tabh = tab/2+od/2*sqrt(2)-ogap/2;
- h = od+tab/2;
- anchors = [
- anchorpt("axis", [0,0,-tab/2/2]),
- anchorpt("screw", [0,2-ogap/2,tabh-tab/2/2],FWD),
- anchorpt("nut", [0,ogap/2-2,tabh-tab/2/2],FWD)
- ];
- attachable(anchor,spin,orient, size=[l, od, h], anchors=anchors) {
- down(tab/2/2)
- difference() {
- union() {
- // Housing
- zrot(90) teardrop(r=od/2,h=l);
+ od = d+2*wall;
+ ogap = gap+2*tabwall;
+ tabh = tab/2+od/2*sqrt(2)-ogap/2;
+ h = od+tab/2;
+ anchors = [
+ anchorpt("axis", [0,0,-tab/2/2]),
+ anchorpt("screw", [0,2-ogap/2,tabh-tab/2/2],FWD),
+ anchorpt("nut", [0,ogap/2-2,tabh-tab/2/2],FWD)
+ ];
+ attachable(anchor,spin,orient, size=[l, od, h], anchors=anchors) {
+ down(tab/2/2)
+ difference() {
+ union() {
+ // Housing
+ zrot(90) teardrop(r=od/2,h=l);
- // Base
- cube([l,od,od/2], anchor=TOP);
+ // Base
+ cube([l,od,od/2], anchor=TOP);
- // Tabs
- cube([l,ogap,od/2+tab/2], anchor=BOTTOM);
- }
+ // Tabs
+ cube([l,ogap,od/2+tab/2], anchor=BOTTOM);
+ }
- // Clear bearing space
- zrot(90) teardrop(r=d/2,h=l+0.05);
+ // Clear bearing space
+ zrot(90) teardrop(r=d/2,h=l+0.05);
- // Clear gap
- cube([l+0.05,gap,od], anchor=BOTTOM);
+ // Clear gap
+ cube([l+0.05,gap,od], anchor=BOTTOM);
- up(tabh) {
- // Screwhole
- fwd(ogap/2-2+0.01) screw(screwsize=screwsize*1.06, screwlen=ogap, headsize=screwsize*2, headlen=10, orient=FWD);
+ up(tabh) {
+ // Screwhole
+ fwd(ogap/2-2+0.01) screw(screwsize=screwsize*1.06, screwlen=ogap, headsize=screwsize*2, headlen=10, orient=FWD);
- // Nut holder
- back(ogap/2-2+0.01) metric_nut(size=screwsize, hole=false, anchor=BOTTOM, orient=BACK);
- }
- }
- children();
- }
+ // Nut holder
+ back(ogap/2-2+0.01) metric_nut(size=screwsize, hole=false, anchor=BOTTOM, orient=BACK);
+ }
+ }
+ children();
+ }
}
@@ -142,10 +142,10 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw
// lmXuu_housing(size=10, wall=2, tab=6, screwsize=2.5);
module lmXuu_housing(size=8, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, anchor=BOTTOM, spin=0, orient=UP)
{
- d = get_lmXuu_bearing_diam(size);
- l = get_lmXuu_bearing_length(size);
- linear_bearing_housing(d=d, l=l, tab=tab, gap=gap, wall=wall, tabwall=tabwall, screwsize=screwsize, orient=orient, spin=spin, anchor=anchor) children();
+ d = get_lmXuu_bearing_diam(size);
+ l = get_lmXuu_bearing_length(size);
+ linear_bearing_housing(d=d, l=l, tab=tab, gap=gap, wall=wall, tabwall=tabwall, screwsize=screwsize, orient=orient, spin=spin, anchor=anchor) children();
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/masks.scad b/masks.scad
index 6f6c43f..4a75886 100644
--- a/masks.scad
+++ b/masks.scad
@@ -31,19 +31,19 @@
// Example(FR):
// angle_pie_mask(ang=30, d=100, l=20);
module angle_pie_mask(
- ang=45, l=undef,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- h=undef,
- anchor=CENTER, spin=0, orient=UP
+ ang=45, l=undef,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ h=undef,
+ anchor=CENTER, spin=0, orient=UP
) {
- l = first_defined([l, h, 1]);
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- pie_slice(ang=ang, l=l+0.1, r1=r1, r2=r2, anchor=CENTER);
- children();
- }
+ l = first_defined([l, h, 1]);
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ pie_slice(ang=ang, l=l+0.1, r1=r1, r2=r2, anchor=CENTER);
+ children();
+ }
}
@@ -98,53 +98,53 @@ module angle_pie_mask(
// cube([100,50,100], center=true);
// }
module cylinder_mask(
- l,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- chamfer=undef, chamfer1=undef, chamfer2=undef,
- chamfang=undef, chamfang1=undef, chamfang2=undef,
- rounding=undef, rounding1=undef, rounding2=undef,
- circum=false, from_end=false,
- overage=10, ends_only=false,
- anchor=CENTER, spin=0, orient=UP
+ l,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ chamfer=undef, chamfer1=undef, chamfer2=undef,
+ chamfang=undef, chamfang1=undef, chamfang2=undef,
+ rounding=undef, rounding1=undef, rounding2=undef,
+ circum=false, from_end=false,
+ overage=10, ends_only=false,
+ anchor=CENTER, spin=0, orient=UP
) {
- r1 = get_radius(r=r, d=d, r1=r1, d1=d1, dflt=1);
- r2 = get_radius(r=r, d=d, r1=r2, d1=d2, dflt=1);
- sides = segs(max(r1,r2));
- sc = circum? 1/cos(180/sides) : 1;
- vang = atan2(l, r1-r2)/2;
- ang1 = first_defined([chamfang1, chamfang, vang]);
- ang2 = first_defined([chamfang2, chamfang, 90-vang]);
- cham1 = first_defined([chamfer1, chamfer, 0]);
- cham2 = first_defined([chamfer2, chamfer, 0]);
- fil1 = first_defined([rounding1, rounding, 0]);
- fil2 = first_defined([rounding2, rounding, 0]);
- maxd = max(r1,r2);
- if ($children > 0) {
- difference() {
- children();
- cylinder_mask(l=l, r1=sc*r1, r2=sc*r2, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, rounding1=fil1, rounding2=fil2, orient=orient, from_end=from_end);
- }
- } else {
- attachable(anchor,spin,orient, r=r1, l=l) {
- difference() {
- union() {
- chlen1 = cham1 / (from_end? 1 : tan(ang1));
- chlen2 = cham2 / (from_end? 1 : tan(ang2));
- if (!ends_only) {
- cylinder(r=maxd+overage, h=l+2*overage, center=true);
- } else {
- if (cham2>0) up(l/2-chlen2) cylinder(r=maxd+overage, h=chlen2+overage, center=false);
- if (cham1>0) down(l/2+overage) cylinder(r=maxd+overage, h=chlen1+overage, center=false);
- if (fil2>0) up(l/2-fil2) cylinder(r=maxd+overage, h=fil2+overage, center=false);
- if (fil1>0) down(l/2+overage) cylinder(r=maxd+overage, h=fil1+overage, center=false);
- }
- }
- cyl(r1=sc*r1, r2=sc*r2, l=l, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, from_end=from_end, rounding1=fil1, rounding2=fil2);
- }
- nil();
- }
- }
+ r1 = get_radius(r=r, d=d, r1=r1, d1=d1, dflt=1);
+ r2 = get_radius(r=r, d=d, r1=r2, d1=d2, dflt=1);
+ sides = segs(max(r1,r2));
+ sc = circum? 1/cos(180/sides) : 1;
+ vang = atan2(l, r1-r2)/2;
+ ang1 = first_defined([chamfang1, chamfang, vang]);
+ ang2 = first_defined([chamfang2, chamfang, 90-vang]);
+ cham1 = first_defined([chamfer1, chamfer, 0]);
+ cham2 = first_defined([chamfer2, chamfer, 0]);
+ fil1 = first_defined([rounding1, rounding, 0]);
+ fil2 = first_defined([rounding2, rounding, 0]);
+ maxd = max(r1,r2);
+ if ($children > 0) {
+ difference() {
+ children();
+ cylinder_mask(l=l, r1=sc*r1, r2=sc*r2, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, rounding1=fil1, rounding2=fil2, orient=orient, from_end=from_end);
+ }
+ } else {
+ attachable(anchor,spin,orient, r=r1, l=l) {
+ difference() {
+ union() {
+ chlen1 = cham1 / (from_end? 1 : tan(ang1));
+ chlen2 = cham2 / (from_end? 1 : tan(ang2));
+ if (!ends_only) {
+ cylinder(r=maxd+overage, h=l+2*overage, center=true);
+ } else {
+ if (cham2>0) up(l/2-chlen2) cylinder(r=maxd+overage, h=chlen2+overage, center=false);
+ if (cham1>0) down(l/2+overage) cylinder(r=maxd+overage, h=chlen1+overage, center=false);
+ if (fil2>0) up(l/2-fil2) cylinder(r=maxd+overage, h=fil2+overage, center=false);
+ if (fil1>0) down(l/2+overage) cylinder(r=maxd+overage, h=fil1+overage, center=false);
+ }
+ }
+ cyl(r1=sc*r1, r2=sc*r2, l=l, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, from_end=from_end, rounding1=fil1, rounding2=fil2);
+ }
+ nil();
+ }
+ }
}
@@ -171,10 +171,10 @@ module cylinder_mask(
// #chamfer_mask(l=50, chamfer=10, orient=RIGHT);
// }
module chamfer_mask(l=1, chamfer=1, anchor=CENTER, spin=0, orient=UP) {
- attachable(anchor,spin,orient, size=[chamfer*2, chamfer*2, l]) {
- cylinder(r=chamfer, h=l+0.1, center=true, $fn=4);
- children();
- }
+ attachable(anchor,spin,orient, size=[chamfer*2, chamfer*2, l]) {
+ cylinder(r=chamfer, h=l+0.1, center=true, $fn=4);
+ children();
+ }
}
@@ -196,7 +196,7 @@ module chamfer_mask(l=1, chamfer=1, anchor=CENTER, spin=0, orient=UP) {
// #chamfer_mask_x(l=50, chamfer=10);
// }
module chamfer_mask_x(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
- chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=RIGHT) children();
+ chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=RIGHT) children();
}
@@ -218,7 +218,7 @@ module chamfer_mask_x(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
// #chamfer_mask_y(l=50, chamfer=10);
// }
module chamfer_mask_y(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
- chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=BACK) children();
+ chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=BACK) children();
}
@@ -240,7 +240,7 @@ module chamfer_mask_y(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
// #chamfer_mask_z(l=50, chamfer=10);
// }
module chamfer_mask_z(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
- chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=UP) children();
+ chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=UP) children();
}
@@ -264,13 +264,13 @@ module chamfer_mask_z(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) {
// }
module chamfer(chamfer=1, size=[1,1,1], edges=EDGES_ALL, except_edges=[])
{
- difference() {
- children();
- difference() {
- cube(size, center=true);
- cuboid(size+[1,1,1]*0.02, chamfer=chamfer+0.01, edges=edges, except_edges=except_edges, trimcorners=true);
- }
- }
+ difference() {
+ children();
+ difference() {
+ cube(size, center=true);
+ cuboid(size+[1,1,1]*0.02, chamfer=chamfer+0.01, edges=edges, except_edges=except_edges, trimcorners=true);
+ }
+ }
}
@@ -303,11 +303,11 @@ module chamfer(chamfer=1, size=[1,1,1], edges=EDGES_ALL, except_edges=[])
// }
module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, anchor=CENTER, spin=0, orient=UP)
{
- r = get_radius(r=r, d=d, dflt=1);
- attachable(anchor,spin,orient, r=r, l=chamfer*2) {
- cylinder_mask(l=chamfer*3, r=r, chamfer2=chamfer, chamfang2=ang, from_end=from_end, ends_only=true, anchor=TOP);
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ attachable(anchor,spin,orient, r=r, l=chamfer*2) {
+ cylinder_mask(l=chamfer*3, r=r, chamfer2=chamfer, chamfang2=ang, from_end=from_end, ends_only=true, anchor=TOP);
+ children();
+ }
}
@@ -344,17 +344,17 @@ module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=fa
// chamfer_hole_mask(d=100, chamfer=25, ang=30, overage=10);
module chamfer_hole_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, overage=0.1, anchor=CENTER, spin=0, orient=UP)
{
- r = get_radius(r=r, d=d, dflt=1);
- h = chamfer * (from_end? 1 : tan(90-ang));
- r2 = r + chamfer * (from_end? tan(ang) : 1);
- $fn = segs(r);
- attachable(anchor,spin,orient, r1=r, r2=r2, l=h*2) {
- union() {
- cylinder(r=r2, h=overage, center=false);
- down(h) cylinder(r1=r, r2=r2, h=h, center=false);
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ h = chamfer * (from_end? 1 : tan(90-ang));
+ r2 = r + chamfer * (from_end? tan(ang) : 1);
+ $fn = segs(r);
+ attachable(anchor,spin,orient, r1=r, r2=r2, l=h*2) {
+ union() {
+ cylinder(r=r2, h=overage, center=false);
+ down(h) cylinder(r1=r, r2=r2, h=h, center=false);
+ }
+ children();
+ }
}
@@ -406,30 +406,30 @@ module chamfer_hole_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false,
// }
module rounding_mask(l=undef, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0, orient=UP, h=undef)
{
- l = first_defined([l, h, 1]);
- r1 = get_radius(r1=r1, r=r, dflt=1);
- r2 = get_radius(r1=r2, r=r, dflt=1);
- sides = quantup(segs(max(r1,r2)),4);
- attachable(anchor,spin,orient, size=[2*r1,2*r1,l], size2=[2*r2,2*r2]) {
- if (r10 && angle<90);
- r = get_radius(r=r, d=d, dflt=1);
- difference() {
- translate(-[1,1,1]*excess) cube(r+excess, center=false);
- translate([1,1,1]*r) onion(r=r,maxang=angle,orient=DOWN);
- }
+ assert(is_num(angle));
+ assert(is_num(excess));
+ assert(angle>0 && angle<90);
+ r = get_radius(r=r, d=d, dflt=1);
+ difference() {
+ translate(-[1,1,1]*excess) cube(r+excess, center=false);
+ translate([1,1,1]*r) onion(r=r,maxang=angle,orient=DOWN);
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/math.scad b/math.scad
index 15f738a..f8dc707 100644
--- a/math.scad
+++ b/math.scad
@@ -109,10 +109,10 @@ function factorial(n,d=1) = product([for (i=[n:-1:d]) i]);
// // Points colored in ROYGBIV order.
// rainbow(pts) translate($item) circle(d=3,$fn=8);
function lerp(a,b,u) =
- assert(same_shape(a,b), "Bad or inconsistent inputs to lerp")
- is_num(u)? (1-u)*a + u*b :
- assert(!is_undef(u)&&!is_bool(u)&&!is_string(u), "Input u to lerp must be a number, vector, or range.")
- [for (v = u) lerp(a,b,v)];
+ assert(same_shape(a,b), "Bad or inconsistent inputs to lerp")
+ is_num(u)? (1-u)*a + u*b :
+ assert(!is_undef(u)&&!is_bool(u)&&!is_string(u), "Input u to lerp must be a number, vector, or range.")
+ [for (v = u) lerp(a,b,v)];
@@ -121,37 +121,37 @@ function lerp(a,b,u) =
// Function: sinh()
// Description: Takes a value `x`, and returns the hyperbolic sine of it.
function sinh(x) =
- (exp(x)-exp(-x))/2;
+ (exp(x)-exp(-x))/2;
// Function: cosh()
// Description: Takes a value `x`, and returns the hyperbolic cosine of it.
function cosh(x) =
- (exp(x)+exp(-x))/2;
+ (exp(x)+exp(-x))/2;
// Function: tanh()
// Description: Takes a value `x`, and returns the hyperbolic tangent of it.
function tanh(x) =
- sinh(x)/cosh(x);
+ sinh(x)/cosh(x);
// Function: asinh()
// Description: Takes a value `x`, and returns the inverse hyperbolic sine of it.
function asinh(x) =
- ln(x+sqrt(x*x+1));
+ ln(x+sqrt(x*x+1));
// Function: acosh()
// Description: Takes a value `x`, and returns the inverse hyperbolic cosine of it.
function acosh(x) =
- ln(x+sqrt(x*x-1));
+ ln(x+sqrt(x*x-1));
// Function: atanh()
// Description: Takes a value `x`, and returns the inverse hyperbolic tangent of it.
function atanh(x) =
- ln((1+x)/(1-x))/2;
+ ln((1+x)/(1-x))/2;
@@ -182,8 +182,8 @@ function atanh(x) =
// quant([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,12,12,12]
// quant([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[12,12,12]]
function quant(x,y) =
- is_list(x)? [for (v=x) quant(v,y)] :
- floor(x/y+0.5)*y;
+ is_list(x)? [for (v=x) quant(v,y)] :
+ floor(x/y+0.5)*y;
// Function: quantdn()
@@ -211,8 +211,8 @@ function quant(x,y) =
// quantdn([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,9,9,12]
// quantdn([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[9,9,12]]
function quantdn(x,y) =
- is_list(x)? [for (v=x) quantdn(v,y)] :
- floor(x/y)*y;
+ is_list(x)? [for (v=x) quantdn(v,y)] :
+ floor(x/y)*y;
// Function: quantup()
@@ -240,8 +240,8 @@ function quantdn(x,y) =
// quantup([9,10,10.4,10.5,11,12],3); // Returns: [9,12,12,12,12,12]
// quantup([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,12,12],[12,12,12]]
function quantup(x,y) =
- is_list(x)? [for (v=x) quantup(v,y)] :
- ceil(x/y)*y;
+ is_list(x)? [for (v=x) quantup(v,y)] :
+ ceil(x/y)*y;
// Section: Constraints and Modulos
@@ -296,7 +296,7 @@ function posmod(x,m) = (x%m+m)%m;
// modang(270,360); // Returns: -90
// modang(700,360); // Returns: -20
function modang(x) =
- let(xx = posmod(x,360)) xx<180? xx : xx-360;
+ let(xx = posmod(x,360)) xx<180? xx : xx-360;
// Function: modrange()
@@ -315,11 +315,11 @@ function modang(x) =
// modrange(90,270,360, step=-45); // Returns: [90,45,0,315,270]
// modrange(270,90,360, step=-45); // Returns: [270,225,180,135,90]
function modrange(x, y, m, step=1) =
- let(
- a = posmod(x, m),
- b = posmod(y, m),
- c = step>0? (a>b? b+m : b) : (a0? (a>b? b+m : b) : (a= min, "Max value cannot be smaller than min")
- let (rvect = is_def(seed) ? rands(min,max+1,N,seed) : rands(min,max+1,N))
- [for(entry = rvect) floor(entry)];
+ assert(max >= min, "Max value cannot be smaller than min")
+ let (rvect = is_def(seed) ? rands(min,max+1,N,seed) : rands(min,max+1,N))
+ [for(entry = rvect) floor(entry)];
// Function: gaussian_rands()
@@ -355,8 +355,8 @@ function rand_int(min, max, N, seed=undef) =
// N = Number of random numbers to return. Default: 1
// seed = If given, sets the random number seed.
function gaussian_rands(mean, stddev, N=1, seed=undef) =
- let(nums = is_undef(seed)? rands(0,1,N*2) : rands(0,1,N*2,seed))
- [for (i = list_range(N)) mean + stddev*sqrt(-2*ln(nums[i*2]))*cos(360*nums[i*2+1])];
+ let(nums = is_undef(seed)? rands(0,1,N*2) : rands(0,1,N*2,seed))
+ [for (i = list_range(N)) mean + stddev*sqrt(-2*ln(nums[i*2]))*cos(360*nums[i*2+1])];
// Function: log_rands()
@@ -371,12 +371,12 @@ function gaussian_rands(mean, stddev, N=1, seed=undef) =
// N = Number of random numbers to return. Default: 1
// seed = If given, sets the random number seed.
function log_rands(minval, maxval, factor, N=1, seed=undef) =
- assert(maxval >= minval, "maxval cannot be smaller than minval")
- let(
- minv = 1-1/pow(factor,minval),
- maxv = 1-1/pow(factor,maxval),
- nums = is_undef(seed)? rands(minv, maxv, N) : rands(minv, maxv, N, seed)
- ) [for (num=nums) -ln(1-num)/ln(factor)];
+ assert(maxval >= minval, "maxval cannot be smaller than minval")
+ let(
+ minv = 1-1/pow(factor,minval),
+ maxv = 1-1/pow(factor,maxval),
+ nums = is_undef(seed)? rands(minv, maxv, N) : rands(minv, maxv, N, seed)
+ ) [for (num=nums) -ln(1-num)/ln(factor)];
@@ -388,22 +388,22 @@ function log_rands(minval, maxval, factor, N=1, seed=undef) =
// Description:
// Computes the Greatest Common Divisor/Factor of `a` and `b`.
function gcd(a,b) =
- assert(is_int(a) && is_int(b),"Arguments to gcd must be integers")
- b==0 ? abs(a) : gcd(b,a % b);
+ assert(is_int(a) && is_int(b),"Arguments to gcd must be integers")
+ b==0 ? abs(a) : gcd(b,a % b);
// Computes lcm for two scalars
function _lcm(a,b) =
- assert(is_int(a), "Invalid non-integer parameters to lcm")
- assert(is_int(b), "Invalid non-integer parameters to lcm")
- assert(a!=0 && b!=0, "Arguments to lcm must be nonzero")
- abs(a*b) / gcd(a,b);
+ assert(is_int(a), "Invalid non-integer parameters to lcm")
+ assert(is_int(b), "Invalid non-integer parameters to lcm")
+ assert(a!=0 && b!=0, "Arguments to lcm must be nonzero")
+ abs(a*b) / gcd(a,b);
// Computes lcm for a list of values
function _lcmlist(a) =
- len(a)==1 ? a[0] :
- _lcmlist(concat(slice(a,0,len(a)-2),[lcm(a[len(a)-2],a[len(a)-1])]));
+ len(a)==1 ? a[0] :
+ _lcmlist(concat(slice(a,0,len(a)-2),[lcm(a[len(a)-2],a[len(a)-1])]));
// Function: lcm()
@@ -415,12 +415,12 @@ function _lcmlist(a) =
// be non-zero integers. The output is always a positive integer. It is an error to pass zero
// as an argument.
function lcm(a,b=[]) =
- !is_list(a) && !is_list(b) ? _lcm(a,b) :
- let(
- arglist = concat(force_list(a),force_list(b))
- )
- assert(len(arglist)>0,"invalid call to lcm with empty list(s)")
- _lcmlist(arglist);
+ !is_list(a) && !is_list(b) ? _lcm(a,b) :
+ let(
+ arglist = concat(force_list(a),force_list(b))
+ )
+ assert(len(arglist)>0,"invalid call to lcm with empty list(s)")
+ _lcmlist(arglist);
@@ -438,8 +438,8 @@ function lcm(a,b=[]) =
// sum([1,2,3]); // returns 6.
// sum([[1,2,3], [3,4,5], [5,6,7]]); // returns [9, 12, 15]
function sum(v, dflt=0) =
- assert(is_consistent(v), "Input to sum is non-numeric or inconsistent")
- len(v) == 0 ? dflt : _sum(v,v[0]*0);
+ assert(is_consistent(v), "Input to sum is non-numeric or inconsistent")
+ len(v) == 0 ? dflt : _sum(v,v[0]*0);
function _sum(v,_total,_i=0) = _i>=len(v) ? _total : _sum(v,_total+v[_i], _i+1);
@@ -456,14 +456,14 @@ function _sum(v,_total,_i=0) = _i>=len(v) ? _total : _sum(v,_total+v[_i], _i+1);
// cumsum([1,2,3]); // returns [1,3,6]
// cumsum([[1,2,3], [3,4,5], [5,6,7]]); // returns [[1,2,3], [4,6,8], [9,12,15]]
function cumsum(v,_i=0,_acc=[]) =
- _i==len(v) ? _acc :
- cumsum(
- v, _i+1,
- concat(
- _acc,
- [_i==0 ? v[_i] : select(_acc,-1)+v[_i]]
- )
- );
+ _i==len(v) ? _acc :
+ cumsum(
+ v, _i+1,
+ concat(
+ _acc,
+ [_i==0 ? v[_i] : select(_acc,-1)+v[_i]]
+ )
+ );
// Function: sum_of_squares()
@@ -489,12 +489,12 @@ function sum_of_squares(v, i=0, tot=0) = sum(vmul(v,v));
// Examples:
// v = sum_of_sines(30, [[10,3,0], [5,5.5,60]]);
function sum_of_sines(a, sines) =
- sum([
- for (s = sines) let(
- ss=point3d(s),
- v=ss.x*sin(a*ss.y+ss.z)
- ) v
- ]);
+ sum([
+ for (s = sines) let(
+ ss=point3d(s),
+ v=ss.x*sin(a*ss.y+ss.z)
+ ) v
+ ]);
// Function: deltas()
@@ -541,16 +541,16 @@ function mean(v) = sum(v)/len(v);
// Given a list of numbers or vectors, finds the median value or midpoint.
// If passed a list of vectors, returns the vector of the median of each part.
function median(v) =
- assert(is_list(v))
- assert(len(v)>0)
- is_vector(v[0])? (
- assert(is_consistent(v))
- [
- for (i=idx(v[0]))
- let(vals = subindex(v,i))
- (min(vals)+max(vals))/2
- ]
- ) : (min(v)+max(v))/2;
+ assert(is_list(v))
+ assert(len(v)>0)
+ is_vector(v[0])? (
+ assert(is_consistent(v))
+ [
+ for (i=idx(v[0]))
+ let(vals = subindex(v,i))
+ (min(vals)+max(vals))/2
+ ]
+ ) : (min(v)+max(v))/2;
// Section: Matrix math
@@ -565,23 +565,23 @@ function median(v) =
// want to solve Ax=b1 and Ax=b2 that you need to form the matrix transpose([b1,b2]) for the right hand side and then
// transpose the returned value.
function linear_solve(A,b) =
- assert(is_matrix(A))
- let(
- m = len(A),
- n = len(A[0])
- )
- assert(is_vector(b,m) || is_matrix(b,m),"Incompatible matrix and right hand side")
- let (
- qr = mj ? 0 : qr[1][i][j]
- ]
- ]
- ) [qr[0],Rzero];
+ assert(is_matrix(A))
+ let(
+ m = len(A),
+ n = len(A[0])
+ )
+ let(
+ qr =_qr_factor(A, column=0, m = m, n=n, Q=ident(m)),
+ Rzero = [
+ for(i=[0:m-1]) [
+ for(j=[0:n-1])
+ i>j ? 0 : qr[1][i][j]
+ ]
+ ]
+ ) [qr[0],Rzero];
function _qr_factor(A,Q, column, m, n) =
- column >= min(m-1,n) ? [Q,A] :
- let(
- x = [for(i=[column:1:m-1]) A[i][column]],
- alpha = (x[0]<=0 ? 1 : -1) * norm(x),
- u = x - concat([alpha],repeat(0,m-1)),
- v = u / norm(u),
- Qc = ident(len(x)) - 2*transpose([v])*[v],
- Qf = [for(i=[0:m-1]) [for(j=[0:m-1]) i= min(m-1,n) ? [Q,A] :
+ let(
+ x = [for(i=[column:1:m-1]) A[i][column]],
+ alpha = (x[0]<=0 ? 1 : -1) * norm(x),
+ u = x - concat([alpha],repeat(0,m-1)),
+ v = u / norm(u),
+ Qc = ident(len(x)) - 2*transpose([v])*[v],
+ Qf = [for(i=[0:m-1]) [for(j=[0:m-1]) i0 &&
- (is_undef(m) || len(A)==m) &&
- is_vector(A[0]) &&
- (is_undef(n) || len(A[0])==n) &&
- (!square || n==m) &&
- is_consistent(A);
+ is_list(A) && len(A)>0 &&
+ (is_undef(m) || len(A)==m) &&
+ is_vector(A[0]) &&
+ (is_undef(n) || len(A[0])==n) &&
+ (!square || n==m) &&
+ is_consistent(A);
@@ -758,18 +758,18 @@ function is_matrix(A,m,n, square=false) =
// approx(0.3333,1/3,eps=1e-3); // Returns: true
// approx(PI,3.1415926536); // Returns: true
function approx(a,b,eps=EPSILON) =
- a==b? true :
- a*0!=b*0? false :
- is_list(a)? ([for (i=idx(a)) if(!approx(a[i],b[i],eps=eps)) 1] == []) :
- (abs(a-b) <= eps);
+ a==b? true :
+ a*0!=b*0? false :
+ is_list(a)? ([for (i=idx(a)) if(!approx(a[i],b[i],eps=eps)) 1] == []) :
+ (abs(a-b) <= eps);
function _type_num(x) =
- is_undef(x)? 0 :
- is_bool(x)? 1 :
- is_num(x)? 2 :
- is_string(x)? 3 :
- is_list(x)? 4 : 5;
+ is_undef(x)? 0 :
+ is_bool(x)? 1 :
+ is_num(x)? 2 :
+ is_string(x)? 3 :
+ is_list(x)? 4 : 5;
// Function: compare_vals()
@@ -782,10 +782,10 @@ function _type_num(x) =
// a = First value to compare.
// b = Second value to compare.
function compare_vals(a, b) =
- (a==b)? 0 :
- let(t1=_type_num(a), t2=_type_num(b)) (t1!=t2)? (t1-t2) :
- is_list(a)? compare_lists(a,b) :
- (ab)? 1 : 0;
+ (a==b)? 0 :
+ let(t1=_type_num(a), t2=_type_num(b)) (t1!=t2)? (t1-t2) :
+ is_list(a)? compare_lists(a,b) :
+ (ab)? 1 : 0;
// Function: compare_lists()
@@ -800,13 +800,13 @@ function compare_vals(a, b) =
// a = First list to compare.
// b = Second list to compare.
function compare_lists(a, b) =
- a==b? 0 : let(
- cmps = [
- for(i=[0:1:min(len(a),len(b))-1]) let(
- cmp = compare_vals(a[i],b[i])
- ) if(cmp!=0) cmp
- ]
- ) cmps==[]? (len(a)-len(b)) : cmps[0];
+ a==b? 0 : let(
+ cmps = [
+ for(i=[0:1:min(len(a),len(b))-1]) let(
+ cmp = compare_vals(a[i],b[i])
+ ) if(cmp!=0) cmp
+ ]
+ ) cmps==[]? (len(a)-len(b)) : cmps[0];
// Function: any()
@@ -822,13 +822,13 @@ function compare_lists(a, b) =
// any([[0,0], [0,0]]); // Returns false.
// any([[0,0], [1,0]]); // Returns true.
function any(l, i=0, succ=false) =
- (i>=len(l) || succ)? succ :
- any(
- l, i=i+1, succ=(
- is_list(l[i])? any(l[i]) :
- !(!l[i])
- )
- );
+ (i>=len(l) || succ)? succ :
+ any(
+ l, i=i+1, succ=(
+ is_list(l[i])? any(l[i]) :
+ !(!l[i])
+ )
+ );
// Function: all()
@@ -845,13 +845,13 @@ function any(l, i=0, succ=false) =
// all([[0,0], [1,0]]); // Returns false.
// all([[1,1], [1,1]]); // Returns true.
function all(l, i=0, fail=false) =
- (i>=len(l) || fail)? (!fail) :
- all(
- l, i=i+1, fail=(
- is_list(l[i])? !all(l[i]) :
- !l[i]
- )
- );
+ (i>=len(l) || fail)? (!fail) :
+ all(
+ l, i=i+1, fail=(
+ is_list(l[i])? !all(l[i]) :
+ !l[i]
+ )
+ );
// Function: count_true()
@@ -875,13 +875,13 @@ function all(l, i=0, fail=false) =
// count_true([[1,1], [1,1]]); // Returns 4.
// count_true([[1,1], [1,1]], nmax=3); // Returns 3.
function count_true(l, nmax=undef, i=0, cnt=0) =
- (i>=len(l) || (nmax!=undef && cnt>=nmax))? cnt :
- count_true(
- l=l, nmax=nmax, i=i+1, cnt=cnt+(
- is_list(l[i])? count_true(l[i], nmax=nmax-cnt) :
- (l[i]? 1 : 0)
- )
- );
+ (i>=len(l) || (nmax!=undef && cnt>=nmax))? cnt :
+ count_true(
+ l=l, nmax=nmax, i=i+1, cnt=cnt+(
+ is_list(l[i])? count_true(l[i], nmax=nmax-cnt) :
+ (l[i]? 1 : 0)
+ )
+ );
@@ -897,23 +897,23 @@ function count_true(l, nmax=undef, i=0, cnt=0) =
// for internal points, f'(t) = (f(t+h)-f(t-h))/2h. For the endpoints (when closed=false) the algorithm
// uses a two point method if sufficient points are available: f'(t) = (3*(f(t+h)-f(t)) - (f(t+2*h)-f(t+h)))/2h.
function deriv(data, h=1, closed=false) =
- let( L = len(data) )
- closed? [
- for(i=[0:1:L-1])
- (data[(i+1)%L]-data[(L+i-1)%L])/2/h
- ] :
- let(
- first =
- L<3? data[1]-data[0] :
- 3*(data[1]-data[0]) - (data[2]-data[1]),
- last =
- L<3? data[L-1]-data[L-2]:
- (data[L-3]-data[L-2])-3*(data[L-2]-data[L-1])
- ) [
- first/2/h,
- for(i=[1:1:L-2]) (data[i+1]-data[i-1])/2/h,
- last/2/h
- ];
+ let( L = len(data) )
+ closed? [
+ for(i=[0:1:L-1])
+ (data[(i+1)%L]-data[(L+i-1)%L])/2/h
+ ] :
+ let(
+ first =
+ L<3? data[1]-data[0] :
+ 3*(data[1]-data[0]) - (data[2]-data[1]),
+ last =
+ L<3? data[L-1]-data[L-2]:
+ (data[L-3]-data[L-2])-3*(data[L-2]-data[L-1])
+ ) [
+ first/2/h,
+ for(i=[1:1:L-2]) (data[i+1]-data[i-1])/2/h,
+ last/2/h
+ ];
// Function: deriv2()
@@ -928,25 +928,25 @@ function deriv(data, h=1, closed=false) =
// f''(t) = (2*f(t) - 5*f(t+h) + 4*f(t+2*h) - f(t+3*h))/h^2 or if five points are available
// f''(t) = (35*f(t) - 104*f(t+h) + 114*f(t+2*h) - 56*f(t+3*h) + 11*f(t+4*h)) / 12h^2
function deriv2(data, h=1, closed=false) =
- let( L = len(data) )
- closed? [
- for(i=[0:1:L-1])
- (data[(i+1)%L]-2*data[i]+data[(L+i-1)%L])/h/h
- ] :
- let(
- first = L<3? undef :
- L==3? data[0] - 2*data[1] + data[2] :
- L==4? 2*data[0] - 5*data[1] + 4*data[2] - data[3] :
- (35*data[0] - 104*data[1] + 114*data[2] - 56*data[3] + 11*data[4])/12,
- last = L<3? undef :
- L==3? data[L-1] - 2*data[L-2] + data[L-3] :
- L==4? -2*data[L-1] + 5*data[L-2] - 4*data[L-3] + data[L-4] :
- (35*data[L-1] - 104*data[L-2] + 114*data[L-3] - 56*data[L-4] + 11*data[L-5])/12
- ) [
- first/h/h,
- for(i=[1:1:L-2]) (data[i+1]-2*data[i]+data[i-1])/h/h,
- last/h/h
- ];
+ let( L = len(data) )
+ closed? [
+ for(i=[0:1:L-1])
+ (data[(i+1)%L]-2*data[i]+data[(L+i-1)%L])/h/h
+ ] :
+ let(
+ first = L<3? undef :
+ L==3? data[0] - 2*data[1] + data[2] :
+ L==4? 2*data[0] - 5*data[1] + 4*data[2] - data[3] :
+ (35*data[0] - 104*data[1] + 114*data[2] - 56*data[3] + 11*data[4])/12,
+ last = L<3? undef :
+ L==3? data[L-1] - 2*data[L-2] + data[L-3] :
+ L==4? -2*data[L-1] + 5*data[L-2] - 4*data[L-3] + data[L-4] :
+ (35*data[L-1] - 104*data[L-2] + 114*data[L-3] - 56*data[L-4] + 11*data[L-5])/12
+ ) [
+ first/h/h,
+ for(i=[1:1:L-2]) (data[i+1]-2*data[i]+data[i-1])/h/h,
+ last/h/h
+ ];
// Function: deriv3()
@@ -960,28 +960,28 @@ function deriv2(data, h=1, closed=false) =
// the estimates are f'''(t) = (-5*f(t)+18*f(t+h)-24*f(t+2*h)+14*f(t+3*h)-3*f(t+4*h)) / 2h^3 and
// f'''(t) = (-3*f(t-h)+10*f(t)-12*f(t+h)+6*f(t+2*h)-f(t+3*h)) / 2h^3.
function deriv3(data, h=1, closed=false) =
- let(
- L = len(data),
- h3 = h*h*h
- )
- assert(L>=5, "Need five points for 3rd derivative estimate")
- closed? [
- for(i=[0:1:L-1])
- (-data[(L+i-2)%L]+2*data[(L+i-1)%L]-2*data[(i+1)%L]+data[(i+2)%L])/2/h3
- ] :
- let(
- first=(-5*data[0]+18*data[1]-24*data[2]+14*data[3]-3*data[4])/2,
- second=(-3*data[0]+10*data[1]-12*data[2]+6*data[3]-data[4])/2,
- last=(5*data[L-1]-18*data[L-2]+24*data[L-3]-14*data[L-4]+3*data[L-5])/2,
- prelast=(3*data[L-1]-10*data[L-2]+12*data[L-3]-6*data[L-4]+data[L-5])/2
- ) [
- first/h3,
- second/h3,
- for(i=[2:1:L-3]) (-data[i-2]+2*data[i-1]-2*data[i+1]+data[i+2])/2/h3,
- prelast/h3,
- last/h3
- ];
+ let(
+ L = len(data),
+ h3 = h*h*h
+ )
+ assert(L>=5, "Need five points for 3rd derivative estimate")
+ closed? [
+ for(i=[0:1:L-1])
+ (-data[(L+i-2)%L]+2*data[(L+i-1)%L]-2*data[(i+1)%L]+data[(i+2)%L])/2/h3
+ ] :
+ let(
+ first=(-5*data[0]+18*data[1]-24*data[2]+14*data[3]-3*data[4])/2,
+ second=(-3*data[0]+10*data[1]-12*data[2]+6*data[3]-data[4])/2,
+ last=(5*data[L-1]-18*data[L-2]+24*data[L-3]-14*data[L-4]+3*data[L-5])/2,
+ prelast=(3*data[L-1]-10*data[L-2]+12*data[L-3]-6*data[L-4]+data[L-5])/2
+ ) [
+ first/h3,
+ second/h3,
+ for(i=[2:1:L-3]) (-data[i-2]+2*data[i-1]-2*data[i+1]+data[i+2])/2/h3,
+ prelast/h3,
+ last/h3
+ ];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/metric_screws.scad b/metric_screws.scad
index 81b0de7..01ae5aa 100644
--- a/metric_screws.scad
+++ b/metric_screws.scad
@@ -20,339 +20,339 @@ include
// Function: get_metric_bolt_head_size()
// Description: Returns the diameter of a typical metric bolt's head, based on the bolt `size`.
function get_metric_bolt_head_size(size) = lookup(size, [
- [ 3.0, 5.5],
- [ 4.0, 7.0],
- [ 5.0, 8.0],
- [ 6.0, 10.0],
- [ 7.0, 11.0],
- [ 8.0, 13.0],
- [10.0, 17.0],
- [12.0, 19.0],
- [14.0, 22.0],
- [16.0, 24.0],
- [18.0, 27.0],
- [20.0, 30.0],
- [24.0, 36.0],
- [30.0, 46.0],
- [36.0, 55.0],
- [42.0, 65.0],
- [48.0, 75.0],
- [56.0, 85.0],
- [64.0, 95.0]
- ]);
+ [ 3.0, 5.5],
+ [ 4.0, 7.0],
+ [ 5.0, 8.0],
+ [ 6.0, 10.0],
+ [ 7.0, 11.0],
+ [ 8.0, 13.0],
+ [10.0, 17.0],
+ [12.0, 19.0],
+ [14.0, 22.0],
+ [16.0, 24.0],
+ [18.0, 27.0],
+ [20.0, 30.0],
+ [24.0, 36.0],
+ [30.0, 46.0],
+ [36.0, 55.0],
+ [42.0, 65.0],
+ [48.0, 75.0],
+ [56.0, 85.0],
+ [64.0, 95.0]
+ ]);
// Function: get_metric_bolt_head_height()
// Description: Returns the height of a typical metric bolt's head, based on the bolt `size`.
function get_metric_bolt_head_height(size) = lookup(size, [
- [ 1.6, 1.23],
- [ 2.0, 1.53],
- [ 2.5, 1.83],
- [ 3.0, 2.13],
- [ 4.0, 2.93],
- [ 5.0, 3.65],
- [ 6.0, 4.15],
- [ 8.0, 5.45],
- [10.0, 6.58],
- [12.0, 7.68],
- [14.0, 8.98],
- [16.0, 10.18],
- [20.0, 12.72],
- [24.0, 15.35],
- [30.0, 19.12],
- [36.0, 22.92],
- [42.0, 26.42],
- [48.0, 30.42],
- [56.0, 35.50],
- [64.0, 40.50]
- ]);
+ [ 1.6, 1.23],
+ [ 2.0, 1.53],
+ [ 2.5, 1.83],
+ [ 3.0, 2.13],
+ [ 4.0, 2.93],
+ [ 5.0, 3.65],
+ [ 6.0, 4.15],
+ [ 8.0, 5.45],
+ [10.0, 6.58],
+ [12.0, 7.68],
+ [14.0, 8.98],
+ [16.0, 10.18],
+ [20.0, 12.72],
+ [24.0, 15.35],
+ [30.0, 19.12],
+ [36.0, 22.92],
+ [42.0, 26.42],
+ [48.0, 30.42],
+ [56.0, 35.50],
+ [64.0, 40.50]
+ ]);
// Function: get_metric_socket_cap_diam()
// Description: Returns the diameter of a typical metric socket cap bolt's head, based on the bolt `size`.
function get_metric_socket_cap_diam(size) = lookup(size, [
- [ 1.6, 3.0],
- [ 2.0, 3.8],
- [ 2.5, 4.5],
- [ 3.0, 5.5],
- [ 4.0, 7.0],
- [ 5.0, 8.5],
- [ 6.0, 10.0],
- [ 8.0, 13.0],
- [10.0, 16.0],
- [12.0, 18.0],
- [14.0, 21.0],
- [16.0, 24.0],
- [18.0, 27.0],
- [20.0, 30.0],
- [22.0, 33.0],
- [24.0, 36.0],
- [27.0, 40.0],
- [30.0, 45.0],
- [33.0, 50.0],
- [36.0, 54.0],
- [42.0, 63.0],
- [48.0, 72.0],
- [56.0, 84.0],
- [64.0, 96.0]
- ]);
+ [ 1.6, 3.0],
+ [ 2.0, 3.8],
+ [ 2.5, 4.5],
+ [ 3.0, 5.5],
+ [ 4.0, 7.0],
+ [ 5.0, 8.5],
+ [ 6.0, 10.0],
+ [ 8.0, 13.0],
+ [10.0, 16.0],
+ [12.0, 18.0],
+ [14.0, 21.0],
+ [16.0, 24.0],
+ [18.0, 27.0],
+ [20.0, 30.0],
+ [22.0, 33.0],
+ [24.0, 36.0],
+ [27.0, 40.0],
+ [30.0, 45.0],
+ [33.0, 50.0],
+ [36.0, 54.0],
+ [42.0, 63.0],
+ [48.0, 72.0],
+ [56.0, 84.0],
+ [64.0, 96.0]
+ ]);
// Function: get_metric_socket_cap_height()
// Description: Returns the height of a typical metric socket cap bolt's head, based on the bolt `size`.
function get_metric_socket_cap_height(size) = lookup(size, [
- [ 1.6, 1.7],
- [ 2.0, 2.0],
- [ 2.5, 2.5],
- [ 3.0, 3.0],
- [ 4.0, 4.0],
- [ 5.0, 5.0],
- [ 6.0, 6.0],
- [ 8.0, 8.0],
- [10.0, 10.0],
- [12.0, 12.0],
- [14.0, 14.0],
- [16.0, 16.0],
- [18.0, 18.0],
- [20.0, 20.0],
- [22.0, 22.0],
- [24.0, 24.0],
- [27.0, 27.0],
- [30.0, 30.0],
- [33.0, 33.0],
- [36.0, 36.0],
- [42.0, 42.0],
- [48.0, 48.0],
- [56.0, 56.0],
- [64.0, 64.0]
- ]);
+ [ 1.6, 1.7],
+ [ 2.0, 2.0],
+ [ 2.5, 2.5],
+ [ 3.0, 3.0],
+ [ 4.0, 4.0],
+ [ 5.0, 5.0],
+ [ 6.0, 6.0],
+ [ 8.0, 8.0],
+ [10.0, 10.0],
+ [12.0, 12.0],
+ [14.0, 14.0],
+ [16.0, 16.0],
+ [18.0, 18.0],
+ [20.0, 20.0],
+ [22.0, 22.0],
+ [24.0, 24.0],
+ [27.0, 27.0],
+ [30.0, 30.0],
+ [33.0, 33.0],
+ [36.0, 36.0],
+ [42.0, 42.0],
+ [48.0, 48.0],
+ [56.0, 56.0],
+ [64.0, 64.0]
+ ]);
// Function: get_metric_socket_cap_socket_size()
// Description: Returns the diameter of a typical metric socket cap bolt's hex drive socket, based on the bolt `size`.
function get_metric_socket_cap_socket_size(size) = lookup(size, [
- [ 1.6, 1.5],
- [ 2.0, 1.5],
- [ 2.5, 2.0],
- [ 3.0, 2.5],
- [ 4.0, 3.0],
- [ 5.0, 4.0],
- [ 6.0, 5.0],
- [ 8.0, 6.0],
- [10.0, 8.0],
- [12.0, 10.0],
- [14.0, 12.0],
- [16.0, 14.0],
- [18.0, 14.0],
- [20.0, 17.0],
- [22.0, 17.0],
- [24.0, 19.0],
- [27.0, 19.0],
- [30.0, 22.0],
- [33.0, 24.0],
- [36.0, 27.0],
- [42.0, 32.0],
- [48.0, 36.0],
- [56.0, 41.0],
- [64.0, 46.0]
- ]);
+ [ 1.6, 1.5],
+ [ 2.0, 1.5],
+ [ 2.5, 2.0],
+ [ 3.0, 2.5],
+ [ 4.0, 3.0],
+ [ 5.0, 4.0],
+ [ 6.0, 5.0],
+ [ 8.0, 6.0],
+ [10.0, 8.0],
+ [12.0, 10.0],
+ [14.0, 12.0],
+ [16.0, 14.0],
+ [18.0, 14.0],
+ [20.0, 17.0],
+ [22.0, 17.0],
+ [24.0, 19.0],
+ [27.0, 19.0],
+ [30.0, 22.0],
+ [33.0, 24.0],
+ [36.0, 27.0],
+ [42.0, 32.0],
+ [48.0, 36.0],
+ [56.0, 41.0],
+ [64.0, 46.0]
+ ]);
// Function: get_metric_socket_cap_socket_depth()
// Description: Returns the depth of a typical metric socket cap bolt's hex drive socket, based on the bolt `size`.
function get_metric_socket_cap_socket_depth(size) = lookup(size, [
- [ 1.6, 0.7],
- [ 2.0, 1.0],
- [ 2.5, 1.1],
- [ 3.0, 1.3],
- [ 4.0, 2.0],
- [ 5.0, 2.5],
- [ 6.0, 3.0],
- [ 8.0, 4.0],
- [10.0, 5.0],
- [12.0, 6.0],
- [14.0, 7.0],
- [16.0, 8.0],
- [18.0, 9.0],
- [20.0, 10.0],
- [22.0, 11.0],
- [24.0, 12.0],
- [27.0, 13.5],
- [30.0, 15.5],
- [33.0, 18.0],
- [36.0, 19.0],
- [42.0, 24.0],
- [48.0, 28.0],
- [56.0, 34.0],
- [64.0, 38.0]
- ]);
+ [ 1.6, 0.7],
+ [ 2.0, 1.0],
+ [ 2.5, 1.1],
+ [ 3.0, 1.3],
+ [ 4.0, 2.0],
+ [ 5.0, 2.5],
+ [ 6.0, 3.0],
+ [ 8.0, 4.0],
+ [10.0, 5.0],
+ [12.0, 6.0],
+ [14.0, 7.0],
+ [16.0, 8.0],
+ [18.0, 9.0],
+ [20.0, 10.0],
+ [22.0, 11.0],
+ [24.0, 12.0],
+ [27.0, 13.5],
+ [30.0, 15.5],
+ [33.0, 18.0],
+ [36.0, 19.0],
+ [42.0, 24.0],
+ [48.0, 28.0],
+ [56.0, 34.0],
+ [64.0, 38.0]
+ ]);
// Function: get_metric_iso_coarse_thread_pitch()
// Description: Returns the ISO metric standard coarse threading pitch for a given bolt `size`.
function get_metric_iso_coarse_thread_pitch(size) = lookup(size, [
- [ 1.6, 0.35],
- [ 2.0, 0.40],
- [ 2.5, 0.45],
- [ 3.0, 0.50],
- [ 4.0, 0.70],
- [ 5.0, 0.80],
- [ 6.0, 1.00],
- [ 7.0, 1.00],
- [ 8.0, 1.25],
- [10.0, 1.50],
- [12.0, 1.75],
- [14.0, 2.00],
- [16.0, 2.00],
- [18.0, 2.50],
- [20.0, 2.50],
- [22.0, 2.50],
- [24.0, 3.00],
- [27.0, 3.00],
- [30.0, 3.50],
- [33.0, 3.50],
- [36.0, 4.00],
- [39.0, 4.00],
- [42.0, 4.50],
- [45.0, 4.50],
- [48.0, 5.00],
- [56.0, 5.50],
- [64.0, 6.00]
- ]);
+ [ 1.6, 0.35],
+ [ 2.0, 0.40],
+ [ 2.5, 0.45],
+ [ 3.0, 0.50],
+ [ 4.0, 0.70],
+ [ 5.0, 0.80],
+ [ 6.0, 1.00],
+ [ 7.0, 1.00],
+ [ 8.0, 1.25],
+ [10.0, 1.50],
+ [12.0, 1.75],
+ [14.0, 2.00],
+ [16.0, 2.00],
+ [18.0, 2.50],
+ [20.0, 2.50],
+ [22.0, 2.50],
+ [24.0, 3.00],
+ [27.0, 3.00],
+ [30.0, 3.50],
+ [33.0, 3.50],
+ [36.0, 4.00],
+ [39.0, 4.00],
+ [42.0, 4.50],
+ [45.0, 4.50],
+ [48.0, 5.00],
+ [56.0, 5.50],
+ [64.0, 6.00]
+ ]);
// Function: get_metric_iso_fine_thread_pitch()
// Description: Returns the ISO metric standard fine threading pitch for a given bolt `size`.
function get_metric_iso_fine_thread_pitch(size) = lookup(size, [
- [ 1.6, 0.35],
- [ 2.0, 0.40],
- [ 2.5, 0.45],
- [ 3.0, 0.50],
- [ 4.0, 0.70],
- [ 5.0, 0.80],
- [ 6.0, 1.00],
- [ 7.0, 1.00],
- [ 8.0, 1.00],
- [10.0, 1.25],
- [12.0, 1.50],
- [14.0, 1.50],
- [16.0, 2.00],
- [18.0, 2.50],
- [20.0, 2.50],
- [22.0, 2.50],
- [24.0, 3.00],
- [27.0, 3.00],
- [30.0, 3.50],
- [33.0, 3.50],
- [36.0, 4.00],
- [39.0, 4.00],
- [42.0, 4.50],
- [45.0, 4.50],
- [48.0, 5.00],
- [56.0, 5.50],
- [64.0, 6.00]
- ]);
+ [ 1.6, 0.35],
+ [ 2.0, 0.40],
+ [ 2.5, 0.45],
+ [ 3.0, 0.50],
+ [ 4.0, 0.70],
+ [ 5.0, 0.80],
+ [ 6.0, 1.00],
+ [ 7.0, 1.00],
+ [ 8.0, 1.00],
+ [10.0, 1.25],
+ [12.0, 1.50],
+ [14.0, 1.50],
+ [16.0, 2.00],
+ [18.0, 2.50],
+ [20.0, 2.50],
+ [22.0, 2.50],
+ [24.0, 3.00],
+ [27.0, 3.00],
+ [30.0, 3.50],
+ [33.0, 3.50],
+ [36.0, 4.00],
+ [39.0, 4.00],
+ [42.0, 4.50],
+ [45.0, 4.50],
+ [48.0, 5.00],
+ [56.0, 5.50],
+ [64.0, 6.00]
+ ]);
// Function: get_metric_iso_superfine_thread_pitch()
// Description: Returns the ISO metric standard superfine threading pitch for a given bolt `size`.
function get_metric_iso_superfine_thread_pitch(size) = lookup(size, [
- [ 1.6, 0.35],
- [ 2.0, 0.40],
- [ 2.5, 0.45],
- [ 3.0, 0.50],
- [ 4.0, 0.70],
- [ 5.0, 0.80],
- [ 6.0, 1.00],
- [ 7.0, 1.00],
- [ 8.0, 1.00],
- [10.0, 1.00],
- [12.0, 1.25],
- [14.0, 1.50],
- [16.0, 2.00],
- [18.0, 2.50],
- [20.0, 2.50],
- [22.0, 2.50],
- [24.0, 3.00],
- [27.0, 3.00],
- [30.0, 3.50],
- [33.0, 3.50],
- [36.0, 4.00],
- [39.0, 4.00],
- [42.0, 4.50],
- [45.0, 4.50],
- [48.0, 5.00],
- [56.0, 5.50],
- [64.0, 6.00]
- ]);
+ [ 1.6, 0.35],
+ [ 2.0, 0.40],
+ [ 2.5, 0.45],
+ [ 3.0, 0.50],
+ [ 4.0, 0.70],
+ [ 5.0, 0.80],
+ [ 6.0, 1.00],
+ [ 7.0, 1.00],
+ [ 8.0, 1.00],
+ [10.0, 1.00],
+ [12.0, 1.25],
+ [14.0, 1.50],
+ [16.0, 2.00],
+ [18.0, 2.50],
+ [20.0, 2.50],
+ [22.0, 2.50],
+ [24.0, 3.00],
+ [27.0, 3.00],
+ [30.0, 3.50],
+ [33.0, 3.50],
+ [36.0, 4.00],
+ [39.0, 4.00],
+ [42.0, 4.50],
+ [45.0, 4.50],
+ [48.0, 5.00],
+ [56.0, 5.50],
+ [64.0, 6.00]
+ ]);
// Function: get_metric_jis_thread_pitch()
// Description: Returns the JIS metric standard threading pitch for a given bolt `size`.
function get_metric_jis_thread_pitch(size) = lookup(size, [
- [ 2.0, 0.40],
- [ 2.5, 0.45],
- [ 3.0, 0.50],
- [ 4.0, 0.70],
- [ 5.0, 0.80],
- [ 6.0, 1.00],
- [ 7.0, 1.00],
- [ 8.0, 1.25],
- [10.0, 1.25],
- [12.0, 1.25],
- [14.0, 1.50],
- [16.0, 1.50],
- [18.0, 1.50],
- [20.0, 1.50]
- ]);
+ [ 2.0, 0.40],
+ [ 2.5, 0.45],
+ [ 3.0, 0.50],
+ [ 4.0, 0.70],
+ [ 5.0, 0.80],
+ [ 6.0, 1.00],
+ [ 7.0, 1.00],
+ [ 8.0, 1.25],
+ [10.0, 1.25],
+ [12.0, 1.25],
+ [14.0, 1.50],
+ [16.0, 1.50],
+ [18.0, 1.50],
+ [20.0, 1.50]
+ ]);
// Function: get_metric_nut_size()
// Description: Returns the typical metric nut flat-to-flat diameter for a given bolt `size`.
function get_metric_nut_size(size) = lookup(size, [
- [ 2.0, 4.0],
- [ 2.5, 5.0],
- [ 3.0, 5.5],
- [ 4.0, 7.0],
- [ 5.0, 8.0],
- [ 6.0, 10.0],
- [ 7.0, 11.0],
- [ 8.0, 13.0],
- [10.0, 17.0],
- [12.0, 19.0],
- [14.0, 22.0],
- [16.0, 24.0],
- [18.0, 27.0],
- [20.0, 30.0]
- ]);
+ [ 2.0, 4.0],
+ [ 2.5, 5.0],
+ [ 3.0, 5.5],
+ [ 4.0, 7.0],
+ [ 5.0, 8.0],
+ [ 6.0, 10.0],
+ [ 7.0, 11.0],
+ [ 8.0, 13.0],
+ [10.0, 17.0],
+ [12.0, 19.0],
+ [14.0, 22.0],
+ [16.0, 24.0],
+ [18.0, 27.0],
+ [20.0, 30.0]
+ ]);
// Function: get_metric_nut_thickness()
// Description: Returns the typical metric nut thickness for a given bolt `size`.
function get_metric_nut_thickness(size) = lookup(size, [
- [ 1.6, 1.3],
- [ 2.0, 1.6],
- [ 2.5, 2.0],
- [ 3.0, 2.4],
- [ 4.0, 3.2],
- [ 5.0, 4.0],
- [ 6.0, 5.0],
- [ 7.0, 5.5],
- [ 8.0, 6.5],
- [10.0, 8.0],
- [12.0, 10.0],
- [14.0, 11.0],
- [16.0, 13.0],
- [18.0, 15.0],
- [20.0, 16.0],
- [24.0, 21.5],
- [30.0, 25.6],
- [36.0, 31.0],
- [42.0, 34.0],
- [48.0, 38.0],
- [56.0, 45.0],
- [64.0, 51.0]
- ]);
+ [ 1.6, 1.3],
+ [ 2.0, 1.6],
+ [ 2.5, 2.0],
+ [ 3.0, 2.4],
+ [ 4.0, 3.2],
+ [ 5.0, 4.0],
+ [ 6.0, 5.0],
+ [ 7.0, 5.5],
+ [ 8.0, 6.5],
+ [10.0, 8.0],
+ [12.0, 10.0],
+ [14.0, 11.0],
+ [16.0, 13.0],
+ [18.0, 15.0],
+ [20.0, 16.0],
+ [24.0, 21.5],
+ [30.0, 25.6],
+ [36.0, 31.0],
+ [42.0, 34.0],
+ [48.0, 38.0],
+ [56.0, 45.0],
+ [64.0, 51.0]
+ ]);
@@ -386,33 +386,33 @@ function get_metric_nut_thickness(size) = lookup(size, [
// screw(screwsize=3,screwlen=10,headsize=6,headlen=3)
// show_anchors(5, std=false);
module screw(
- screwsize=3,
- screwlen=10,
- headsize=6,
- headlen=3,
- pitch=undef,
- anchor="base",
- spin=0,
- orient=UP
+ screwsize=3,
+ screwlen=10,
+ headsize=6,
+ headlen=3,
+ pitch=undef,
+ anchor="base",
+ spin=0,
+ orient=UP
) {
- sides = max(12, segs(screwsize/2));
- anchors = [
- anchorpt("countersunk", [0,0,(headlen+screwlen)/2-0.01]),
- anchorpt("base", [0,0,-headlen/2+screwlen/2])
- ];
- attachable(anchor,spin,orient, d=screwsize, l=headlen+screwlen, anchors=anchors) {
- down(headlen/2-screwlen/2) {
- down(screwlen/2) {
- if (pitch == undef) {
- cylinder(r=screwsize/2, h=screwlen+0.05, center=true, $fn=sides);
- } else {
- threaded_rod(d=screwsize, l=screwlen+0.05, pitch=pitch, $fn=sides);
- }
- }
- cylinder(r=headsize/2, h=headlen, center=false, $fn=sides*2);
- }
- children();
- }
+ sides = max(12, segs(screwsize/2));
+ anchors = [
+ anchorpt("countersunk", [0,0,(headlen+screwlen)/2-0.01]),
+ anchorpt("base", [0,0,-headlen/2+screwlen/2])
+ ];
+ attachable(anchor,spin,orient, d=screwsize, l=headlen+screwlen, anchors=anchors) {
+ down(headlen/2-screwlen/2) {
+ down(screwlen/2) {
+ if (pitch == undef) {
+ cylinder(r=screwsize/2, h=screwlen+0.05, center=true, $fn=sides);
+ } else {
+ threaded_rod(d=screwsize, l=screwlen+0.05, pitch=pitch, $fn=sides);
+ }
+ }
+ cylinder(r=headsize/2, h=headlen, center=false, $fn=sides*2);
+ }
+ children();
+ }
}
@@ -477,150 +477,150 @@ module screw(
// metric_bolt(headtype="oval", size=10, l=15, shank=5, details=true, phillips="#2")
// show_anchors(5, std=false);
module metric_bolt(
- headtype="socket",
- size=3,
- l=12,
- shank=0,
- pitch=undef,
- details=false,
- coarse=true,
- phillips=undef,
- torx=undef,
- flange=0,
- anchor="base",
- spin=0,
- orient=UP
+ headtype="socket",
+ size=3,
+ l=12,
+ shank=0,
+ pitch=undef,
+ details=false,
+ coarse=true,
+ phillips=undef,
+ torx=undef,
+ flange=0,
+ anchor="base",
+ spin=0,
+ orient=UP
) {
- D = headtype != "hex"?
- get_metric_socket_cap_diam(size) :
- get_metric_bolt_head_size(size);
- H = headtype == "socket"?
- get_metric_socket_cap_height(size) :
- get_metric_bolt_head_height(size);
- P = coarse?
- (pitch==undef? get_metric_iso_coarse_thread_pitch(size) : pitch) :
- (pitch==undef? get_metric_iso_fine_thread_pitch(size) : pitch);
- tlen = l - min(l, shank);
- sides = max(12, segs(size/2));
- tcirc = D/cos(30);
- bevtop = (tcirc-D)/2;
- bevbot = P/2;
+ D = headtype != "hex"?
+ get_metric_socket_cap_diam(size) :
+ get_metric_bolt_head_size(size);
+ H = headtype == "socket"?
+ get_metric_socket_cap_height(size) :
+ get_metric_bolt_head_height(size);
+ P = coarse?
+ (pitch==undef? get_metric_iso_coarse_thread_pitch(size) : pitch) :
+ (pitch==undef? get_metric_iso_fine_thread_pitch(size) : pitch);
+ tlen = l - min(l, shank);
+ sides = max(12, segs(size/2));
+ tcirc = D/cos(30);
+ bevtop = (tcirc-D)/2;
+ bevbot = P/2;
- headlen = (
- (headtype == "pan" || headtype == "round" || headtype == "button")? H*0.75 :
- (headtype == "countersunk")? (D-size)/2 :
- (headtype == "oval")? ((D-size)/2 + D/2/3) :
- H
- );
- base = l/2 - headlen/2;
- sunklen = (
- (headtype == "oval")? (D-size)/2 :
- headlen-0.001
- );
+ headlen = (
+ (headtype == "pan" || headtype == "round" || headtype == "button")? H*0.75 :
+ (headtype == "countersunk")? (D-size)/2 :
+ (headtype == "oval")? ((D-size)/2 + D/2/3) :
+ H
+ );
+ base = l/2 - headlen/2;
+ sunklen = (
+ (headtype == "oval")? (D-size)/2 :
+ headlen-0.001
+ );
- anchors = [
- anchorpt("countersunk", [0,0,base+sunklen]),
- anchorpt("base", [0,0,base]),
- anchorpt("shank", [0,0,base-shank])
- ];
+ anchors = [
+ anchorpt("countersunk", [0,0,base+sunklen]),
+ anchorpt("base", [0,0,base]),
+ anchorpt("shank", [0,0,base-shank])
+ ];
- //color("silver")
- attachable(anchor,spin,orient, d=size, l=headlen+l, anchors=anchors) {
- up(base) {
- difference() {
- union() {
- // Head
- if (headtype == "hex") {
- difference() {
- cylinder(d=tcirc, h=H, $fn=6);
+ //color("silver")
+ attachable(anchor,spin,orient, d=size, l=headlen+l, anchors=anchors) {
+ up(base) {
+ difference() {
+ union() {
+ // Head
+ if (headtype == "hex") {
+ difference() {
+ cylinder(d=tcirc, h=H, $fn=6);
- // Bevel hex nut top
- if (details) {
- up(H-bevtop) {
- difference() {
- cube([tcirc+1, tcirc+1, bevtop+0.5], anchor=BOTTOM);
- down(0.01) cylinder(d1=tcirc, d2=tcirc-bevtop*2, h=bevtop+0.02, center=false);
- }
- }
- }
- }
- } else if (headtype == "socket") {
- sockw = get_metric_socket_cap_socket_size(size);
- sockd = get_metric_socket_cap_socket_depth(size);
- difference() {
- cylinder(d=D, h=H);
- up(H-sockd) cylinder(h=sockd+0.1, d=sockw/cos(30), $fn=6);
- if (details) {
- kcnt = 36;
- zrot_copies(n=kcnt, r=D/2) up(H/3) cube([PI*D/kcnt/2, PI*D/kcnt/2, H], anchor=BOTTOM);
- }
- }
- } else if (headtype == "pan") {
- cyl(l=H*0.75, d=D, rounding2=H*0.75/2, anchor=DOWN);
- } else if (headtype == "round") {
- top_half(D) zscale(H*0.75/D*2) sphere(d=D);
- } else if (headtype == "button") {
- up(H*0.75/3) top_half(D) zscale(H*0.75*2/3/D*2) sphere(d=D);
- cylinder(d=D, h=H*0.75/3+0.01, center=false);
- } else if (headtype == "countersunk") {
- cylinder(h=(D-size)/2, d1=size, d2=D);
- } else if (headtype == "oval") {
- up((D-size)/2) top_half(D) zscale(0.333) sphere(d=D);
- cylinder(h=(D-size)/2, d1=size, d2=D);
- }
+ // Bevel hex nut top
+ if (details) {
+ up(H-bevtop) {
+ difference() {
+ cube([tcirc+1, tcirc+1, bevtop+0.5], anchor=BOTTOM);
+ down(0.01) cylinder(d1=tcirc, d2=tcirc-bevtop*2, h=bevtop+0.02, center=false);
+ }
+ }
+ }
+ }
+ } else if (headtype == "socket") {
+ sockw = get_metric_socket_cap_socket_size(size);
+ sockd = get_metric_socket_cap_socket_depth(size);
+ difference() {
+ cylinder(d=D, h=H);
+ up(H-sockd) cylinder(h=sockd+0.1, d=sockw/cos(30), $fn=6);
+ if (details) {
+ kcnt = 36;
+ zrot_copies(n=kcnt, r=D/2) up(H/3) cube([PI*D/kcnt/2, PI*D/kcnt/2, H], anchor=BOTTOM);
+ }
+ }
+ } else if (headtype == "pan") {
+ cyl(l=H*0.75, d=D, rounding2=H*0.75/2, anchor=DOWN);
+ } else if (headtype == "round") {
+ top_half(D) zscale(H*0.75/D*2) sphere(d=D);
+ } else if (headtype == "button") {
+ up(H*0.75/3) top_half(D) zscale(H*0.75*2/3/D*2) sphere(d=D);
+ cylinder(d=D, h=H*0.75/3+0.01, center=false);
+ } else if (headtype == "countersunk") {
+ cylinder(h=(D-size)/2, d1=size, d2=D);
+ } else if (headtype == "oval") {
+ up((D-size)/2) top_half(D) zscale(0.333) sphere(d=D);
+ cylinder(h=(D-size)/2, d1=size, d2=D);
+ }
- // Flange
- if (flange>0) {
- up(headtype == "countersunk" || headtype == "oval"? (D-size)/2 : 0) {
- cylinder(d=D+flange, h=H/8, center=false);
- up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
- }
- }
+ // Flange
+ if (flange>0) {
+ up(headtype == "countersunk" || headtype == "oval"? (D-size)/2 : 0) {
+ cylinder(d=D+flange, h=H/8, center=false);
+ up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
+ }
+ }
- // Unthreaded Shank
- if (tlen < l) {
- down(l-tlen) cylinder(d=size, h=l-tlen+0.05, center=false, $fn=sides);
- }
+ // Unthreaded Shank
+ if (tlen < l) {
+ down(l-tlen) cylinder(d=size, h=l-tlen+0.05, center=false, $fn=sides);
+ }
- // Threads
- down(l) {
- difference() {
- up(tlen/2+0.05) {
- if (tlen > 0) {
- if (P > 0) {
- threaded_rod(d=size, l=tlen+0.05, pitch=P, $fn=sides);
- } else {
- cylinder(d=size, h=tlen+0.05, $fn=sides, center=true);
- }
- }
- }
+ // Threads
+ down(l) {
+ difference() {
+ up(tlen/2+0.05) {
+ if (tlen > 0) {
+ if (P > 0) {
+ threaded_rod(d=size, l=tlen+0.05, pitch=P, $fn=sides);
+ } else {
+ cylinder(d=size, h=tlen+0.05, $fn=sides, center=true);
+ }
+ }
+ }
- // Bevel bottom end of threads
- if (details) {
- difference() {
- down(0.5) cube([size+1, size+1, bevbot+0.5], anchor=BOTTOM);
- cylinder(d1=size-bevbot*2, d2=size, h=bevbot+0.01, center=false);
- }
- }
- }
- }
- }
+ // Bevel bottom end of threads
+ if (details) {
+ difference() {
+ down(0.5) cube([size+1, size+1, bevbot+0.5], anchor=BOTTOM);
+ cylinder(d1=size-bevbot*2, d2=size, h=bevbot+0.01, center=false);
+ }
+ }
+ }
+ }
+ }
- // Phillips drive hole
- if (headtype != "socket" && phillips != undef) {
- down(headtype != "hex"? H/6 : 0) {
- phillips_drive(size=phillips, shaft=D);
- }
- }
+ // Phillips drive hole
+ if (headtype != "socket" && phillips != undef) {
+ down(headtype != "hex"? H/6 : 0) {
+ phillips_drive(size=phillips, shaft=D);
+ }
+ }
- // Torx drive hole
- if (headtype != "socket" && torx != undef) {
- up(1) torx_drive(size=torx, l=H+0.1, center=false);
- }
- }
- }
- children();
- }
+ // Torx drive hole
+ if (headtype != "socket" && torx != undef) {
+ up(1) torx_drive(size=torx, l=H+0.1, center=false);
+ }
+ }
+ }
+ children();
+ }
}
@@ -650,65 +650,65 @@ module metric_bolt(
// Example: Flange
// metric_nut(size=10, hole=true, pitch=1.5, flange=3, details=true);
module metric_nut(
- size=3,
- hole=true,
- pitch=undef,
- details=false,
- flange=0,
- center,
- anchor,
- spin=0,
- orient=UP
+ size=3,
+ hole=true,
+ pitch=undef,
+ details=false,
+ flange=0,
+ center,
+ anchor,
+ spin=0,
+ orient=UP
) {
- H = get_metric_nut_thickness(size);
- D = get_metric_nut_size(size);
- boltfn = max(12, segs(size/2));
- nutfn = max(12, segs(D/2));
- dcirc = D/cos(30);
- bevtop = (dcirc - D)/2;
+ H = get_metric_nut_thickness(size);
+ D = get_metric_nut_size(size);
+ boltfn = max(12, segs(size/2));
+ nutfn = max(12, segs(D/2));
+ dcirc = D/cos(30);
+ bevtop = (dcirc - D)/2;
- //color("silver")
- anchor = get_anchor(anchor,center,BOT,CENTER);
- attachable(anchor,spin,orient, d=dcirc+flange, l=H) {
- difference() {
- union() {
- difference() {
- cylinder(d=dcirc, h=H, center=true, $fn=6);
- if (details) {
- up(H/2-bevtop) {
- difference() {
- cube([dcirc+1, dcirc+1, bevtop+0.5], anchor=BOTTOM);
- down(0.01) cylinder(d1=dcirc, d2=dcirc-bevtop*2, h=bevtop+0.02, center=false, $fn=nutfn);
- }
- }
- if (flange == 0) {
- down(H/2) {
- difference() {
- down(0.5) cube([dcirc+1, dcirc+1, bevtop+0.5], anchor=BOTTOM);
- down(0.01) cylinder(d1=dcirc-bevtop*2, d2=dcirc, h=bevtop+0.02, center=false, $fn=nutfn);
- }
- }
- }
- }
- }
- if (flange>0) {
- down(H/2) {
- cylinder(d=D+flange, h=H/8, center=false);
- up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
- }
- }
- }
- if (hole == true) {
- if (pitch == undef) {
- cylinder(r=size/2, h=H+0.5, center=true, $fn=boltfn);
- } else {
- threaded_rod(d=size, l=H+0.5, pitch=pitch, $fn=boltfn);
- }
- }
- }
- children();
- }
+ //color("silver")
+ anchor = get_anchor(anchor,center,BOT,CENTER);
+ attachable(anchor,spin,orient, d=dcirc+flange, l=H) {
+ difference() {
+ union() {
+ difference() {
+ cylinder(d=dcirc, h=H, center=true, $fn=6);
+ if (details) {
+ up(H/2-bevtop) {
+ difference() {
+ cube([dcirc+1, dcirc+1, bevtop+0.5], anchor=BOTTOM);
+ down(0.01) cylinder(d1=dcirc, d2=dcirc-bevtop*2, h=bevtop+0.02, center=false, $fn=nutfn);
+ }
+ }
+ if (flange == 0) {
+ down(H/2) {
+ difference() {
+ down(0.5) cube([dcirc+1, dcirc+1, bevtop+0.5], anchor=BOTTOM);
+ down(0.01) cylinder(d1=dcirc-bevtop*2, d2=dcirc, h=bevtop+0.02, center=false, $fn=nutfn);
+ }
+ }
+ }
+ }
+ }
+ if (flange>0) {
+ down(H/2) {
+ cylinder(d=D+flange, h=H/8, center=false);
+ up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
+ }
+ }
+ }
+ if (hole == true) {
+ if (pitch == undef) {
+ cylinder(r=size/2, h=H+0.5, center=true, $fn=boltfn);
+ } else {
+ threaded_rod(d=size, l=H+0.5, pitch=pitch, $fn=boltfn);
+ }
+ }
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/mutators.scad b/mutators.scad
index a8619cc..b801e48 100644
--- a/mutators.scad
+++ b/mutators.scad
@@ -33,30 +33,30 @@
// half_of([1,1], planar=true) circle(d=50);
module half_of(v=UP, cp, s=1000, planar=false)
{
- cp = is_vector(v,4)? assert(cp==undef, "Don't use cp with plane definition.") plane_normal(v) * v[3] :
- is_vector(cp)? cp :
- is_num(cp)? cp*unit(v) :
- [0,0,0];
- v = is_vector(v,4)? plane_normal(v) : v;
- if (cp != [0,0,0]) {
- translate(cp) half_of(v=v, s=s, planar=planar) translate(-cp) children();
- } else if (planar) {
- v = (v==UP)? BACK : (v==DOWN)? FWD : v;
- ang = atan2(v.y, v.x);
- difference() {
- children();
- rotate(ang+90) {
- back(s/2) square(s, center=true);
- }
- }
- } else {
- difference() {
- children();
- rot(from=UP, to=-v) {
- up(s/2) cube(s, center=true);
- }
- }
- }
+ cp = is_vector(v,4)? assert(cp==undef, "Don't use cp with plane definition.") plane_normal(v) * v[3] :
+ is_vector(cp)? cp :
+ is_num(cp)? cp*unit(v) :
+ [0,0,0];
+ v = is_vector(v,4)? plane_normal(v) : v;
+ if (cp != [0,0,0]) {
+ translate(cp) half_of(v=v, s=s, planar=planar) translate(-cp) children();
+ } else if (planar) {
+ v = (v==UP)? BACK : (v==DOWN)? FWD : v;
+ ang = atan2(v.y, v.x);
+ difference() {
+ children();
+ rotate(ang+90) {
+ back(s/2) square(s, center=true);
+ }
+ }
+ } else {
+ difference() {
+ children();
+ rot(from=UP, to=-v) {
+ up(s/2) cube(s, center=true);
+ }
+ }
+ }
}
@@ -81,17 +81,17 @@ module half_of(v=UP, cp, s=1000, planar=false)
// left_half(planar=true) circle(r=20);
module left_half(s=1000, x=0, planar=false)
{
- dir = LEFT;
- difference() {
- children();
- translate([x,0,0]-dir*s/2) {
- if (planar) {
- square(s, center=true);
- } else {
- cube(s, center=true);
- }
- }
- }
+ dir = LEFT;
+ difference() {
+ children();
+ translate([x,0,0]-dir*s/2) {
+ if (planar) {
+ square(s, center=true);
+ } else {
+ cube(s, center=true);
+ }
+ }
+ }
}
@@ -117,17 +117,17 @@ module left_half(s=1000, x=0, planar=false)
// right_half(planar=true) circle(r=20);
module right_half(s=1000, x=0, planar=false)
{
- dir = RIGHT;
- difference() {
- children();
- translate([x,0,0]-dir*s/2) {
- if (planar) {
- square(s, center=true);
- } else {
- cube(s, center=true);
- }
- }
- }
+ dir = RIGHT;
+ difference() {
+ children();
+ translate([x,0,0]-dir*s/2) {
+ if (planar) {
+ square(s, center=true);
+ } else {
+ cube(s, center=true);
+ }
+ }
+ }
}
@@ -153,17 +153,17 @@ module right_half(s=1000, x=0, planar=false)
// front_half(planar=true) circle(r=20);
module front_half(s=1000, y=0, planar=false)
{
- dir = FWD;
- difference() {
- children();
- translate([0,y,0]-dir*s/2) {
- if (planar) {
- square(s, center=true);
- } else {
- cube(s, center=true);
- }
- }
- }
+ dir = FWD;
+ difference() {
+ children();
+ translate([0,y,0]-dir*s/2) {
+ if (planar) {
+ square(s, center=true);
+ } else {
+ cube(s, center=true);
+ }
+ }
+ }
}
@@ -189,17 +189,17 @@ module front_half(s=1000, y=0, planar=false)
// back_half(planar=true) circle(r=20);
module back_half(s=1000, y=0, planar=false)
{
- dir = BACK;
- difference() {
- children();
- translate([0,y,0]-dir*s/2) {
- if (planar) {
- square(s, center=true);
- } else {
- cube(s, center=true);
- }
- }
- }
+ dir = BACK;
+ difference() {
+ children();
+ translate([0,y,0]-dir*s/2) {
+ if (planar) {
+ square(s, center=true);
+ } else {
+ cube(s, center=true);
+ }
+ }
+ }
}
@@ -221,13 +221,13 @@ module back_half(s=1000, y=0, planar=false)
// bottom_half(z=-10) sphere(r=20);
module bottom_half(s=1000, z=0)
{
- dir = DOWN;
- difference() {
- children();
- translate([0,0,z]-dir*s/2) {
- cube(s, center=true);
- }
- }
+ dir = DOWN;
+ difference() {
+ children();
+ translate([0,0,z]-dir*s/2) {
+ cube(s, center=true);
+ }
+ }
}
@@ -249,13 +249,13 @@ module bottom_half(s=1000, z=0)
// top_half(z=5) sphere(r=20);
module top_half(s=1000, z=0)
{
- dir = UP;
- difference() {
- children();
- translate([0,0,z]-dir*s/2) {
- cube(s, center=true);
- }
- }
+ dir = UP;
+ difference() {
+ children();
+ translate([0,0,z]-dir*s/2) {
+ cube(s, center=true);
+ }
+ }
}
@@ -296,19 +296,19 @@ module top_half(s=1000, z=0)
// }
module chain_hull()
{
- union() {
- if ($children == 1) {
- children();
- } else if ($children > 1) {
- for (i =[1:1:$children-1]) {
- $idx = i;
- hull() {
- let($primary=true) children(i-1);
- let($primary=false) children(i);
- }
- }
- }
- }
+ union() {
+ if ($children == 1) {
+ children();
+ } else if ($children > 1) {
+ for (i =[1:1:$children-1]) {
+ $idx = i;
+ hull() {
+ let($primary=true) children(i-1);
+ let($primary=false) children(i);
+ }
+ }
+ }
+ }
}
@@ -341,35 +341,35 @@ module chain_hull()
// cylindrical_extrude(or=40, ir=35, orient=BACK)
// text(text="Hello World!", size=10, halign="center", valign="center");
module cylindrical_extrude(or, ir, od, id, size=1000, convexity=10, spin=0, orient=UP) {
- assert(is_num(size) || is_vector(size,2));
- size = is_num(size)? [size,size] : size;
- ir = get_radius(r=ir,d=id);
- or = get_radius(r=or,d=od);
- index_r = or;
- circumf = 2 * PI * index_r;
- width = min(size.x, circumf);
- assert(width <= circumf, "Shape would more than completely wrap around.");
- sides = segs(or);
- step = circumf / sides;
- steps = ceil(width / step);
- rot(from=UP, to=orient) rot(spin) {
- for (i=[0:1:steps-2]) {
- x = (i+0.5-steps/2) * step;
- zrot(360 * x / circumf) {
- fwd(or*cos(180/sides)) {
- xrot(-90) {
- linear_extrude(height=or-ir, scale=[ir/or,1], center=false, convexity=convexity) {
- yflip()
- intersection() {
- left(x) children();
- rect([quantup(step,pow(2,-15)),size.y],center=true);
- }
- }
- }
- }
- }
- }
- }
+ assert(is_num(size) || is_vector(size,2));
+ size = is_num(size)? [size,size] : size;
+ ir = get_radius(r=ir,d=id);
+ or = get_radius(r=or,d=od);
+ index_r = or;
+ circumf = 2 * PI * index_r;
+ width = min(size.x, circumf);
+ assert(width <= circumf, "Shape would more than completely wrap around.");
+ sides = segs(or);
+ step = circumf / sides;
+ steps = ceil(width / step);
+ rot(from=UP, to=orient) rot(spin) {
+ for (i=[0:1:steps-2]) {
+ x = (i+0.5-steps/2) * step;
+ zrot(360 * x / circumf) {
+ fwd(or*cos(180/sides)) {
+ xrot(-90) {
+ linear_extrude(height=or-ir, scale=[ir/or,1], center=false, convexity=convexity) {
+ yflip()
+ intersection() {
+ left(x) children();
+ rect([quantup(step,pow(2,-15)),size.y],center=true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
@@ -397,12 +397,12 @@ module cylindrical_extrude(or, ir, od, id, size=1000, convexity=10, spin=0, orie
// ir = Radius to round only inside (concave) corners to. Use instead of `r`.
module round3d(r, or, ir, size=100)
{
- or = get_radius(r1=or, r=r, dflt=0);
- ir = get_radius(r1=ir, r=r, dflt=0);
- offset3d(or, size=size)
- offset3d(-ir-or, size=size)
- offset3d(ir, size=size)
- children();
+ or = get_radius(r1=or, r=r, dflt=0);
+ ir = get_radius(r1=ir, r=r, dflt=0);
+ offset3d(or, size=size)
+ offset3d(-ir-or, size=size)
+ offset3d(ir, size=size)
+ children();
}
@@ -418,30 +418,30 @@ module round3d(r, or, ir, size=100)
// size = Maximum size of object to be contracted, given as a scalar. Default: 100
// convexity = Max number of times a line could intersect the walls of the object. Default: 10
module offset3d(r=1, size=100, convexity=10) {
- n = quant(max(8,segs(abs(r))),4);
- if (r==0) {
- children();
- } else if (r>0) {
- render(convexity=convexity)
- minkowski() {
- children();
- sphere(r, $fn=n);
- }
- } else {
- size2 = size * [1,1,1];
- size1 = size2 * 1.02;
- render(convexity=convexity)
- difference() {
- cube(size2, center=true);
- minkowski() {
- difference() {
- cube(size1, center=true);
- children();
- }
- sphere(-r, $fn=n);
- }
- }
- }
+ n = quant(max(8,segs(abs(r))),4);
+ if (r==0) {
+ children();
+ } else if (r>0) {
+ render(convexity=convexity)
+ minkowski() {
+ children();
+ sphere(r, $fn=n);
+ }
+ } else {
+ size2 = size * [1,1,1];
+ size1 = size2 * 1.02;
+ render(convexity=convexity)
+ difference() {
+ cube(size2, center=true);
+ minkowski() {
+ difference() {
+ cube(size1, center=true);
+ children();
+ }
+ sphere(-r, $fn=n);
+ }
+ }
+ }
}
@@ -468,9 +468,9 @@ module offset3d(r=1, size=100, convexity=10) {
// round2d(or=16,ir=8) {square([40,100], center=true); square([100,40], center=true);}
module round2d(r, or, ir)
{
- or = get_radius(r1=or, r=r, dflt=0);
- ir = get_radius(r1=ir, r=r, dflt=0);
- offset(or) offset(-ir-or) offset(delta=ir,chamfer=true) children();
+ or = get_radius(r1=or, r=r, dflt=0);
+ ir = get_radius(r1=ir, r=r, dflt=0);
+ offset(or) offset(-ir-or) offset(delta=ir,chamfer=true) children();
}
@@ -496,19 +496,19 @@ module round2d(r, or, ir)
// shell2d(8,or=16,ir=8,round=16,fill=8) {square([40,100], center=true); square([100,40], center=true);}
module shell2d(thickness, or=0, ir=0, fill=0, round=0)
{
- thickness = is_num(thickness)? (
- thickness<0? [thickness,0] : [0,thickness]
- ) : (thickness[0]>thickness[1])? (
- [thickness[1],thickness[0]]
- ) : thickness;
- difference() {
- round2d(or=or,ir=ir)
- offset(delta=thickness[1])
- children();
- round2d(or=fill,ir=round)
- offset(delta=thickness[0])
- children();
- }
+ thickness = is_num(thickness)? (
+ thickness<0? [thickness,0] : [0,thickness]
+ ) : (thickness[0]>thickness[1])? (
+ [thickness[1],thickness[0]]
+ ) : thickness;
+ difference() {
+ round2d(or=or,ir=ir)
+ offset(delta=thickness[1])
+ children();
+ round2d(or=fill,ir=round)
+ offset(delta=thickness[0])
+ children();
+ }
}
@@ -534,13 +534,13 @@ module shell2d(thickness, or=0, ir=0, fill=0, round=0)
// rgb = HSL(h=270,s=0.75,l=0.6);
// color(rgb) cube(60, center=true);
function HSL(h,s=1,l=0.5) =
- let(
- h=posmod(h,360)
- ) [
- for (n=[0,8,4]) let(
- k=(n+h/30)%12
- ) l - s*min(l,1-l)*max(min(k-3,9-k,1),-1)
- ];
+ let(
+ h=posmod(h,360)
+ ) [
+ for (n=[0,8,4]) let(
+ k=(n+h/30)%12
+ ) l - s*min(l,1-l)*max(min(k-3,9-k,1),-1)
+ ];
module HSL(h,s=1,l=0.5,a=1) color(HSL(h,s,l),a) children();
@@ -563,13 +563,13 @@ module HSL(h,s=1,l=0.5,a=1) color(HSL(h,s,l),a) children();
// rgb = HSV(h=270,s=0.75,v=0.9);
// color(rgb) cube(60, center=true);
function HSV(h,s=1,v=1) =
- let(
- h=posmod(h,360),
- v2=v*(1-s),
- r=lookup(h,[[0,v], [60,v], [120,v2], [240,v2], [300,v], [360,v]]),
- g=lookup(h,[[0,v2], [60,v], [180,v], [240,v2], [360,v2]]),
- b=lookup(h,[[0,v2], [120,v2], [180,v], [300,v], [360,v2]])
- ) [r,g,b];
+ let(
+ h=posmod(h,360),
+ v2=v*(1-s),
+ r=lookup(h,[[0,v], [60,v], [120,v2], [240,v2], [300,v], [360,v]]),
+ g=lookup(h,[[0,v2], [60,v], [180,v], [240,v2], [360,v2]]),
+ b=lookup(h,[[0,v2], [120,v2], [180,v], [300,v], [360,v2]])
+ ) [r,g,b];
module HSV(h,s=1,v=1,a=1) color(HSV(h,s,v),a) children();
@@ -594,14 +594,14 @@ module HSV(h,s=1,v=1,a=1) color(HSV(h,s,v),a) children();
// rainbow(rgn) stroke($item, closed=true);
module rainbow(list, stride=1)
{
- ll = len(list);
- huestep = 360 / ll;
- hues = [for (i=[0:1:ll-1]) posmod(i*huestep+i*360/stride,360)];
- for($idx=idx(list)) {
- $item = list[$idx];
- HSV(h=hues[$idx]) children();
- }
+ ll = len(list);
+ huestep = 360 / ll;
+ hues = [for (i=[0:1:ll-1]) posmod(i*huestep+i*360/stride,360)];
+ for($idx=idx(list)) {
+ $item = list[$idx];
+ HSV(h=hues[$idx]) children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/nema_steppers.scad b/nema_steppers.scad
index a8b54bb..2244806 100644
--- a/nema_steppers.scad
+++ b/nema_steppers.scad
@@ -17,12 +17,12 @@
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_width(size) = lookup(size, [
- [11.0, 28.2],
- [14.0, 35.2],
- [17.0, 42.3],
- [23.0, 57.0],
- [34.0, 86.0],
- ]);
+ [11.0, 28.2],
+ [14.0, 35.2],
+ [17.0, 42.3],
+ [23.0, 57.0],
+ [34.0, 86.0],
+ ]);
// Function: nema_motor_plinth_height()
@@ -30,12 +30,12 @@ function nema_motor_width(size) = lookup(size, [
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_plinth_height(size) = lookup(size, [
- [11.0, 1.5],
- [14.0, 2.0],
- [17.0, 2.0],
- [23.0, 1.6],
- [34.0, 2.03],
- ]);
+ [11.0, 1.5],
+ [14.0, 2.0],
+ [17.0, 2.0],
+ [23.0, 1.6],
+ [34.0, 2.03],
+ ]);
// Function: nema_motor_plinth_diam()
@@ -43,12 +43,12 @@ function nema_motor_plinth_height(size) = lookup(size, [
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_plinth_diam(size) = lookup(size, [
- [11.0, 22.0],
- [14.0, 22.0],
- [17.0, 22.0],
- [23.0, 38.1],
- [34.0, 73.0],
- ]);
+ [11.0, 22.0],
+ [14.0, 22.0],
+ [17.0, 22.0],
+ [23.0, 38.1],
+ [34.0, 73.0],
+ ]);
// Function: nema_motor_screw_spacing()
@@ -56,12 +56,12 @@ function nema_motor_plinth_diam(size) = lookup(size, [
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_screw_spacing(size) = lookup(size, [
- [11.0, 23.11],
- [14.0, 26.0],
- [17.0, 30.99],
- [23.0, 47.14],
- [34.0, 69.6],
- ]);
+ [11.0, 23.11],
+ [14.0, 26.0],
+ [17.0, 30.99],
+ [23.0, 47.14],
+ [34.0, 69.6],
+ ]);
// Function: nema_motor_screw_size()
@@ -69,12 +69,12 @@ function nema_motor_screw_spacing(size) = lookup(size, [
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_screw_size(size) = lookup(size, [
- [11.0, 2.6],
- [14.0, 3.0],
- [17.0, 3.0],
- [23.0, 5.1],
- [34.0, 5.5],
- ]);
+ [11.0, 2.6],
+ [14.0, 3.0],
+ [17.0, 3.0],
+ [23.0, 5.1],
+ [34.0, 5.5],
+ ]);
// Function: nema_motor_screw_depth()
@@ -82,12 +82,12 @@ function nema_motor_screw_size(size) = lookup(size, [
// Arguments:
// size = The standard NEMA motor size.
function nema_motor_screw_depth(size) = lookup(size, [
- [11.0, 3.0],
- [14.0, 4.5],
- [17.0, 4.5],
- [23.0, 4.8],
- [34.0, 9.0],
- ]);
+ [11.0, 3.0],
+ [14.0, 4.5],
+ [17.0, 4.5],
+ [23.0, 4.8],
+ [34.0, 9.0],
+ ]);
// Section: Motor Models
@@ -115,45 +115,45 @@ function nema_motor_screw_depth(size) = lookup(size, [
// nema11_stepper();
module nema11_stepper(h=24, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP)
{
- size = 11;
- motor_width = nema_motor_width(size);
- plinth_height = nema_motor_plinth_height(size);
- plinth_diam = nema_motor_plinth_diam(size);
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size);
- screw_depth = nema_motor_screw_depth(size);
+ size = 11;
+ motor_width = nema_motor_width(size);
+ plinth_height = nema_motor_plinth_height(size);
+ plinth_diam = nema_motor_plinth_diam(size);
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size);
+ screw_depth = nema_motor_screw_depth(size);
- anchors = [
- anchorpt("shaft-top", [0,0,h/2+shaft_len]),
- anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
- anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
- anchorpt("plinth-top", [0,0,h/2+plinth_height]),
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
- ];
- attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
- up(h/2)
- union() {
- difference() {
- color([0.4, 0.4, 0.4])
- cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
- color("silver")
- xcopies(screw_spacing)
- ycopies(screw_spacing)
- cyl(r=screw_size/2, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
- }
- color([0.6, 0.6, 0.6]) {
- difference() {
- cylinder(h=plinth_height, d=plinth_diam);
- cyl(h=plinth_height*3, d=shaft+0.75);
- }
- }
- color("silver") cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
- }
- children();
- }
+ anchors = [
+ anchorpt("shaft-top", [0,0,h/2+shaft_len]),
+ anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
+ anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
+ anchorpt("plinth-top", [0,0,h/2+plinth_height]),
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
+ ];
+ attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
+ up(h/2)
+ union() {
+ difference() {
+ color([0.4, 0.4, 0.4])
+ cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
+ color("silver")
+ xcopies(screw_spacing)
+ ycopies(screw_spacing)
+ cyl(r=screw_size/2, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
+ }
+ color([0.6, 0.6, 0.6]) {
+ difference() {
+ cylinder(h=plinth_height, d=plinth_diam);
+ cyl(h=plinth_height*3, d=shaft+0.75);
+ }
+ }
+ color("silver") cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
+ }
+ children();
+ }
}
@@ -180,45 +180,45 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
// nema14_stepper();
module nema14_stepper(h=24, shaft=5, shaft_len=24, anchor=TOP, spin=0, orient=UP)
{
- size = 14;
- motor_width = nema_motor_width(size);
- plinth_height = nema_motor_plinth_height(size);
- plinth_diam = nema_motor_plinth_diam(size);
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size);
- screw_depth = nema_motor_screw_depth(size);
+ size = 14;
+ motor_width = nema_motor_width(size);
+ plinth_height = nema_motor_plinth_height(size);
+ plinth_diam = nema_motor_plinth_diam(size);
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size);
+ screw_depth = nema_motor_screw_depth(size);
- anchors = [
- anchorpt("shaft-top", [0,0,h/2+shaft_len]),
- anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
- anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
- anchorpt("plinth-top", [0,0,h/2+plinth_height]),
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
- ];
- attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
- up(h/2)
- union() {
- difference() {
- color([0.4, 0.4, 0.4])
- cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
- color("silver")
- xcopies(screw_spacing)
- ycopies(screw_spacing)
- cyl(d=screw_size, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
- }
- color([0.6, 0.6, 0.6]) {
- difference() {
- cylinder(h=plinth_height, d=plinth_diam);
- cyl(h=plinth_height*3, d=shaft+0.75);
- }
- }
- color("silver") cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
- }
- children();
- }
+ anchors = [
+ anchorpt("shaft-top", [0,0,h/2+shaft_len]),
+ anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
+ anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
+ anchorpt("plinth-top", [0,0,h/2+plinth_height]),
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
+ ];
+ attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
+ up(h/2)
+ union() {
+ difference() {
+ color([0.4, 0.4, 0.4])
+ cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
+ color("silver")
+ xcopies(screw_spacing)
+ ycopies(screw_spacing)
+ cyl(d=screw_size, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
+ }
+ color([0.6, 0.6, 0.6]) {
+ difference() {
+ cylinder(h=plinth_height, d=plinth_diam);
+ cyl(h=plinth_height*3, d=shaft+0.75);
+ }
+ }
+ color("silver") cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
+ }
+ children();
+ }
}
@@ -245,64 +245,64 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, anchor=TOP, spin=0, orient=UP
// nema17_stepper();
module nema17_stepper(h=34, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP)
{
- size = 17;
- motor_width = nema_motor_width(size);
- plinth_height = nema_motor_plinth_height(size);
- plinth_diam = nema_motor_plinth_diam(size);
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size);
- screw_depth = nema_motor_screw_depth(size);
+ size = 17;
+ motor_width = nema_motor_width(size);
+ plinth_height = nema_motor_plinth_height(size);
+ plinth_diam = nema_motor_plinth_diam(size);
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size);
+ screw_depth = nema_motor_screw_depth(size);
- anchors = [
- anchorpt("shaft-top", [0,0,h/2+shaft_len]),
- anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
- anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
- anchorpt("plinth-top", [0,0,h/2+plinth_height]),
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
- ];
- attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
- up(h/2)
- union() {
- difference() {
- color([0.4, 0.4, 0.4])
- cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
- color("silver")
- xcopies(screw_spacing)
- ycopies(screw_spacing)
- cyl(d=screw_size, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
- }
- color([0.6, 0.6, 0.6]) {
- difference() {
- cylinder(h=plinth_height, d=plinth_diam);
- cyl(h=plinth_height*3, d=shaft+0.75);
- }
- }
- color([0.9, 0.9, 0.9]) {
- down(h-motor_width/12) {
- fwd(motor_width/2+motor_width/24/2-0.1) {
- difference() {
- cube(size=[motor_width/8, motor_width/24, motor_width/8], center=true);
- cyl(d=motor_width/8-2, h=motor_width/6, orient=BACK, $fn=12);
- }
- }
- }
- }
- color("silver") {
- difference() {
- cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
- up(shaft_len/2+1) {
- right(shaft-0.75) {
- cube([shaft, shaft, shaft_len], center=true);
- }
- }
- }
- }
- }
- children();
- }
+ anchors = [
+ anchorpt("shaft-top", [0,0,h/2+shaft_len]),
+ anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
+ anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
+ anchorpt("plinth-top", [0,0,h/2+plinth_height]),
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
+ ];
+ attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
+ up(h/2)
+ union() {
+ difference() {
+ color([0.4, 0.4, 0.4])
+ cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
+ color("silver")
+ xcopies(screw_spacing)
+ ycopies(screw_spacing)
+ cyl(d=screw_size, h=screw_depth*2, $fn=max(12,segs(screw_size/2)));
+ }
+ color([0.6, 0.6, 0.6]) {
+ difference() {
+ cylinder(h=plinth_height, d=plinth_diam);
+ cyl(h=plinth_height*3, d=shaft+0.75);
+ }
+ }
+ color([0.9, 0.9, 0.9]) {
+ down(h-motor_width/12) {
+ fwd(motor_width/2+motor_width/24/2-0.1) {
+ difference() {
+ cube(size=[motor_width/8, motor_width/24, motor_width/8], center=true);
+ cyl(d=motor_width/8-2, h=motor_width/6, orient=BACK, $fn=12);
+ }
+ }
+ }
+ }
+ color("silver") {
+ difference() {
+ cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
+ up(shaft_len/2+1) {
+ right(shaft-0.75) {
+ cube([shaft, shaft, shaft_len], center=true);
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -329,47 +329,47 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
// nema23_stepper();
module nema23_stepper(h=50, shaft=6.35, shaft_len=25, anchor=TOP, spin=0, orient=UP)
{
- size = 23;
- motor_width = nema_motor_width(size);
- plinth_height = nema_motor_plinth_height(size);
- plinth_diam = nema_motor_plinth_diam(size);
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size);
- screw_depth = nema_motor_screw_depth(size);
+ size = 23;
+ motor_width = nema_motor_width(size);
+ plinth_height = nema_motor_plinth_height(size);
+ plinth_diam = nema_motor_plinth_diam(size);
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size);
+ screw_depth = nema_motor_screw_depth(size);
- screw_inset = motor_width - screw_spacing + 1;
- anchors = [
- anchorpt("shaft-top", [0,0,h/2+shaft_len]),
- anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
- anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
- anchorpt("plinth-top", [0,0,h/2+plinth_height]),
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
- ];
- attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
- up(h/2)
- difference() {
- union() {
- color([0.4, 0.4, 0.4])
- cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
- color([0.4, 0.4, 0.4])
- cylinder(h=plinth_height, d=plinth_diam);
- color("silver")
- cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
- }
- color([0.4, 0.4, 0.4]) {
- xcopies(screw_spacing) {
- ycopies(screw_spacing) {
- cyl(d=screw_size, h=screw_depth*3, $fn=max(12,segs(screw_size/2)));
- down(screw_depth) cuboid([screw_inset, screw_inset, h], anchor=TOP);
- }
- }
- }
- }
- children();
- }
+ screw_inset = motor_width - screw_spacing + 1;
+ anchors = [
+ anchorpt("shaft-top", [0,0,h/2+shaft_len]),
+ anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
+ anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
+ anchorpt("plinth-top", [0,0,h/2+plinth_height]),
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
+ ];
+ attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
+ up(h/2)
+ difference() {
+ union() {
+ color([0.4, 0.4, 0.4])
+ cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
+ color([0.4, 0.4, 0.4])
+ cylinder(h=plinth_height, d=plinth_diam);
+ color("silver")
+ cylinder(h=shaft_len, d=shaft, $fn=max(12,segs(shaft/2)));
+ }
+ color([0.4, 0.4, 0.4]) {
+ xcopies(screw_spacing) {
+ ycopies(screw_spacing) {
+ cyl(d=screw_size, h=screw_depth*3, $fn=max(12,segs(screw_size/2)));
+ down(screw_depth) cuboid([screw_inset, screw_inset, h], anchor=TOP);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -396,47 +396,47 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, anchor=TOP, spin=0, orient
// nema34_stepper();
module nema34_stepper(h=75, shaft=12.7, shaft_len=32, anchor=TOP, spin=0, orient=UP)
{
- size = 34;
- motor_width = nema_motor_width(size);
- plinth_height = nema_motor_plinth_height(size);
- plinth_diam = nema_motor_plinth_diam(size);
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size);
- screw_depth = nema_motor_screw_depth(size);
+ size = 34;
+ motor_width = nema_motor_width(size);
+ plinth_height = nema_motor_plinth_height(size);
+ plinth_diam = nema_motor_plinth_diam(size);
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size);
+ screw_depth = nema_motor_screw_depth(size);
- screw_inset = motor_width - screw_spacing + 1;
- anchors = [
- anchorpt("shaft-top", [0,0,h/2+shaft_len]),
- anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
- anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
- anchorpt("plinth-top", [0,0,h/2+plinth_height]),
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
- ];
- attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
- up(h/2)
- difference() {
- union() {
- color([0.4, 0.4, 0.4])
- cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
- color([0.4, 0.4, 0.4])
- cylinder(h=plinth_height, d=plinth_diam);
- color("silver")
- cylinder(h=shaft_len, d=shaft, $fn=max(24,segs(shaft/2)));
- }
- color([0.4, 0.4, 0.4]) {
- xcopies(screw_spacing) {
- ycopies(screw_spacing) {
- cylinder(d=screw_size, h=screw_depth*3, center=true, $fn=max(12,segs(screw_size/2)));
- down(screw_depth) cube([screw_inset, screw_inset, h], anchor=TOP);
- }
- }
- }
- }
- children();
- }
+ screw_inset = motor_width - screw_spacing + 1;
+ anchors = [
+ anchorpt("shaft-top", [0,0,h/2+shaft_len]),
+ anchorpt("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
+ anchorpt("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
+ anchorpt("plinth-top", [0,0,h/2+plinth_height]),
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
+ ];
+ attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
+ up(h/2)
+ difference() {
+ union() {
+ color([0.4, 0.4, 0.4])
+ cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
+ color([0.4, 0.4, 0.4])
+ cylinder(h=plinth_height, d=plinth_diam);
+ color("silver")
+ cylinder(h=shaft_len, d=shaft, $fn=max(24,segs(shaft/2)));
+ }
+ color([0.4, 0.4, 0.4]) {
+ xcopies(screw_spacing) {
+ ycopies(screw_spacing) {
+ cylinder(d=screw_size, h=screw_depth*3, center=true, $fn=max(12,segs(screw_size/2)));
+ down(screw_depth) cube([screw_inset, screw_inset, h], anchor=TOP);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -468,45 +468,45 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, anchor=TOP, spin=0, orient
// nema_mount_holes(size=17, depth=5, l=0);
module nema_mount_holes(size=17, depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- motor_width = nema_motor_width(size);
- plinth_diam = nema_motor_plinth_diam(size)+$slop;
- screw_spacing = nema_motor_screw_spacing(size);
- screw_size = nema_motor_screw_size(size)+$slop;
+ motor_width = nema_motor_width(size);
+ plinth_diam = nema_motor_plinth_diam(size)+$slop;
+ screw_spacing = nema_motor_screw_spacing(size);
+ screw_size = nema_motor_screw_size(size)+$slop;
- anchors = [
- anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, depth/2]),
- anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, depth/2]),
- anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, depth/2]),
- anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, depth/2]),
- ];
- screwfn = quantup(max(8,segs(screw_size/2)),4);
- plinthfn = quantup(max(8,segs(plinth_diam/2)),4);
- s = [screw_spacing+screw_size, screw_spacing+screw_size+l, depth];
- attachable(anchor,spin,orient, size=s, anchors=anchors) {
- union() {
- xcopies(screw_spacing) {
- ycopies(screw_spacing) {
- if (l>0) {
- union() {
- ycopies(l) cyl(h=depth, d=screw_size, $fn=screwfn);
- cube([screw_size, l, depth], center=true);
- }
- } else {
- cyl(h=depth, d=screw_size, $fn=screwfn);
- }
- }
- }
- if (l>0) {
- union () {
- ycopies(l) cyl(h=depth, d=plinth_diam, $fn=plinthfn);
- cube([plinth_diam, l, depth], center=true);
- }
- } else {
- cyl(h=depth, d=plinth_diam, $fn=plinthfn);
- }
- }
- children();
- }
+ anchors = [
+ anchorpt("screw1", [+screw_spacing/2, +screw_spacing/2, depth/2]),
+ anchorpt("screw2", [-screw_spacing/2, +screw_spacing/2, depth/2]),
+ anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, depth/2]),
+ anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, depth/2]),
+ ];
+ screwfn = quantup(max(8,segs(screw_size/2)),4);
+ plinthfn = quantup(max(8,segs(plinth_diam/2)),4);
+ s = [screw_spacing+screw_size, screw_spacing+screw_size+l, depth];
+ attachable(anchor,spin,orient, size=s, anchors=anchors) {
+ union() {
+ xcopies(screw_spacing) {
+ ycopies(screw_spacing) {
+ if (l>0) {
+ union() {
+ ycopies(l) cyl(h=depth, d=screw_size, $fn=screwfn);
+ cube([screw_size, l, depth], center=true);
+ }
+ } else {
+ cyl(h=depth, d=screw_size, $fn=screwfn);
+ }
+ }
+ }
+ if (l>0) {
+ union () {
+ ycopies(l) cyl(h=depth, d=plinth_diam, $fn=plinthfn);
+ cube([plinth_diam, l, depth], center=true);
+ }
+ } else {
+ cyl(h=depth, d=plinth_diam, $fn=plinthfn);
+ }
+ }
+ children();
+ }
}
@@ -531,7 +531,7 @@ module nema_mount_holes(size=17, depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
// nema11_mount_holes(depth=5, l=0);
module nema11_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- nema_mount_holes(size=11, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
+ nema_mount_holes(size=11, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
}
@@ -556,7 +556,7 @@ module nema11_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
// nema14_mount_holes(depth=5, l=0);
module nema14_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- nema_mount_holes(size=14, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
+ nema_mount_holes(size=14, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
}
@@ -581,7 +581,7 @@ module nema14_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
// nema17_mount_holes(depth=5, l=0);
module nema17_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- nema_mount_holes(size=17, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
+ nema_mount_holes(size=17, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
}
@@ -606,7 +606,7 @@ module nema17_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
// nema23_mount_holes(depth=5, l=0);
module nema23_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- nema_mount_holes(size=23, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
+ nema_mount_holes(size=23, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
}
@@ -631,9 +631,9 @@ module nema23_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
// nema34_mount_holes(depth=5, l=0);
module nema34_mount_holes(depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
{
- nema_mount_holes(size=34, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
+ nema_mount_holes(size=34, depth=depth, l=l, anchor=anchor, spin=spin, orient=orient) children();
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/partitions.scad b/partitions.scad
index ef3c4fd..534219b 100644
--- a/partitions.scad
+++ b/partitions.scad
@@ -13,39 +13,39 @@
_partition_cutpaths = [
- ["flat", [[0,0],[1,0]]],
- ["sawtooth", [[0,-0.5], [0.5,0.5], [1,-0.5]]],
- ["sinewave", [for (a=[0:5:360]) [a/360,sin(a)/2]]],
- ["comb", let(dx=0.5*sin(2)) [[0,0],[0+dx,0.5],[0.5-dx,0.5],[0.5+dx,-0.5],[1-dx,-0.5],[1,0]]],
- ["finger", let(dx=0.5*sin(20)) [[0,0],[0+dx,0.5],[0.5-dx,0.5],[0.5+dx,-0.5],[1-dx,-0.5],[1,0]]],
- ["dovetail", [[0,-0.5], [0.3,-0.5], [0.2,0.5], [0.8,0.5], [0.7,-0.5], [1,-0.5]]],
- ["hammerhead", [[0,-0.5], [0.35,-0.5], [0.35,0], [0.15,0], [0.15,0.5], [0.85,0.5], [0.85,0], [0.65,0], [0.65,-0.5],[1,-0.5]]],
- ["jigsaw", concat(
- arc(N=6, r=5/16, cp=[0,-3/16], start=270, angle=125),
- arc(N=12, r=5/16, cp=[1/2,3/16], start=215, angle=-250),
- arc(N=6, r=5/16, cp=[1,-3/16], start=145, angle=125)
- )
- ],
+ ["flat", [[0,0],[1,0]]],
+ ["sawtooth", [[0,-0.5], [0.5,0.5], [1,-0.5]]],
+ ["sinewave", [for (a=[0:5:360]) [a/360,sin(a)/2]]],
+ ["comb", let(dx=0.5*sin(2)) [[0,0],[0+dx,0.5],[0.5-dx,0.5],[0.5+dx,-0.5],[1-dx,-0.5],[1,0]]],
+ ["finger", let(dx=0.5*sin(20)) [[0,0],[0+dx,0.5],[0.5-dx,0.5],[0.5+dx,-0.5],[1-dx,-0.5],[1,0]]],
+ ["dovetail", [[0,-0.5], [0.3,-0.5], [0.2,0.5], [0.8,0.5], [0.7,-0.5], [1,-0.5]]],
+ ["hammerhead", [[0,-0.5], [0.35,-0.5], [0.35,0], [0.15,0], [0.15,0.5], [0.85,0.5], [0.85,0], [0.65,0], [0.65,-0.5],[1,-0.5]]],
+ ["jigsaw", concat(
+ arc(N=6, r=5/16, cp=[0,-3/16], start=270, angle=125),
+ arc(N=12, r=5/16, cp=[1/2,3/16], start=215, angle=-250),
+ arc(N=6, r=5/16, cp=[1,-3/16], start=145, angle=125)
+ )
+ ],
];
function _partition_cutpath(l, h, cutsize, cutpath, gap) =
- let(
- cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize],
- cutpath = is_path(cutpath)? cutpath : (
- assert(is_string(cutpath), "cutpath must be a 2D path or a string.")
- let(idx = search([cutpath], _partition_cutpaths))
- idx==[[]]? assert(in_list(cutpath,_partition_cutpaths,idx=0)) :
- _partition_cutpaths[idx.x][1]
- ),
- reps = ceil(l/(cutsize.x+gap)),
- cplen = (cutsize.x+gap) * reps,
- path = deduplicate(concat(
- [[-l/2, cutpath[0].y*cutsize.y]],
- [for (i=[0:1:reps-1], pt=cutpath) vmul(pt,cutsize)+[i*(cutsize.x+gap)+gap/2-cplen/2,0]],
- [[ l/2, cutpath[len(cutpath)-1].y*cutsize.y]]
- ))
- ) path;
+ let(
+ cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize],
+ cutpath = is_path(cutpath)? cutpath : (
+ assert(is_string(cutpath), "cutpath must be a 2D path or a string.")
+ let(idx = search([cutpath], _partition_cutpaths))
+ idx==[[]]? assert(in_list(cutpath,_partition_cutpaths,idx=0)) :
+ _partition_cutpaths[idx.x][1]
+ ),
+ reps = ceil(l/(cutsize.x+gap)),
+ cplen = (cutsize.x+gap) * reps,
+ path = deduplicate(concat(
+ [[-l/2, cutpath[0].y*cutsize.y]],
+ [for (i=[0:1:reps-1], pt=cutpath) vmul(pt,cutsize)+[i*(cutsize.x+gap)+gap/2-cplen/2,0]],
+ [[ l/2, cutpath[len(cutpath)-1].y*cutsize.y]]
+ ))
+ ) path;
// Module: partition_mask()
@@ -79,16 +79,16 @@ function _partition_cutpath(l, h, cutsize, cutpath, gap) =
// partition_mask(w=20, cutpath="jigsaw");
module partition_mask(l=100, w=100, h=100, cutsize=10, cutpath=undef, gap=0, inverse=false, spin=0, orient=UP)
{
- cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
- path = _partition_cutpath(l, h, cutsize, cutpath, gap);
- fullpath = concat(path, [[l/2,w*(inverse?-1:1)], [-l/2,w*(inverse?-1:1)]]);
- rot(from=UP,to=orient) {
- rotate(spin) {
- linear_extrude(height=h, convexity=10) {
- offset(delta=-$slop) polygon(fullpath);
- }
- }
- }
+ cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
+ path = _partition_cutpath(l, h, cutsize, cutpath, gap);
+ fullpath = concat(path, [[l/2,w*(inverse?-1:1)], [-l/2,w*(inverse?-1:1)]]);
+ rot(from=UP,to=orient) {
+ rotate(spin) {
+ linear_extrude(height=h, convexity=10) {
+ offset(delta=-$slop) polygon(fullpath);
+ }
+ }
+ }
}
@@ -121,15 +121,15 @@ module partition_mask(l=100, w=100, h=100, cutsize=10, cutpath=undef, gap=0, inv
// partition_cut_mask(cutpath="jigsaw");
module partition_cut_mask(l=100, h=100, cutsize=10, cutpath=undef, gap=0, spin=0, orient=UP)
{
- cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
- path = _partition_cutpath(l, h, cutsize, cutpath, gap);
- rot(from=UP,to=orient) {
- rotate(spin) {
- linear_extrude(height=h, convexity=10) {
- stroke(path, width=$slop*2);
- }
- }
- }
+ cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
+ path = _partition_cutpath(l, h, cutsize, cutpath, gap);
+ rot(from=UP,to=orient) {
+ rotate(spin) {
+ linear_extrude(height=h, convexity=10) {
+ stroke(path, width=$slop*2);
+ }
+ }
+ }
}
@@ -160,24 +160,24 @@ module partition_cut_mask(l=100, h=100, cutsize=10, cutpath=undef, gap=0, spin=0
// partition(cutpath="jigsaw") cylinder(h=50, d=80, center=false);
module partition(size=100, spread=10, cutsize=10, cutpath=undef, gap=0, spin=0)
{
- size = is_vector(size)? size : [size,size,size];
- cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
- rsize = vabs(rot(spin,p=size));
- vec = rot(spin,p=BACK)*spread/2;
- move(vec) {
- intersection() {
- children();
- partition_mask(l=rsize.x, w=rsize.y, h=rsize.z, cutsize=cutsize, cutpath=cutpath, gap=gap, spin=spin);
- }
- }
- move(-vec) {
- intersection() {
- children();
- partition_mask(l=rsize.x, w=rsize.y, h=rsize.z, cutsize=cutsize, cutpath=cutpath, gap=gap, inverse=true, spin=spin);
- }
- }
+ size = is_vector(size)? size : [size,size,size];
+ cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
+ rsize = vabs(rot(spin,p=size));
+ vec = rot(spin,p=BACK)*spread/2;
+ move(vec) {
+ intersection() {
+ children();
+ partition_mask(l=rsize.x, w=rsize.y, h=rsize.z, cutsize=cutsize, cutpath=cutpath, gap=gap, spin=spin);
+ }
+ }
+ move(-vec) {
+ intersection() {
+ children();
+ partition_mask(l=rsize.x, w=rsize.y, h=rsize.z, cutsize=cutsize, cutpath=cutpath, gap=gap, inverse=true, spin=spin);
+ }
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/paths.scad b/paths.scad
index 34a1f55..ad8b732 100644
--- a/paths.scad
+++ b/paths.scad
@@ -43,10 +43,10 @@ include
// dim = list of allowed dimensions of the vectors in the path. Default: [2,3]
// fast = set to true for fast check that only looks at first entry. Default: false
function is_path(list, dim=[2,3], fast=false) =
- fast? is_list(list) && is_vector(list[0],fast=true) :
- is_list(list) && is_list(list[0]) && len(list)>1 &&
- (is_undef(dim) || in_list(len(list[0]), force_list(dim))) &&
- is_list_of(list, repeat(0,len(list[0])));
+ fast? is_list(list) && is_vector(list[0],fast=true) :
+ is_list(list) && is_list(list[0]) && len(list)>1 &&
+ (is_undef(dim) || in_list(len(list[0]), force_list(dim))) &&
+ is_list_of(list, repeat(0,len(list[0])));
// Function: is_closed_path()
@@ -88,19 +88,19 @@ function cleanup_path(path, eps=EPSILON) = is_closed_path(path,eps=eps)? select(
// u2 = The proportion along the ending segment, between 0.0 and 1.0, inclusive.
// closed = If true, treat path as a closed polygon.
function path_subselect(path, s1, u1, s2, u2, closed=false) =
- let(
- lp = len(path),
- l = lp-(closed?0:1),
- u1 = s1<0? 0 : s1>l? 1 : u1,
- u2 = s2<0? 0 : s2>l? 1 : u2,
- s1 = constrain(s1,0,l),
- s2 = constrain(s2,0,l),
- pathout = concat(
- (s10)? [lerp(path[s2],path[(s2+1)%lp],u2)] : []
- )
- ) pathout;
+ let(
+ lp = len(path),
+ l = lp-(closed?0:1),
+ u1 = s1<0? 0 : s1>l? 1 : u1,
+ u2 = s2<0? 0 : s2>l? 1 : u2,
+ s1 = constrain(s1,0,l),
+ s2 = constrain(s2,0,l),
+ pathout = concat(
+ (s10)? [lerp(path[s2],path[(s2+1)%lp],u2)] : []
+ )
+ ) pathout;
// Function: simplify_path()
@@ -112,9 +112,9 @@ function path_subselect(path, s1, u1, s2, u2, closed=false) =
// path = A list of 2D path points.
// eps = Largest positional variance allowed. Default: `EPSILON` (1-e9)
function simplify_path(path, eps=EPSILON) =
- len(path)<=2? path : let(
- indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(path, i-1, i, i+1, eps=eps)) i], [len(path)-1])
- ) [for (i = indices) path[i]];
+ len(path)<=2? path : let(
+ indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(path, i-1, i, i+1, eps=eps)) i], [len(path)-1])
+ ) [for (i = indices) path[i]];
// Function: simplify_path_indexed()
@@ -128,9 +128,9 @@ function simplify_path(path, eps=EPSILON) =
// path = A list of indices into `points` that forms a path.
// eps = Largest angle variance allowed. Default: EPSILON (1-e9) degrees.
function simplify_path_indexed(points, path, eps=EPSILON) =
- len(path)<=2? path : let(
- indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(points, path[i-1], path[i], path[i+1], eps=eps)) i], [len(path)-1])
- ) [for (i = indices) path[i]];
+ len(path)<=2? path : let(
+ indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(points, path[i-1], path[i], path[i+1], eps=eps)) i], [len(path)-1])
+ ) [for (i = indices) path[i]];
// Function: path_length()
@@ -145,8 +145,8 @@ function simplify_path_indexed(points, path, eps=EPSILON) =
// path = [[0,0], [5,35], [60,-25], [80,0]];
// echo(path_length(path));
function path_length(path,closed=false) =
- len(path)<2? 0 :
- sum([for (i = [0:1:len(path)-2]) norm(path[i+1]-path[i])])+(closed?norm(path[len(path)-1]-path[0]):0);
+ len(path)<2? 0 :
+ sum([for (i = [0:1:len(path)-2]) norm(path[i+1]-path[i])])+(closed?norm(path[len(path)-1]-path[0]):0);
// Function: path_pos_from_start()
@@ -167,11 +167,11 @@ function path_length(path,closed=false) =
// pt = lerp(path[pos[0]], path[(pos[0]+1)%len(path)], pos[1]);
// color("red") translate(pt) circle(d=2,$fn=12);
function path_pos_from_start(path,length,closed=false,_d=0,_i=0) =
- let (lp = len(path))
- _i >= lp - (closed?0:1)? undef :
- let (l = norm(path[(_i+1)%lp]-path[_i]))
- _d+l <= length? path_pos_from_start(path,length,closed,_d+l,_i+1) :
- [_i, (length-_d)/l];
+ let (lp = len(path))
+ _i >= lp - (closed?0:1)? undef :
+ let (l = norm(path[(_i+1)%lp]-path[_i]))
+ _d+l <= length? path_pos_from_start(path,length,closed,_d+l,_i+1) :
+ [_i, (length-_d)/l];
// Function: path_pos_from_end()
@@ -192,14 +192,14 @@ function path_pos_from_start(path,length,closed=false,_d=0,_i=0) =
// pt = lerp(path[pos[0]], path[(pos[0]+1)%len(path)], pos[1]);
// color("red") translate(pt) circle(d=2,$fn=12);
function path_pos_from_end(path,length,closed=false,_d=0,_i=undef) =
- let (
- lp = len(path),
- _i = _i!=undef? _i : lp - (closed?1:2)
- )
- _i < 0? undef :
- let (l = norm(path[(_i+1)%lp]-path[_i]))
- _d+l <= length? path_pos_from_end(path,length,closed,_d+l,_i-1) :
- [_i, 1-(length-_d)/l];
+ let (
+ lp = len(path),
+ _i = _i!=undef? _i : lp - (closed?1:2)
+ )
+ _i < 0? undef :
+ let (l = norm(path[(_i+1)%lp]-path[_i]))
+ _d+l <= length? path_pos_from_end(path,length,closed,_d+l,_i-1) :
+ [_i, 1-(length-_d)/l];
// Function: path_trim_start()
@@ -218,14 +218,14 @@ function path_pos_from_end(path,length,closed=false,_d=0,_i=undef) =
// color("cyan") stroke(path2,width=3,endcaps=false);
// color("red") stroke(path,width=1,endcaps=false);
function path_trim_start(path,trim,_d=0,_i=0) =
- _i >= len(path)-1? [] :
- let (l = norm(path[_i+1]-path[_i]))
- _d+l <= trim? path_trim_start(path,trim,_d+l,_i+1) :
- let (v = unit(path[_i+1]-path[_i]))
- concat(
- [path[_i+1]-v*(l-(trim-_d))],
- [for (i=[_i+1:1:len(path)-1]) path[i]]
- );
+ _i >= len(path)-1? [] :
+ let (l = norm(path[_i+1]-path[_i]))
+ _d+l <= trim? path_trim_start(path,trim,_d+l,_i+1) :
+ let (v = unit(path[_i+1]-path[_i]))
+ concat(
+ [path[_i+1]-v*(l-(trim-_d))],
+ [for (i=[_i+1:1:len(path)-1]) path[i]]
+ );
// Function: path_trim_end()
@@ -244,15 +244,15 @@ function path_trim_start(path,trim,_d=0,_i=0) =
// color("cyan") stroke(path2,width=3,endcaps=false);
// color("red") stroke(path,width=1,endcaps=false);
function path_trim_end(path,trim,_d=0,_i=undef) =
- let (_i = _i!=undef? _i : len(path)-1)
- _i <= 0? [] :
- let (l = norm(path[_i]-path[_i-1]))
- _d+l <= trim? path_trim_end(path,trim,_d+l,_i-1) :
- let (v = unit(path[_i]-path[_i-1]))
- concat(
- [for (i=[0:1:_i-1]) path[i]],
- [path[_i-1]+v*(l-(trim-_d))]
- );
+ let (_i = _i!=undef? _i : len(path)-1)
+ _i <= 0? [] :
+ let (l = norm(path[_i]-path[_i-1]))
+ _d+l <= trim? path_trim_end(path,trim,_d+l,_i-1) :
+ let (v = unit(path[_i]-path[_i-1]))
+ concat(
+ [for (i=[0:1:_i-1]) path[i]],
+ [path[_i-1]+v*(l-(trim-_d))]
+ );
// Function: path_closest_point()
@@ -272,11 +272,11 @@ function path_trim_end(path,trim,_d=0,_i=undef) =
// color("blue") translate(pt) circle(d=3, $fn=12);
// color("red") translate(closest[1]) circle(d=3, $fn=12);
function path_closest_point(path, pt) =
- let(
- pts = [for (seg=idx(path)) segment_closest_point(select(path,seg,seg+1),pt)],
- dists = [for (p=pts) norm(p-pt)],
- min_seg = min_index(dists)
- ) [min_seg, pts[min_seg]];
+ let(
+ pts = [for (seg=idx(path)) segment_closest_point(select(path,seg,seg+1),pt)],
+ dists = [for (p=pts) norm(p-pt)],
+ min_seg = min_index(dists)
+ ) [min_seg, pts[min_seg]];
// Function: path_tangents()
@@ -285,8 +285,8 @@ function path_closest_point(path, pt) =
// Compute the tangent vector to the input path. The derivative approximation is described in deriv().
// The returns vectors will be normalized to length 1.
function path_tangents(path, closed=false) =
- assert(is_path(path))
- [for(t=deriv(path,closed=closed)) unit(t)];
+ assert(is_path(path))
+ [for(t=deriv(path,closed=closed)) unit(t)];
// Function: path_normals()
@@ -296,20 +296,20 @@ function path_tangents(path, closed=false) =
// path tangent and lies in the plane of the curve. When there are collinear points,
// the curve does not define a unique plane and the normal is not uniquely defined.
function path_normals(path, tangents, closed=false) =
- assert(is_path(path))
- assert(is_bool(closed))
- let( tangents = default(tangents, path_tangents(path,closed)) )
- assert(is_path(tangents))
- [
- for(i=idx(path)) let(
- pts = i==0? (closed? select(path,-1,1) : select(path,0,2)) :
- i==len(path)-1? (closed? select(path,i-1,i+1) : select(path,i-2,i)) :
- select(path,i-1,i+1)
- ) unit(cross(
- cross(pts[1]-pts[0], pts[2]-pts[0]),
- tangents[i]
- ))
- ];
+ assert(is_path(path))
+ assert(is_bool(closed))
+ let( tangents = default(tangents, path_tangents(path,closed)) )
+ assert(is_path(tangents))
+ [
+ for(i=idx(path)) let(
+ pts = i==0? (closed? select(path,-1,1) : select(path,0,2)) :
+ i==len(path)-1? (closed? select(path,i-1,i+1) : select(path,i-2,i)) :
+ select(path,i-1,i+1)
+ ) unit(cross(
+ cross(pts[1]-pts[0], pts[2]-pts[0]),
+ tangents[i]
+ ))
+ ];
// Function: path_curvature()
@@ -317,16 +317,16 @@ function path_normals(path, tangents, closed=false) =
// Description:
// Numerically estimate the curvature of the path (in any dimension).
function path_curvature(path, closed=false) =
- let(
- d1 = deriv(path, closed=closed),
- d2 = deriv2(path, closed=closed)
- ) [
- for(i=idx(path))
- sqrt(
- sqr(norm(d1[i])*norm(d2[i])) -
- sqr(d1[i]*d2[i])
- ) / pow(norm(d1[i]),3)
- ];
+ let(
+ d1 = deriv(path, closed=closed),
+ d2 = deriv2(path, closed=closed)
+ ) [
+ for(i=idx(path))
+ sqrt(
+ sqr(norm(d1[i])*norm(d2[i])) -
+ sqr(d1[i]*d2[i])
+ ) / pow(norm(d1[i]),3)
+ ];
// Function: path_torsion()
@@ -334,15 +334,15 @@ function path_curvature(path, closed=false) =
// Description:
// Numerically estimate the torsion of a 3d path.
function path_torsion(path, closed=false) =
- let(
- d1 = deriv(path,closed=closed),
- d2 = deriv2(path,closed=closed),
- d3 = deriv3(path,closed=closed)
- ) [
- for (i=idx(path)) let(
- crossterm = cross(d1[i],d2[i])
- ) crossterm * d3[i] / sqr(norm(crossterm))
- ];
+ let(
+ d1 = deriv(path,closed=closed),
+ d2 = deriv2(path,closed=closed),
+ d3 = deriv3(path,closed=closed)
+ ) [
+ for (i=idx(path)) let(
+ crossterm = cross(d1[i],d2[i])
+ ) crossterm * d3[i] / sqr(norm(crossterm))
+ ];
// Function: path3d_spiral()
@@ -361,16 +361,16 @@ function path_torsion(path, closed=false) =
// Example(3D):
// trace_polyline(path3d_spiral(turns=2.5, h=100, n=24, r=50), N=1, showpts=true);
function path3d_spiral(turns=3, h=100, n=12, r=undef, d=undef, cp=[0,0], scale=[1,1]) = let(
- rr=get_radius(r=r, d=d, dflt=100),
- cnt=floor(turns*n),
- dz=h/cnt
- ) [
- for (i=[0:1:cnt]) [
- rr * cos(i*360/n) * scale.x + cp.x,
- rr * sin(i*360/n) * scale.y + cp.y,
- i*dz
- ]
- ];
+ rr=get_radius(r=r, d=d, dflt=100),
+ cnt=floor(turns*n),
+ dz=h/cnt
+ ) [
+ for (i=[0:1:cnt]) [
+ rr * cos(i*360/n) * scale.x + cp.x,
+ rr * sin(i*360/n) * scale.y + cp.y,
+ i*dz
+ ]
+ ];
// Function: points_along_path3d()
@@ -388,25 +388,25 @@ function path3d_spiral(turns=3, h=100, n=12, r=undef, d=undef, cp=[0,0], scale=[
// polyline = A closed list of 2D path points.
// path = A list of 3D path points.
function points_along_path3d(
- polyline, // The 2D polyline to drag along the 3D path.
- path, // The 3D polyline path to follow.
- q=Q_Ident(), // Used in recursion
- n=0 // Used in recursion
+ polyline, // The 2D polyline to drag along the 3D path.
+ path, // The 3D polyline path to follow.
+ q=Q_Ident(), // Used in recursion
+ n=0 // Used in recursion
) = let(
- end = len(path)-1,
- v1 = (n == 0)? [0, 0, 1] : unit(path[n]-path[n-1]),
- v2 = (n == end)? unit(path[n]-path[n-1]) : unit(path[n+1]-path[n]),
- crs = cross(v1, v2),
- axis = norm(crs) <= 0.001? [0, 0, 1] : crs,
- ang = vector_angle(v1, v2),
- hang = ang * (n==0? 1.0 : 0.5),
- hrot = Quat(axis, hang),
- arot = Quat(axis, ang),
- roth = Q_Mul(hrot, q),
- rotm = Q_Mul(arot, q)
+ end = len(path)-1,
+ v1 = (n == 0)? [0, 0, 1] : unit(path[n]-path[n-1]),
+ v2 = (n == end)? unit(path[n]-path[n-1]) : unit(path[n+1]-path[n]),
+ crs = cross(v1, v2),
+ axis = norm(crs) <= 0.001? [0, 0, 1] : crs,
+ ang = vector_angle(v1, v2),
+ hang = ang * (n==0? 1.0 : 0.5),
+ hrot = Quat(axis, hang),
+ arot = Quat(axis, ang),
+ roth = Q_Mul(hrot, q),
+ rotm = Q_Mul(arot, q)
) concat(
- [for (i = [0:1:len(polyline)-1]) Qrot(roth,p=point3d(polyline[i])) + path[n]],
- (n == end)? [] : points_along_path3d(polyline, path, rotm, n+1)
+ [for (i = [0:1:len(polyline)-1]) Qrot(roth,p=point3d(polyline[i])) + path[n]],
+ (n == end)? [] : points_along_path3d(polyline, path, rotm, n+1)
);
@@ -434,35 +434,35 @@ function points_along_path3d(
// stroke(path, closed=true, width=1);
// for (isect=isects) translate(isect[0]) color("blue") sphere(d=10);
function path_self_intersections(path, closed=true, eps=EPSILON) =
- let(
- path = cleanup_path(path, eps=eps),
- plen = len(path)
- ) [
- for (i = [0:1:plen-(closed?2:3)], j=[i+1:1:plen-(closed?1:2)]) let(
- a1 = path[i],
- a2 = path[(i+1)%plen],
- b1 = path[j],
- b2 = path[(j+1)%plen],
- isect =
- (max(a1.x, a2.x) < min(b1.x, b2.x))? undef :
- (min(a1.x, a2.x) > max(b1.x, b2.x))? undef :
- (max(a1.y, a2.y) < min(b1.y, b2.y))? undef :
- (min(a1.y, a2.y) > max(b1.y, b2.y))? undef :
- let(
- c = a1-a2,
- d = b1-b2,
- denom = (c.x*d.y)-(c.y*d.x)
- ) abs(denom)eps && isect[1]<=1+eps &&
- isect[2]>eps && isect[2]<=1+eps
- ) [isect[0], i, isect[1], j, isect[2]]
- ];
+ let(
+ path = cleanup_path(path, eps=eps),
+ plen = len(path)
+ ) [
+ for (i = [0:1:plen-(closed?2:3)], j=[i+1:1:plen-(closed?1:2)]) let(
+ a1 = path[i],
+ a2 = path[(i+1)%plen],
+ b1 = path[j],
+ b2 = path[(j+1)%plen],
+ isect =
+ (max(a1.x, a2.x) < min(b1.x, b2.x))? undef :
+ (min(a1.x, a2.x) > max(b1.x, b2.x))? undef :
+ (max(a1.y, a2.y) < min(b1.y, b2.y))? undef :
+ (min(a1.y, a2.y) > max(b1.y, b2.y))? undef :
+ let(
+ c = a1-a2,
+ d = b1-b2,
+ denom = (c.x*d.y)-(c.y*d.x)
+ ) abs(denom)eps && isect[1]<=1+eps &&
+ isect[2]>eps && isect[2]<=1+eps
+ ) [isect[0], i, isect[1], j, isect[2]]
+ ];
// Function: split_path_at_self_crossings()
@@ -480,52 +480,52 @@ function path_self_intersections(path, closed=true, eps=EPSILON) =
// polylines = split_path_at_self_crossings(path);
// rainbow(polylines) stroke($item, closed=false, width=2);
function split_path_at_self_crossings(path, closed=true, eps=EPSILON) =
- let(
- path = cleanup_path(path, eps=eps),
- isects = deduplicate(
- eps=eps,
- concat(
- [[0, 0]],
- sort([
- for (
- a = path_self_intersections(path, closed=closed, eps=eps),
- ss = [ [a[1],a[2]], [a[3],a[4]] ]
- ) if (ss[0] != undef) ss
- ]),
- [[len(path)-(closed?1:2), 1]]
- )
- )
- ) [
- for (p = pair(isects))
- let(
- s1 = p[0][0],
- u1 = p[0][1],
- s2 = p[1][0],
- u2 = p[1][1],
- section = path_subselect(path, s1, u1, s2, u2, closed=closed),
- outpath = deduplicate(eps=eps, section)
- )
- outpath
- ];
+ let(
+ path = cleanup_path(path, eps=eps),
+ isects = deduplicate(
+ eps=eps,
+ concat(
+ [[0, 0]],
+ sort([
+ for (
+ a = path_self_intersections(path, closed=closed, eps=eps),
+ ss = [ [a[1],a[2]], [a[3],a[4]] ]
+ ) if (ss[0] != undef) ss
+ ]),
+ [[len(path)-(closed?1:2), 1]]
+ )
+ )
+ ) [
+ for (p = pair(isects))
+ let(
+ s1 = p[0][0],
+ u1 = p[0][1],
+ s2 = p[1][0],
+ u2 = p[1][1],
+ section = path_subselect(path, s1, u1, s2, u2, closed=closed),
+ outpath = deduplicate(eps=eps, section)
+ )
+ outpath
+ ];
function _tag_self_crossing_subpaths(path, closed=true, eps=EPSILON) =
- let(
- subpaths = split_path_at_self_crossings(
- path, closed=closed, eps=eps
- )
- ) [
- for (subpath = subpaths) let(
- seg = select(subpath,0,1),
- mp = mean(seg),
- n = line_normal(seg) / 2048,
- p1 = mp + n,
- p2 = mp - n,
- p1in = point_in_polygon(p1, path) >= 0,
- p2in = point_in_polygon(p2, path) >= 0,
- tag = (p1in && p2in)? "I" : "O"
- ) [tag, subpath]
- ];
+ let(
+ subpaths = split_path_at_self_crossings(
+ path, closed=closed, eps=eps
+ )
+ ) [
+ for (subpath = subpaths) let(
+ seg = select(subpath,0,1),
+ mp = mean(seg),
+ n = line_normal(seg) / 2048,
+ p1 = mp + n,
+ p2 = mp - n,
+ p1in = point_in_polygon(p1, path) >= 0,
+ p2in = point_in_polygon(p2, path) >= 0,
+ tag = (p1in && p2in)? "I" : "O"
+ ) [tag, subpath]
+ ];
// Function: decompose_path()
@@ -545,74 +545,74 @@ function _tag_self_crossing_subpaths(path, closed=true, eps=EPSILON) =
// splitpaths = decompose_path(path, closed=true);
// rainbow(splitpaths) stroke($item, closed=true, width=3);
function decompose_path(path, closed=true, eps=EPSILON) =
- let(
- path = cleanup_path(path, eps=eps),
- tagged = _tag_self_crossing_subpaths(path, closed=closed, eps=eps),
- kept = [for (sub = tagged) if(sub[0] == "O") sub[1]],
- completed = [for (frag=kept) if(is_closed_path(frag)) frag],
- incomplete = [for (frag=kept) if(!is_closed_path(frag)) frag],
- defrag = _path_fast_defragment(incomplete, eps=eps),
- completed2 = assemble_path_fragments(defrag, eps=eps)
- ) concat(completed2,completed);
+ let(
+ path = cleanup_path(path, eps=eps),
+ tagged = _tag_self_crossing_subpaths(path, closed=closed, eps=eps),
+ kept = [for (sub = tagged) if(sub[0] == "O") sub[1]],
+ completed = [for (frag=kept) if(is_closed_path(frag)) frag],
+ incomplete = [for (frag=kept) if(!is_closed_path(frag)) frag],
+ defrag = _path_fast_defragment(incomplete, eps=eps),
+ completed2 = assemble_path_fragments(defrag, eps=eps)
+ ) concat(completed2,completed);
function _path_fast_defragment(fragments, eps=EPSILON, _done=[]) =
- len(fragments)==0? _done :
- let(
- path = fragments[0],
- endpt = select(path,-1),
- extenders = [
- for (i = [1:1:len(fragments)-1]) let(
- test1 = approx(endpt,fragments[i][0],eps=eps),
- test2 = approx(endpt,select(fragments[i],-1),eps=eps)
- ) if (test1 || test2) (test1? i : -1)
- ]
- ) len(extenders) == 1 && extenders[0] >= 0? _path_fast_defragment(
- fragments=[
- concat(select(path,0,-2),fragments[extenders[0]]),
- for (i = [1:1:len(fragments)-1])
- if (i != extenders[0]) fragments[i]
- ],
- eps=eps,
- _done=_done
- ) : _path_fast_defragment(
- fragments=[for (i = [1:1:len(fragments)-1]) fragments[i]],
- eps=eps,
- _done=concat(_done,[deduplicate(path,closed=true,eps=eps)])
- );
+ len(fragments)==0? _done :
+ let(
+ path = fragments[0],
+ endpt = select(path,-1),
+ extenders = [
+ for (i = [1:1:len(fragments)-1]) let(
+ test1 = approx(endpt,fragments[i][0],eps=eps),
+ test2 = approx(endpt,select(fragments[i],-1),eps=eps)
+ ) if (test1 || test2) (test1? i : -1)
+ ]
+ ) len(extenders) == 1 && extenders[0] >= 0? _path_fast_defragment(
+ fragments=[
+ concat(select(path,0,-2),fragments[extenders[0]]),
+ for (i = [1:1:len(fragments)-1])
+ if (i != extenders[0]) fragments[i]
+ ],
+ eps=eps,
+ _done=_done
+ ) : _path_fast_defragment(
+ fragments=[for (i = [1:1:len(fragments)-1]) fragments[i]],
+ eps=eps,
+ _done=concat(_done,[deduplicate(path,closed=true,eps=eps)])
+ );
function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
- !fragments? [undef, []] :
- let(
- delta = seg[1] - seg[0],
- segang = atan2(delta.y,delta.x),
- frags = [
- for (i = idx(fragments)) let(
- fragment = fragments[i],
- fwdmatch = approx(seg[1], fragment[0], eps=eps),
- bakmatch = approx(seg[1], select(fragment,-1), eps=eps)
- ) [
- fwdmatch,
- bakmatch,
- bakmatch? reverse(fragment) : fragment
- ]
- ],
- angs = [
- for (frag = frags)
- (frag[0] || frag[1])? let(
- delta2 = frag[2][1] - frag[2][0],
- segang2 = atan2(delta2.y, delta2.x)
- ) modang(segang2 - segang) : (
- rightmost? 999 : -999
- )
- ],
- fi = rightmost? min_index(angs) : max_index(angs)
- ) abs(angs[fi]) > 360? [undef, fragments] : let(
- remainder = [for (i=idx(fragments)) if (i!=fi) fragments[i]],
- frag = frags[fi],
- foundfrag = frag[2]
- ) [foundfrag, remainder];
+ !fragments? [undef, []] :
+ let(
+ delta = seg[1] - seg[0],
+ segang = atan2(delta.y,delta.x),
+ frags = [
+ for (i = idx(fragments)) let(
+ fragment = fragments[i],
+ fwdmatch = approx(seg[1], fragment[0], eps=eps),
+ bakmatch = approx(seg[1], select(fragment,-1), eps=eps)
+ ) [
+ fwdmatch,
+ bakmatch,
+ bakmatch? reverse(fragment) : fragment
+ ]
+ ],
+ angs = [
+ for (frag = frags)
+ (frag[0] || frag[1])? let(
+ delta2 = frag[2][1] - frag[2][0],
+ segang2 = atan2(delta2.y, delta2.x)
+ ) modang(segang2 - segang) : (
+ rightmost? 999 : -999
+ )
+ ],
+ fi = rightmost? min_index(angs) : max_index(angs)
+ ) abs(angs[fi]) > 360? [undef, fragments] : let(
+ remainder = [for (i=idx(fragments)) if (i!=fi) fragments[i]],
+ frag = frags[fi],
+ foundfrag = frag[2]
+ ) [foundfrag, remainder];
// Function: assemble_a_path_from_fragments()
@@ -628,48 +628,48 @@ function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
// startfrag = The fragment to start with. Default: 0
// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=EPSILON) =
- len(fragments)==0? _finished :
- let(
- path = fragments[startfrag],
- newfrags = [for (i=idx(fragments)) if (i!=startfrag) fragments[i]]
- ) is_closed_path(path, eps=eps)? (
- // starting fragment is already closed
- [path, newfrags]
- ) : let(
- // Find rightmost/leftmost continuation fragment
- seg = select(path,-2,-1),
- extrema = _extreme_angle_fragment(seg=seg, fragments=newfrags, rightmost=rightmost, eps=eps),
- foundfrag = extrema[0],
- remainder = extrema[1]
- ) is_undef(foundfrag)? (
- // No remaining fragments connect! INCOMPLETE PATH!
- // Treat it as complete.
- [path, remainder]
- ) : is_closed_path(foundfrag, eps=eps)? (
- // Found fragment is already closed
- [foundfrag, concat([path], remainder)]
- ) : let(
- fragend = select(foundfrag,-1),
- hits = [for (i = idx(path,end=-2)) if(approx(path[i],fragend,eps=eps)) i]
- ) hits? (
- let(
- // Found fragment intersects with initial path
- hitidx = select(hits,-1),
- newpath = slice(path,0,hitidx+1),
- newfrags = concat(len(newpath)>1? [newpath] : [], remainder),
- outpath = concat(slice(path,hitidx,-2), foundfrag)
- )
- [outpath, newfrags]
- ) : let(
- // Path still incomplete. Continue building it.
- newpath = concat(path, slice(foundfrag, 1, -1)),
- newfrags = concat([newpath], remainder)
- )
- assemble_a_path_from_fragments(
- fragments=newfrags,
- rightmost=rightmost,
- eps=eps
- );
+ len(fragments)==0? _finished :
+ let(
+ path = fragments[startfrag],
+ newfrags = [for (i=idx(fragments)) if (i!=startfrag) fragments[i]]
+ ) is_closed_path(path, eps=eps)? (
+ // starting fragment is already closed
+ [path, newfrags]
+ ) : let(
+ // Find rightmost/leftmost continuation fragment
+ seg = select(path,-2,-1),
+ extrema = _extreme_angle_fragment(seg=seg, fragments=newfrags, rightmost=rightmost, eps=eps),
+ foundfrag = extrema[0],
+ remainder = extrema[1]
+ ) is_undef(foundfrag)? (
+ // No remaining fragments connect! INCOMPLETE PATH!
+ // Treat it as complete.
+ [path, remainder]
+ ) : is_closed_path(foundfrag, eps=eps)? (
+ // Found fragment is already closed
+ [foundfrag, concat([path], remainder)]
+ ) : let(
+ fragend = select(foundfrag,-1),
+ hits = [for (i = idx(path,end=-2)) if(approx(path[i],fragend,eps=eps)) i]
+ ) hits? (
+ let(
+ // Found fragment intersects with initial path
+ hitidx = select(hits,-1),
+ newpath = slice(path,0,hitidx+1),
+ newfrags = concat(len(newpath)>1? [newpath] : [], remainder),
+ outpath = concat(slice(path,hitidx,-2), foundfrag)
+ )
+ [outpath, newfrags]
+ ) : let(
+ // Path still incomplete. Continue building it.
+ newpath = concat(path, slice(foundfrag, 1, -1)),
+ newfrags = concat([newpath], remainder)
+ )
+ assemble_a_path_from_fragments(
+ fragments=newfrags,
+ rightmost=rightmost,
+ eps=eps
+ );
// Function: assemble_path_fragments()
@@ -681,34 +681,34 @@ function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0,
// fragments = List of polylines to be assembled into complete polygons.
// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) =
- len(fragments)==0? _finished :
- let(
- minxidx = min_index([
- for (frag=fragments) min(subindex(frag,0))
- ]),
- result_l = assemble_a_path_from_fragments(
- fragments=fragments,
- startfrag=minxidx,
- rightmost=false,
- eps=eps
- ),
- result_r = assemble_a_path_from_fragments(
- fragments=fragments,
- startfrag=minxidx,
- rightmost=true,
- eps=eps
- ),
- l_area = abs(polygon_area(result_l[0])),
- r_area = abs(polygon_area(result_r[0])),
- result = l_area < r_area? result_l : result_r,
- newpath = cleanup_path(result[0]),
- remainder = result[1],
- finished = concat(_finished, [newpath])
- ) assemble_path_fragments(
- fragments=remainder,
- eps=eps,
- _finished=finished
- );
+ len(fragments)==0? _finished :
+ let(
+ minxidx = min_index([
+ for (frag=fragments) min(subindex(frag,0))
+ ]),
+ result_l = assemble_a_path_from_fragments(
+ fragments=fragments,
+ startfrag=minxidx,
+ rightmost=false,
+ eps=eps
+ ),
+ result_r = assemble_a_path_from_fragments(
+ fragments=fragments,
+ startfrag=minxidx,
+ rightmost=true,
+ eps=eps
+ ),
+ l_area = abs(polygon_area(result_l[0])),
+ r_area = abs(polygon_area(result_r[0])),
+ result = l_area < r_area? result_l : result_r,
+ newpath = cleanup_path(result[0]),
+ remainder = result[1],
+ finished = concat(_finished, [newpath])
+ ) assemble_path_fragments(
+ fragments=remainder,
+ eps=eps,
+ _finished=finished
+ );
@@ -725,12 +725,12 @@ function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) =
// modulated_circle(r=40, sines=[[3, 11], [1, 31]], $fn=6);
module modulated_circle(r=40, sines=[10])
{
- freqs = len(sines)>0? [for (i=sines) i[1]] : [5];
- points = [
- for (a = [0 : (360/segs(r)/max(freqs)) : 360])
- let(nr=r+sum_of_sines(a,sines)) [nr*cos(a), nr*sin(a)]
- ];
- polygon(points);
+ freqs = len(sines)>0? [for (i=sines) i[1]] : [5];
+ points = [
+ for (a = [0 : (360/segs(r)/max(freqs)) : 360])
+ let(nr=r+sum_of_sines(a,sines)) [nr*cos(a), nr*sin(a)]
+ ];
+ polygon(points);
}
@@ -752,14 +752,14 @@ module modulated_circle(r=40, sines=[10])
// xcopies(3) circle(3, $fn=32);
// }
module extrude_from_to(pt1, pt2, convexity=undef, twist=undef, scale=undef, slices=undef) {
- rtp = xyz_to_spherical(pt2-pt1);
- translate(pt1) {
- rotate([0, rtp[2], rtp[1]]) {
- linear_extrude(height=rtp[0], convexity=convexity, center=false, slices=slices, twist=twist, scale=scale) {
- children();
- }
- }
- }
+ rtp = xyz_to_spherical(pt2-pt1);
+ translate(pt1) {
+ rotate([0, rtp[2], rtp[1]]) {
+ linear_extrude(height=rtp[0], convexity=convexity, center=false, slices=slices, twist=twist, scale=scale) {
+ children();
+ }
+ }
+ }
}
@@ -781,53 +781,53 @@ module extrude_from_to(pt1, pt2, convexity=undef, twist=undef, scale=undef, slic
// poly = [[-10,0], [-3,-5], [3,-5], [10,0], [0,-30]];
// spiral_sweep(poly, h=200, r=50, twist=1080, $fn=36);
module spiral_sweep(polyline, h, r, twist=360, center, anchor, spin=0, orient=UP) {
- polyline = path3d(polyline);
- pline_count = len(polyline);
- steps = ceil(segs(r)*(twist/360));
- anchor = get_anchor(anchor,center,BOT,BOT);
+ polyline = path3d(polyline);
+ pline_count = len(polyline);
+ steps = ceil(segs(r)*(twist/360));
+ anchor = get_anchor(anchor,center,BOT,BOT);
- poly_points = [
- for (
- p = [0:1:steps]
- ) let (
- a = twist * (p/steps),
- dx = r*cos(a),
- dy = r*sin(a),
- dz = h * (p/steps),
- pts = apply_list(
- polyline, [
- affine3d_xrot(90),
- affine3d_zrot(a),
- affine3d_translate([dx, dy, dz-h/2])
- ]
- )
- ) for (pt = pts) pt
- ];
+ poly_points = [
+ for (
+ p = [0:1:steps]
+ ) let (
+ a = twist * (p/steps),
+ dx = r*cos(a),
+ dy = r*sin(a),
+ dz = h * (p/steps),
+ pts = apply_list(
+ polyline, [
+ affine3d_xrot(90),
+ affine3d_zrot(a),
+ affine3d_translate([dx, dy, dz-h/2])
+ ]
+ )
+ ) for (pt = pts) pt
+ ];
- poly_faces = concat(
- [[for (b = [0:1:pline_count-1]) b]],
- [
- for (
- p = [0:1:steps-1],
- b = [0:1:pline_count-1],
- i = [0:1]
- ) let (
- b2 = (b == pline_count-1)? 0 : b+1,
- p0 = p * pline_count + b,
- p1 = p * pline_count + b2,
- p2 = (p+1) * pline_count + b2,
- p3 = (p+1) * pline_count + b,
- pt = (i==0)? [p0, p2, p1] : [p0, p3, p2]
- ) pt
- ],
- [[for (b = [pline_count-1:-1:0]) b+(steps)*pline_count]]
- );
+ poly_faces = concat(
+ [[for (b = [0:1:pline_count-1]) b]],
+ [
+ for (
+ p = [0:1:steps-1],
+ b = [0:1:pline_count-1],
+ i = [0:1]
+ ) let (
+ b2 = (b == pline_count-1)? 0 : b+1,
+ p0 = p * pline_count + b,
+ p1 = p * pline_count + b2,
+ p2 = (p+1) * pline_count + b2,
+ p3 = (p+1) * pline_count + b,
+ pt = (i==0)? [p0, p2, p1] : [p0, p3, p2]
+ ) pt
+ ],
+ [[for (b = [pline_count-1:-1:0]) b+(steps)*pline_count]]
+ );
- tri_faces = triangulate_faces(poly_points, poly_faces);
- attachable(anchor,spin,orient, r=r, l=h) {
- polyhedron(points=poly_points, faces=tri_faces, convexity=10);
- children();
- }
+ tri_faces = triangulate_faces(poly_points, poly_faces);
+ attachable(anchor,spin,orient, r=r, l=h) {
+ polyhedron(points=poly_points, faces=tri_faces, convexity=10);
+ children();
+ }
}
@@ -843,44 +843,44 @@ module spiral_sweep(polyline, h, r, twist=360, center, anchor, spin=0, orient=UP
// path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ];
// path_extrude(path) circle(r=10, $fn=6);
module path_extrude(path, convexity=10, clipsize=100) {
- function polyquats(path, q=Q_Ident(), v=[0,0,1], i=0) = let(
- v2 = path[i+1] - path[i],
- ang = vector_angle(v,v2),
- axis = ang>0.001? unit(cross(v,v2)) : [0,0,1],
- newq = Q_Mul(Quat(axis, ang), q),
- dist = norm(v2)
- ) i < (len(path)-2)?
- concat([[dist, newq, ang]], polyquats(path, newq, v2, i+1)) :
- [[dist, newq, ang]];
+ function polyquats(path, q=Q_Ident(), v=[0,0,1], i=0) = let(
+ v2 = path[i+1] - path[i],
+ ang = vector_angle(v,v2),
+ axis = ang>0.001? unit(cross(v,v2)) : [0,0,1],
+ newq = Q_Mul(Quat(axis, ang), q),
+ dist = norm(v2)
+ ) i < (len(path)-2)?
+ concat([[dist, newq, ang]], polyquats(path, newq, v2, i+1)) :
+ [[dist, newq, ang]];
- epsilon = 0.0001; // Make segments ever so slightly too long so they overlap.
- ptcount = len(path);
- pquats = polyquats(path);
- for (i = [0:1:ptcount-2]) {
- pt1 = path[i];
- pt2 = path[i+1];
- dist = pquats[i][0];
- q = pquats[i][1];
- difference() {
- translate(pt1) {
- Qrot(q) {
- down(clipsize/2/2) {
- linear_extrude(height=dist+clipsize/2, convexity=convexity) {
- children();
- }
- }
- }
- }
- translate(pt1) {
- hq = (i > 0)? Q_Slerp(q, pquats[i-1][1], 0.5) : q;
- Qrot(hq) down(clipsize/2+epsilon) cube(clipsize, center=true);
- }
- translate(pt2) {
- hq = (i < ptcount-2)? Q_Slerp(q, pquats[i+1][1], 0.5) : q;
- Qrot(hq) up(clipsize/2+epsilon) cube(clipsize, center=true);
- }
- }
- }
+ epsilon = 0.0001; // Make segments ever so slightly too long so they overlap.
+ ptcount = len(path);
+ pquats = polyquats(path);
+ for (i = [0:1:ptcount-2]) {
+ pt1 = path[i];
+ pt2 = path[i+1];
+ dist = pquats[i][0];
+ q = pquats[i][1];
+ difference() {
+ translate(pt1) {
+ Qrot(q) {
+ down(clipsize/2/2) {
+ linear_extrude(height=dist+clipsize/2, convexity=convexity) {
+ children();
+ }
+ }
+ }
+ }
+ translate(pt1) {
+ hq = (i > 0)? Q_Slerp(q, pquats[i-1][1], 0.5) : q;
+ Qrot(hq) down(clipsize/2+epsilon) cube(clipsize, center=true);
+ }
+ translate(pt2) {
+ hq = (i < ptcount-2)? Q_Slerp(q, pquats[i+1][1], 0.5) : q;
+ Qrot(hq) up(clipsize/2+epsilon) cube(clipsize, center=true);
+ }
+ }
+ }
}
@@ -969,46 +969,46 @@ module path_extrude(path, convexity=10, clipsize=100) {
// }
module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=false)
{
- length = path_length(path,closed);
- distances = is_def(sp)? (
- is_def(n) && is_def(spacing)? list_range(s=sp, step=spacing, n=n) :
- is_def(n)? list_range(s=sp, e=length, n=n) :
- list_range(s=sp, step=spacing, e=length)
- ) : is_def(n) && is_undef(spacing)? (
- closed?
- let(range=list_range(s=0,e=length, n=n+1)) slice(range,0,-2) :
- list_range(s=0, e=length, n=n)
- ) : (
- let(
- n = is_def(n)? n : floor(length/spacing)+(closed?0:1),
- ptlist = list_range(s=0,step=spacing,n=n),
- listcenter = mean(ptlist)
- ) closed?
- sort([for(entry=ptlist) posmod(entry-listcenter,length)]) :
- [for(entry=ptlist) entry + length/2-listcenter ]
- );
- distOK = min(distances)>=0 && max(distances)<=length;
- assert(distOK,"Cannot fit all of the copies");
- cutlist = path_cut(path, distances, closed, direction=true);
- planar = len(path[0])==2;
- if (true) for(i=[0:1:len(cutlist)-1]) {
- $pos = cutlist[i][0];
- $idx = i;
- $dir = rotate_children ? (planar?[1,0]:[1,0,0]) : cutlist[i][2];
- $normal = rotate_children? (planar?[0,1]:[0,0,1]) : cutlist[i][3];
- translate($pos) {
- if (rotate_children) {
- if(planar) {
- rot(from=[0,1],to=cutlist[i][3]) children();
- } else {
- multmatrix(affine2d_to_3d(transpose([cutlist[i][2],cross(cutlist[i][3],cutlist[i][2]), cutlist[i][3]])))
- children();
- }
- } else {
- children();
- }
- }
- }
+ length = path_length(path,closed);
+ distances = is_def(sp)? (
+ is_def(n) && is_def(spacing)? list_range(s=sp, step=spacing, n=n) :
+ is_def(n)? list_range(s=sp, e=length, n=n) :
+ list_range(s=sp, step=spacing, e=length)
+ ) : is_def(n) && is_undef(spacing)? (
+ closed?
+ let(range=list_range(s=0,e=length, n=n+1)) slice(range,0,-2) :
+ list_range(s=0, e=length, n=n)
+ ) : (
+ let(
+ n = is_def(n)? n : floor(length/spacing)+(closed?0:1),
+ ptlist = list_range(s=0,step=spacing,n=n),
+ listcenter = mean(ptlist)
+ ) closed?
+ sort([for(entry=ptlist) posmod(entry-listcenter,length)]) :
+ [for(entry=ptlist) entry + length/2-listcenter ]
+ );
+ distOK = min(distances)>=0 && max(distances)<=length;
+ assert(distOK,"Cannot fit all of the copies");
+ cutlist = path_cut(path, distances, closed, direction=true);
+ planar = len(path[0])==2;
+ if (true) for(i=[0:1:len(cutlist)-1]) {
+ $pos = cutlist[i][0];
+ $idx = i;
+ $dir = rotate_children ? (planar?[1,0]:[1,0,0]) : cutlist[i][2];
+ $normal = rotate_children? (planar?[0,1]:[0,0,1]) : cutlist[i][3];
+ translate($pos) {
+ if (rotate_children) {
+ if(planar) {
+ rot(from=[0,1],to=cutlist[i][3]) children();
+ } else {
+ multmatrix(affine2d_to_3d(transpose([cutlist[i][2],cross(cutlist[i][3],cutlist[i][2]), cutlist[i][3]])))
+ children();
+ }
+ } else {
+ children();
+ }
+ }
+ }
}
@@ -1040,76 +1040,76 @@ module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=fals
// path_cut(square, [0,0.8,1.6,2.4,3.2], closed=true); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], [[0, 0.8], 4]]
// path_cut(square, [0,0.8,1.6,2.4,3.2]); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], undef]
function path_cut(path, dists, closed=false, direction=false) =
- let(long_enough = len(path) >= (closed ? 3 : 2))
- assert(long_enough,len(path)<2 ? "Two points needed to define a path" : "Closed path must include three points")
- !is_list(dists)? path_cut(path, [dists],closed, direction)[0] :
- let(cuts = _path_cut(path,dists,closed))
- !direction ? cuts : let(
- dir = _path_cuts_dir(path, cuts, closed),
- normals = _path_cuts_normals(path, cuts, dir, closed)
- ) zip(cuts, array_group(dir,1), array_group(normals,1));
+ let(long_enough = len(path) >= (closed ? 3 : 2))
+ assert(long_enough,len(path)<2 ? "Two points needed to define a path" : "Closed path must include three points")
+ !is_list(dists)? path_cut(path, [dists],closed, direction)[0] :
+ let(cuts = _path_cut(path,dists,closed))
+ !direction ? cuts : let(
+ dir = _path_cuts_dir(path, cuts, closed),
+ normals = _path_cuts_normals(path, cuts, dir, closed)
+ ) zip(cuts, array_group(dir,1), array_group(normals,1));
// Main recursive path cut function
function _path_cut(path, dists, closed=false, pind=0, dtotal=0, dind=0, result=[]) =
- dind == len(dists) ? result :
- let(
- lastpt = len(result)>0? select(result,-1)[0] : [],
- dpartial = len(result)==0? 0 : norm(lastpt-path[pind]),
- nextpoint = dpartial > dists[dind]-dtotal?
- [lerp(lastpt,path[pind], (dists[dind]-dtotal)/dpartial),pind] :
- _path_cut_single(path, dists[dind]-dtotal-dpartial, closed, pind)
- ) is_undef(nextpoint)?
- concat(result, repeat(undef,len(dists)-dind)) :
- _path_cut(path, dists, closed, nextpoint[1], dists[dind],dind+1, concat(result, [nextpoint]));
+ dind == len(dists) ? result :
+ let(
+ lastpt = len(result)>0? select(result,-1)[0] : [],
+ dpartial = len(result)==0? 0 : norm(lastpt-path[pind]),
+ nextpoint = dpartial > dists[dind]-dtotal?
+ [lerp(lastpt,path[pind], (dists[dind]-dtotal)/dpartial),pind] :
+ _path_cut_single(path, dists[dind]-dtotal-dpartial, closed, pind)
+ ) is_undef(nextpoint)?
+ concat(result, repeat(undef,len(dists)-dind)) :
+ _path_cut(path, dists, closed, nextpoint[1], dists[dind],dind+1, concat(result, [nextpoint]));
// Search for a single cut point in the path
function _path_cut_single(path, dist, closed=false, ind=0, eps=1e-7) =
- ind>=len(path)? undef :
- ind==len(path)-1 && !closed? (dist dist ?
- [lerp(path[ind],select(path,ind+1),dist/d), ind+1] :
- _path_cut_single(path, dist-d,closed, ind+1, eps);
+ ind>=len(path)? undef :
+ ind==len(path)-1 && !closed? (dist dist ?
+ [lerp(path[ind],select(path,ind+1),dist/d), ind+1] :
+ _path_cut_single(path, dist-d,closed, ind+1, eps);
// Find normal directions to the path, coplanar to local part of the path
// Or return a vector parallel to the x-y plane if the above fails
function _path_cuts_normals(path, cuts, dirs, closed=false) =
- [for(i=[0:len(cuts)-1])
- len(path[0])==2? [-dirs[i].y, dirs[i].x] : (
- let(
- plane = len(path)<3 ? undef :
- let(start = max(min(cuts[i][1],len(path)-1),2)) _path_plane(path, start, start-2)
- )
- plane==undef?
- unit([-dirs[i].y, dirs[i].x,0]) :
- unit(cross(dirs[i],cross(plane[0],plane[1])))
- )
- ];
+ [for(i=[0:len(cuts)-1])
+ len(path[0])==2? [-dirs[i].y, dirs[i].x] : (
+ let(
+ plane = len(path)<3 ? undef :
+ let(start = max(min(cuts[i][1],len(path)-1),2)) _path_plane(path, start, start-2)
+ )
+ plane==undef?
+ unit([-dirs[i].y, dirs[i].x,0]) :
+ unit(cross(dirs[i],cross(plane[0],plane[1])))
+ )
+ ];
// Scan from the specified point (ind) to find a noncoplanar triple to use
// to define the plane of the path.
function _path_plane(path, ind, i,closed) =
- i<(closed?-1:0) ? undef :
- !collinear(path[ind],path[ind-1], select(path,i))?
- [select(path,i)-path[ind-1],path[ind]-path[ind-1]] :
- _path_plane(path, ind, i-1);
+ i<(closed?-1:0) ? undef :
+ !collinear(path[ind],path[ind-1], select(path,i))?
+ [select(path,i)-path[ind-1],path[ind]-path[ind-1]] :
+ _path_plane(path, ind, i-1);
// Find the direction of the path at the cut points
function _path_cuts_dir(path, cuts, closed=false, eps=1e-2) =
- [for(ind=[0:len(cuts)-1])
- let(
- nextind = cuts[ind][1],
- nextpath = unit(select(path, nextind+1)-select(path, nextind)),
- thispath = unit(select(path, nextind) - path[nextind-1]),
- lastpath = unit(path[nextind-1] - select(path, nextind-2)),
- nextdir =
- nextind==len(path) && !closed? lastpath :
- (nextind<=len(path)-2 || closed) && approx(cuts[ind][0], path[nextind],eps)?
- unit(nextpath+thispath) :
- (nextind>1 || closed) && approx(cuts[ind][0],path[nextind-1],eps)?
- unit(thispath+lastpath) :
- thispath
- ) nextdir
- ];
+ [for(ind=[0:len(cuts)-1])
+ let(
+ nextind = cuts[ind][1],
+ nextpath = unit(select(path, nextind+1)-select(path, nextind)),
+ thispath = unit(select(path, nextind) - path[nextind-1]),
+ lastpath = unit(path[nextind-1] - select(path, nextind-2)),
+ nextdir =
+ nextind==len(path) && !closed? lastpath :
+ (nextind<=len(path)-2 || closed) && approx(cuts[ind][0], path[nextind],eps)?
+ unit(nextpath+thispath) :
+ (nextind>1 || closed) && approx(cuts[ind][0],path[nextind-1],eps)?
+ unit(thispath+lastpath) :
+ thispath
+ ) nextdir
+ ];
// Input `data` is a list that sums to an integer.
// Returns rounded version of input data so that every
@@ -1118,14 +1118,14 @@ function _path_cuts_dir(path, cuts, closed=false, eps=1e-2) =
// and passing the rounding error forward to the next entry.
// This will generally distribute the error in a uniform manner.
function _sum_preserving_round(data, index=0) =
- index == len(data)-1 ? list_set(data, len(data)-1, round(data[len(data)-1])) :
- let(
- newval = round(data[index]),
- error = newval - data[index]
- ) _sum_preserving_round(
- list_set(data, [index,index+1], [newval, data[index+1]-error]),
- index+1
- );
+ index == len(data)-1 ? list_set(data, len(data)-1, round(data[len(data)-1])) :
+ let(
+ newval = round(data[index]),
+ error = newval - data[index]
+ ) _sum_preserving_round(
+ list_set(data, [index,index+1], [newval, data[index+1]-error]),
+ index+1
+ );
// Function: subdivide_path()
@@ -1184,37 +1184,37 @@ function _sum_preserving_round(data, index=0) =
// mypath = subdivide_path([[0,0,0],[2,0,1],[2,3,2]], 12);
// move_copies(mypath)sphere(r=.1,$fn=32);
function subdivide_path(path, N, closed=true, exact=true, method="length") =
- assert(is_path(path))
- assert(method=="length" || method=="segment")
- assert((is_num(N) && N>0) || is_vector(N),"Parameter N to subdivide_path must be postive number or vector")
- let(
- count = len(path) - (closed?0:1),
- add_guess = method=="segment"? (
- is_list(N)? (
- assert(len(N)==count,"Vector parameter N to subdivide_path has the wrong length")
- add_scalar(N,-1)
- ) : repeat((N-len(path)) / count, count)
- ) : // method=="length"
- assert(is_num(N),"Parameter N to subdivide path must be a number when method=\"length\"")
- let(
- path_lens = concat(
- [ for (i = [0:1:len(path)-2]) norm(path[i+1]-path[i]) ],
- closed? [norm(path[len(path)-1]-path[0])] : []
- ),
- add_density = (N - len(path)) / sum(path_lens)
- )
- path_lens * add_density,
- add = exact? _sum_preserving_round(add_guess) :
- [for (val=add_guess) round(val)]
- ) concat(
- [
- for (i=[0:1:count]) each [
- for(j=[0:1:add[i]])
- lerp(path[i],select(path,i+1), j/(add[i]+1))
- ]
- ],
- closed? [] : [select(path,-1)]
- );
+ assert(is_path(path))
+ assert(method=="length" || method=="segment")
+ assert((is_num(N) && N>0) || is_vector(N),"Parameter N to subdivide_path must be postive number or vector")
+ let(
+ count = len(path) - (closed?0:1),
+ add_guess = method=="segment"? (
+ is_list(N)? (
+ assert(len(N)==count,"Vector parameter N to subdivide_path has the wrong length")
+ add_scalar(N,-1)
+ ) : repeat((N-len(path)) / count, count)
+ ) : // method=="length"
+ assert(is_num(N),"Parameter N to subdivide path must be a number when method=\"length\"")
+ let(
+ path_lens = concat(
+ [ for (i = [0:1:len(path)-2]) norm(path[i+1]-path[i]) ],
+ closed? [norm(path[len(path)-1]-path[0])] : []
+ ),
+ add_density = (N - len(path)) / sum(path_lens)
+ )
+ path_lens * add_density,
+ add = exact? _sum_preserving_round(add_guess) :
+ [for (val=add_guess) round(val)]
+ ) concat(
+ [
+ for (i=[0:1:count]) each [
+ for(j=[0:1:add[i]])
+ lerp(path[i],select(path,i+1), j/(add[i]+1))
+ ]
+ ],
+ closed? [] : [select(path,-1)]
+ );
// Function: path_length_fractions()
@@ -1225,17 +1225,17 @@ function subdivide_path(path, N, closed=true, exact=true, method="length") =
// will have one extra point because of the final connecting segment that connects the last
// point of the path to the first point.
function path_length_fractions(path, closed=false) =
- assert(is_path(path))
- assert(is_bool(closed))
- let(
- lengths = [
- 0,
- for (i=[0:1:len(path)-(closed?1:2)])
- norm(select(path,i+1)-path[i])
- ],
- partial_len = cumsum(lengths),
- total_len = select(partial_len,-1)
- ) partial_len / total_len;
+ assert(is_path(path))
+ assert(is_bool(closed))
+ let(
+ lengths = [
+ 0,
+ for (i=[0:1:len(path)-(closed?1:2)])
+ norm(select(path,i+1)-path[i])
+ ],
+ partial_len = cumsum(lengths),
+ total_len = select(partial_len,-1)
+ ) partial_len / total_len;
// Function: resample_path()
@@ -1258,14 +1258,14 @@ function resample_path(path, N, spacing, closed=false) =
assert(num_defined([N,spacing])==1,"Must define exactly one of N and spacing")
assert(is_bool(closed))
let(
- length = path_length(path,closed),
- N = is_def(N) ? N : round(length/spacing) + (closed?0:1),
+ length = path_length(path,closed),
+ N = is_def(N) ? N : round(length/spacing) + (closed?0:1),
spacing = length/(closed?N:N-1), // Note: worried about round-off error, so don't include
distlist = list_range(closed?N:N-1,step=spacing), // last point when closed=false
- cuts = path_cut(path, distlist, closed=closed)
+ cuts = path_cut(path, distlist, closed=closed)
)
concat(subindex(cuts,0),closed?[]:[select(path,-1)]); // Then add last point here
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/phillips_drive.scad b/phillips_drive.scad
index 2a169b1..3288722 100644
--- a/phillips_drive.scad
+++ b/phillips_drive.scad
@@ -28,52 +28,52 @@
// phillips_drive(size="#3", shaft=6, l=20);
// }
module phillips_drive(size="#2", shaft=6, l=20, $fn=36, anchor=BOTTOM, spin=0, orient=UP) {
- assert(is_string(size));
- assert(in_list(size,["#0","#1","#2","#3","#4"]));
+ assert(is_string(size));
+ assert(in_list(size,["#0","#1","#2","#3","#4"]));
- num = ord(size[1]) - ord("0");
- b = [0.61, 0.97, 1.47, 2.41, 3.48][num];
- e = [0.31, 0.43, 0.81, 2.00, 2.41][num];
- g = [0.81, 1.27, 2.29, 3.81, 5.08][num];
- //f = [0.33, 0.53, 0.70, 0.82, 1.23][num];
- //r = [0.30, 0.50, 0.60, 0.80, 1.00][num];
- alpha = [ 136, 138, 140, 146, 153][num];
- beta = [7.00, 7.00, 5.75, 5.75, 7.00][num];
- gamma = 92.0;
- ang1 = 28.0;
- ang2 = 26.5;
- h1 = adj_ang_to_opp(g/2, ang1);
- h2 = adj_ang_to_opp((shaft-g)/2, 90-ang2);
- h3 = adj_ang_to_opp(b/2, ang1);
- p0 = [0,0];
- p1 = [e/2, adj_ang_to_opp(e/2, 90-alpha/2)];
- p2 = p1 + [(shaft-e)/2, adj_ang_to_hyp((shaft-e)/2, 90-gamma/2)];
- attachable(anchor,spin,orient, d=shaft, l=l) {
- down(l/2) {
- difference() {
- union() {
- cyl(d1=0, d2=g, h=h1, anchor=BOT);
- up(h1) {
- cyl(d1=g, d2=shaft, h=h2, anchor=BOT);
- up(h2) cyl(d=shaft, h=l-h1-h2, anchor=BOT);
- }
- }
- zrot(45)
- zrot_copies(n=4, r=b/2/cos(90-alpha/2), sa=90) {
- up(h3) {
- xrot(-beta) {
- linear_extrude(height=(h1+h2)*20, convexity=4, center=true) {
- path = [p0, p1, p2, [-p2.x,p2.y], [-p1.x,p1.y]];
- polygon(path);
- }
- }
- }
- }
- }
- }
- children();
- }
+ num = ord(size[1]) - ord("0");
+ b = [0.61, 0.97, 1.47, 2.41, 3.48][num];
+ e = [0.31, 0.43, 0.81, 2.00, 2.41][num];
+ g = [0.81, 1.27, 2.29, 3.81, 5.08][num];
+ //f = [0.33, 0.53, 0.70, 0.82, 1.23][num];
+ //r = [0.30, 0.50, 0.60, 0.80, 1.00][num];
+ alpha = [ 136, 138, 140, 146, 153][num];
+ beta = [7.00, 7.00, 5.75, 5.75, 7.00][num];
+ gamma = 92.0;
+ ang1 = 28.0;
+ ang2 = 26.5;
+ h1 = adj_ang_to_opp(g/2, ang1);
+ h2 = adj_ang_to_opp((shaft-g)/2, 90-ang2);
+ h3 = adj_ang_to_opp(b/2, ang1);
+ p0 = [0,0];
+ p1 = [e/2, adj_ang_to_opp(e/2, 90-alpha/2)];
+ p2 = p1 + [(shaft-e)/2, adj_ang_to_hyp((shaft-e)/2, 90-gamma/2)];
+ attachable(anchor,spin,orient, d=shaft, l=l) {
+ down(l/2) {
+ difference() {
+ union() {
+ cyl(d1=0, d2=g, h=h1, anchor=BOT);
+ up(h1) {
+ cyl(d1=g, d2=shaft, h=h2, anchor=BOT);
+ up(h2) cyl(d=shaft, h=l-h1-h2, anchor=BOT);
+ }
+ }
+ zrot(45)
+ zrot_copies(n=4, r=b/2/cos(90-alpha/2), sa=90) {
+ up(h3) {
+ xrot(-beta) {
+ linear_extrude(height=(h1+h2)*20, convexity=4, center=true) {
+ path = [p0, p1, p2, [-p2.x,p2.y], [-p1.x,p1.y]];
+ polygon(path);
+ }
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/polyhedra.scad b/polyhedra.scad
index 1d67564..3902ecf 100644
--- a/polyhedra.scad
+++ b/polyhedra.scad
@@ -22,9 +22,9 @@ include
// Groups entries in "arr" into groups of equal values and returns index lists of those groups
function _unique_groups(m) = [
- for (i=[0:1:len(m)-1]) let(
- s = search([m[i]], m, 0)[0]
- ) if (s[0]==i) s
+ for (i=[0:1:len(m)-1]) let(
+ s = search([m[i]], m, 0)[0]
+ ) if (s[0]==i) s
];
@@ -277,82 +277,82 @@ function _unique_groups(m) = [
// regular_polyhedron("pentagonal hexecontahedron", or=1,facedown=false);
// }
module regular_polyhedron(
- name=undef,
- index=undef,
- type=undef,
- faces=undef,
- facetype=undef,
- hasfaces=undef,
- side=1,
- ir=undef,
- mr=undef,
- or=undef,
- r=undef,
- d=undef,
- anchor=[0,0,0],
- center=undef,
- rounding=0,
- repeat=true,
- facedown=true,
- draw=true,
- rotate_children=true,
- stellate = false,
- longside=undef, // special parameter for trapezohedron
- h=undef // special parameter for trapezohedron
+ name=undef,
+ index=undef,
+ type=undef,
+ faces=undef,
+ facetype=undef,
+ hasfaces=undef,
+ side=1,
+ ir=undef,
+ mr=undef,
+ or=undef,
+ r=undef,
+ d=undef,
+ anchor=[0,0,0],
+ center=undef,
+ rounding=0,
+ repeat=true,
+ facedown=true,
+ draw=true,
+ rotate_children=true,
+ stellate = false,
+ longside=undef, // special parameter for trapezohedron
+ h=undef // special parameter for trapezohedron
) {
- assert(rounding>=0, "'rounding' must be nonnegative");
- entry = regular_polyhedron_info(
- "fullentry", name=name, index=index,
- type=type, faces=faces, facetype=facetype,
- hasfaces=hasfaces, side=side,
- ir=ir, mr=mr, or=or,
- r=r, d=d,
- anchor=anchor, center=center,
- facedown=facedown,
- stellate=stellate,
- longside=longside, h=h
- );
- scaled_points = entry[0];
- translation = entry[1];
- face_triangles = entry[2];
- faces = entry[3];
- face_normals = entry[4];
- in_radius = entry[5];
- if (draw){
- if (rounding==0)
- polyhedron(move(translation, p=scaled_points), faces = face_triangles);
- else {
- fn = segs(rounding);
- rounding = rounding/cos(180/fn);
- adjusted_scale = 1 - rounding / in_radius;
- minkowski(){
- sphere(r=rounding, $fn=fn);
- polyhedron(move(translation,p=adjusted_scale*scaled_points), faces = face_triangles);
- }
- }
- }
- if ($children>0) {
- maxrange = repeat ? len(faces)-1 : $children-1;
- for(i=[0:1:maxrange]) {
- // Would like to orient so an edge (longest edge?) is parallel to x axis
- facepts = move(translation, p=select(scaled_points, faces[i]));
- center = mean(facepts);
- rotatedface = rot(from=face_normals[i], to=[0,0,1], p=move(-center, p=facepts));
- clockwise = sortidx([for(pt=rotatedface) -atan2(pt.y,pt.x)]);
- $face = rotate_children?
- path2d(select(rotatedface,clockwise)) :
- select(move(-center,p=facepts), clockwise);
- $faceindex = i;
- $center = -translation-center;
- translate(center)
- if (rotate_children) {
- rot(from=[0,0,1], to=face_normals[i])
- children(i % $children);
- } else {
- children(i % $children);
- }
- }
- }
+ assert(rounding>=0, "'rounding' must be nonnegative");
+ entry = regular_polyhedron_info(
+ "fullentry", name=name, index=index,
+ type=type, faces=faces, facetype=facetype,
+ hasfaces=hasfaces, side=side,
+ ir=ir, mr=mr, or=or,
+ r=r, d=d,
+ anchor=anchor, center=center,
+ facedown=facedown,
+ stellate=stellate,
+ longside=longside, h=h
+ );
+ scaled_points = entry[0];
+ translation = entry[1];
+ face_triangles = entry[2];
+ faces = entry[3];
+ face_normals = entry[4];
+ in_radius = entry[5];
+ if (draw){
+ if (rounding==0)
+ polyhedron(move(translation, p=scaled_points), faces = face_triangles);
+ else {
+ fn = segs(rounding);
+ rounding = rounding/cos(180/fn);
+ adjusted_scale = 1 - rounding / in_radius;
+ minkowski(){
+ sphere(r=rounding, $fn=fn);
+ polyhedron(move(translation,p=adjusted_scale*scaled_points), faces = face_triangles);
+ }
+ }
+ }
+ if ($children>0) {
+ maxrange = repeat ? len(faces)-1 : $children-1;
+ for(i=[0:1:maxrange]) {
+ // Would like to orient so an edge (longest edge?) is parallel to x axis
+ facepts = move(translation, p=select(scaled_points, faces[i]));
+ center = mean(facepts);
+ rotatedface = rot(from=face_normals[i], to=[0,0,1], p=move(-center, p=facepts));
+ clockwise = sortidx([for(pt=rotatedface) -atan2(pt.y,pt.x)]);
+ $face = rotate_children?
+ path2d(select(rotatedface,clockwise)) :
+ select(move(-center,p=facepts), clockwise);
+ $faceindex = i;
+ $center = -translation-center;
+ translate(center)
+ if (rotate_children) {
+ rot(from=[0,0,1], to=face_normals[i])
+ children(i % $children);
+ } else {
+ children(i % $children);
+ }
+ }
+ }
}
/////////////////////////////////////////////////////////////////////////////
@@ -364,17 +364,17 @@ module regular_polyhedron(
function _even_perms(v) = [v, [v[2], v[0], v[1]], [v[1],v[2],v[0]]];
function _all_perms(v) = [v, [v[2], v[0], v[1]], [v[1],v[2],v[0]], [v[1],v[0],v[2]],[v[2],v[1],v[0]],[v[0],v[2],v[1]]];
//
-// Point reflections across all planes. In the unconstrained case, this means one point becomes 8 points.
+// Point reflections across all planes. In the unconstrained case, this means one point becomes 8 points.
//
// sign=="even" means an even number of minus signs (odd number of plus signs)
// sign=="odd" means an odd number of minus signs (even number of plus signs)
//
function _point_ref(points, sign="both") =
- unique([
- for(i=[-1,1],j=[-1,1],k=[-1,1])
- if (sign=="both" || sign=="even" && i*j*k>0 || sign=="odd" && i*j*k<0)
- each [for(point=points) vmul(point,[i,j,k])]
- ]);
+ unique([
+ for(i=[-1,1],j=[-1,1],k=[-1,1])
+ if (sign=="both" || sign=="even" && i*j*k>0 || sign=="odd" && i*j*k<0)
+ each [for(point=points) vmul(point,[i,j,k])]
+ ]);
//
_tribonacci=(1+4*cosh(acosh(2+3/8)/3))/3;
//
@@ -384,160 +384,160 @@ _tribonacci=(1+4*cosh(acosh(2+3/8)/3))/3;
// The polyhedra information is from Wikipedia and http://dmccooey.com/polyhedra/
//
_polyhedra_ = [
- // Platonic Solids
+ // Platonic Solids
- ["tetrahedron", "platonic", 4,[3], 2*sqrt(2), sqrt(6)/12, sqrt(2)/4, sqrt(6)/4, 1/6/sqrt(2),
- _point_ref([[1,1,1]], sign="even")],
- ["cube", "platonic", 6, [4], 2, 1/2, 1/sqrt(2), sqrt(3)/2, 1,
- _point_ref([[1,1,1]])],
- ["octahedron", "platonic", 8, [3], sqrt(2), sqrt(6)/6, 1/2, sqrt(2)/2, sqrt(2)/3,
- _point_ref(_even_perms([1,0,0]))],
- ["dodecahedron", "platonic", 12, [5], 2/PHI, sqrt(5/2+11*sqrt(5)/10)/2, (3+sqrt(5))/4, sqrt(3)*PHI/2, (15+7*sqrt(5))/4,
- _point_ref(concat([[1,1,1]],_even_perms([0,PHI,1/PHI])))],
- ["icosahedron", "platonic", 20, [3], 2, PHI*PHI/2/sqrt(3), cos(36), sin(72), 5*(3+sqrt(5))/12,
- _point_ref(_even_perms([0,1,PHI]))],
+ ["tetrahedron", "platonic", 4,[3], 2*sqrt(2), sqrt(6)/12, sqrt(2)/4, sqrt(6)/4, 1/6/sqrt(2),
+ _point_ref([[1,1,1]], sign="even")],
+ ["cube", "platonic", 6, [4], 2, 1/2, 1/sqrt(2), sqrt(3)/2, 1,
+ _point_ref([[1,1,1]])],
+ ["octahedron", "platonic", 8, [3], sqrt(2), sqrt(6)/6, 1/2, sqrt(2)/2, sqrt(2)/3,
+ _point_ref(_even_perms([1,0,0]))],
+ ["dodecahedron", "platonic", 12, [5], 2/PHI, sqrt(5/2+11*sqrt(5)/10)/2, (3+sqrt(5))/4, sqrt(3)*PHI/2, (15+7*sqrt(5))/4,
+ _point_ref(concat([[1,1,1]],_even_perms([0,PHI,1/PHI])))],
+ ["icosahedron", "platonic", 20, [3], 2, PHI*PHI/2/sqrt(3), cos(36), sin(72), 5*(3+sqrt(5))/12,
+ _point_ref(_even_perms([0,1,PHI]))],
- // Archimedian Solids, listed in order by Wenniger number, W6-W18
+ // Archimedian Solids, listed in order by Wenniger number, W6-W18
- ["truncated tetrahedron", "archimedean", 8,[6,3], sqrt(8), sqrt(6)/4, 3*sqrt(2)/4, sqrt(11/8), 23*sqrt(2)/12,
- _point_ref(_all_perms([1,1,3]),sign="even")],
- ["truncated octahedron", "archimedean", 14, [6,4], sqrt(2), sqrt(6)/2, 1.5, sqrt(10)/2, 8*sqrt(2),
- _point_ref(_all_perms([0,1,2]))],
- ["truncated cube", "archimedean", 14, [8,3], 2*(sqrt(2)-1), (1+sqrt(2))/2, 1+sqrt(2)/2, sqrt(7+4*sqrt(2))/2, 7+14*sqrt(2)/3,
- _point_ref(_all_perms([1,1,sqrt(2)-1]))],
- ["truncated icosahedron", "archimedean", 32, [6, 5], 2, (3*sqrt(3)+sqrt(15))/4, 3*PHI/2, sqrt(58+18*sqrt(5))/4, (125+43*sqrt(5))/4,
- _point_ref(concat(
- _even_perms([0,1,3*PHI]),
- _even_perms([1,2+PHI,2*PHI]),
- _even_perms([PHI,2,PHI*PHI*PHI])
- ))],
- ["truncated dodecahedron", "archimedean", 32, [10, 3], 2*PHI-2, sqrt(7+11*PHI)/2, (3*PHI+1)/2,sqrt(11+PHI*15)/2, 5*(99+47*sqrt(5))/12,
- _point_ref(concat(
- _even_perms([0,1/PHI, 2+PHI]),
- _even_perms([1/PHI,PHI,2*PHI]),
- _even_perms([PHI,2,PHI+1])
- ))],
- ["cuboctahedron", "archimedean", 14, [4,3], sqrt(2), sqrt(2)/2, sqrt(3)/2, 1, 5*sqrt(2)/3,
- _point_ref(_all_perms([1,1,0]))],
- ["icosidodecahedron", "archimedean", 32, [5,3], 1, sqrt(5*(5+2*sqrt(5)))/5,sqrt(5+2*sqrt(5))/2, PHI, (14+17*PHI)/3,
- _point_ref(concat(_even_perms([0,0,PHI]),_even_perms([1/2,PHI/2,PHI*PHI/2])))],
- ["rhombicuboctahedron", "archimedean", 26, [4, 3], 2, (1+sqrt(2))/2, sqrt(2*(2+sqrt(2)))/2, sqrt(5+2*sqrt(2))/2, 4+10*sqrt(2)/3,
- _point_ref(_even_perms([1,1,1+sqrt(2)]))],
- ["rhombicosidodecahedron", "archimedean", 62, [5,4,3], 2, 3/10*sqrt(15+20*PHI), sqrt(3/2+2*PHI), sqrt(8*PHI+7)/2, (31+58*PHI)/3,
- _point_ref(concat(
- _even_perms([1,1,PHI*PHI*PHI]),
- _even_perms([PHI*PHI,PHI,2*PHI]),
- _even_perms([2+PHI,0,PHI*PHI])
- ))],
- ["truncated cuboctahedron", "archimedean", 26, [8, 6, 4], 2, (1+2*sqrt(2))/2, sqrt(6*(2+sqrt(2)))/2, sqrt(13+6*sqrt(2))/2, (22+14*sqrt(2)),
- _point_ref(_all_perms([1,1+sqrt(2), 1+2*sqrt(2)]))],
- ["truncated icosidodecahedron", "archimedean", 62, [10,6,4], 2*PHI - 2, sqrt(15/4+5*PHI),sqrt(9/2+6*PHI),sqrt(19/4+6*PHI), 95+50*sqrt(5),
- _point_ref(concat(
- _even_perms([1/PHI,1/PHI,3+PHI]),
- _even_perms([2/PHI,PHI,1+2*PHI]),
- _even_perms([1/PHI,PHI*PHI,3*PHI-1]),
- _even_perms([2*PHI-1,2,2+PHI]),
- _even_perms([PHI,3,2*PHI])
- ))],
- ["snub cube", "archimedean", 38, [4,3], 1.60972,1.14261350892596209,1.24722316799364325, 1.34371337374460170,
- sqrt((613*_tribonacci+203)/(9*(35*_tribonacci-62))),
- concat(
- _point_ref(_even_perms([1,1/_tribonacci,_tribonacci]), sign="odd"),
- _point_ref(_even_perms([1,_tribonacci,1/_tribonacci]), sign="even")
- )],
- ["snub dodecahedron", "archimedean", 92, [5, 3], 1, 1.98091594728184,2.097053835252087,2.155837375115, 37.61664996273336,
- concat(
- _point_ref(_even_perms([0.374821658114562,0.330921024729844,2.097053835252088]), sign="odd"),
- _point_ref(_even_perms([0.192893711352359,1.249503788463027,1.746186440985827]), sign="odd"),
- _point_ref(_even_perms([1.103156835071754,0.847550046789061,1.646917940690374]), sign="odd"),
- _point_ref(_even_perms([0.567715369466922,0.643029605914072,1.977838965420219]), sign="even"),
- _point_ref(_even_perms([1.415265416255982,0.728335176957192,1.454024229338015]), sign="even")
- )],
+ ["truncated tetrahedron", "archimedean", 8,[6,3], sqrt(8), sqrt(6)/4, 3*sqrt(2)/4, sqrt(11/8), 23*sqrt(2)/12,
+ _point_ref(_all_perms([1,1,3]),sign="even")],
+ ["truncated octahedron", "archimedean", 14, [6,4], sqrt(2), sqrt(6)/2, 1.5, sqrt(10)/2, 8*sqrt(2),
+ _point_ref(_all_perms([0,1,2]))],
+ ["truncated cube", "archimedean", 14, [8,3], 2*(sqrt(2)-1), (1+sqrt(2))/2, 1+sqrt(2)/2, sqrt(7+4*sqrt(2))/2, 7+14*sqrt(2)/3,
+ _point_ref(_all_perms([1,1,sqrt(2)-1]))],
+ ["truncated icosahedron", "archimedean", 32, [6, 5], 2, (3*sqrt(3)+sqrt(15))/4, 3*PHI/2, sqrt(58+18*sqrt(5))/4, (125+43*sqrt(5))/4,
+ _point_ref(concat(
+ _even_perms([0,1,3*PHI]),
+ _even_perms([1,2+PHI,2*PHI]),
+ _even_perms([PHI,2,PHI*PHI*PHI])
+ ))],
+ ["truncated dodecahedron", "archimedean", 32, [10, 3], 2*PHI-2, sqrt(7+11*PHI)/2, (3*PHI+1)/2,sqrt(11+PHI*15)/2, 5*(99+47*sqrt(5))/12,
+ _point_ref(concat(
+ _even_perms([0,1/PHI, 2+PHI]),
+ _even_perms([1/PHI,PHI,2*PHI]),
+ _even_perms([PHI,2,PHI+1])
+ ))],
+ ["cuboctahedron", "archimedean", 14, [4,3], sqrt(2), sqrt(2)/2, sqrt(3)/2, 1, 5*sqrt(2)/3,
+ _point_ref(_all_perms([1,1,0]))],
+ ["icosidodecahedron", "archimedean", 32, [5,3], 1, sqrt(5*(5+2*sqrt(5)))/5,sqrt(5+2*sqrt(5))/2, PHI, (14+17*PHI)/3,
+ _point_ref(concat(_even_perms([0,0,PHI]),_even_perms([1/2,PHI/2,PHI*PHI/2])))],
+ ["rhombicuboctahedron", "archimedean", 26, [4, 3], 2, (1+sqrt(2))/2, sqrt(2*(2+sqrt(2)))/2, sqrt(5+2*sqrt(2))/2, 4+10*sqrt(2)/3,
+ _point_ref(_even_perms([1,1,1+sqrt(2)]))],
+ ["rhombicosidodecahedron", "archimedean", 62, [5,4,3], 2, 3/10*sqrt(15+20*PHI), sqrt(3/2+2*PHI), sqrt(8*PHI+7)/2, (31+58*PHI)/3,
+ _point_ref(concat(
+ _even_perms([1,1,PHI*PHI*PHI]),
+ _even_perms([PHI*PHI,PHI,2*PHI]),
+ _even_perms([2+PHI,0,PHI*PHI])
+ ))],
+ ["truncated cuboctahedron", "archimedean", 26, [8, 6, 4], 2, (1+2*sqrt(2))/2, sqrt(6*(2+sqrt(2)))/2, sqrt(13+6*sqrt(2))/2, (22+14*sqrt(2)),
+ _point_ref(_all_perms([1,1+sqrt(2), 1+2*sqrt(2)]))],
+ ["truncated icosidodecahedron", "archimedean", 62, [10,6,4], 2*PHI - 2, sqrt(15/4+5*PHI),sqrt(9/2+6*PHI),sqrt(19/4+6*PHI), 95+50*sqrt(5),
+ _point_ref(concat(
+ _even_perms([1/PHI,1/PHI,3+PHI]),
+ _even_perms([2/PHI,PHI,1+2*PHI]),
+ _even_perms([1/PHI,PHI*PHI,3*PHI-1]),
+ _even_perms([2*PHI-1,2,2+PHI]),
+ _even_perms([PHI,3,2*PHI])
+ ))],
+ ["snub cube", "archimedean", 38, [4,3], 1.60972,1.14261350892596209,1.24722316799364325, 1.34371337374460170,
+ sqrt((613*_tribonacci+203)/(9*(35*_tribonacci-62))),
+ concat(
+ _point_ref(_even_perms([1,1/_tribonacci,_tribonacci]), sign="odd"),
+ _point_ref(_even_perms([1,_tribonacci,1/_tribonacci]), sign="even")
+ )],
+ ["snub dodecahedron", "archimedean", 92, [5, 3], 1, 1.98091594728184,2.097053835252087,2.155837375115, 37.61664996273336,
+ concat(
+ _point_ref(_even_perms([0.374821658114562,0.330921024729844,2.097053835252088]), sign="odd"),
+ _point_ref(_even_perms([0.192893711352359,1.249503788463027,1.746186440985827]), sign="odd"),
+ _point_ref(_even_perms([1.103156835071754,0.847550046789061,1.646917940690374]), sign="odd"),
+ _point_ref(_even_perms([0.567715369466922,0.643029605914072,1.977838965420219]), sign="even"),
+ _point_ref(_even_perms([1.415265416255982,0.728335176957192,1.454024229338015]), sign="even")
+ )],
- // Catalan Solids, the duals to the Archimedean solids, listed in the corresponding order
+ // Catalan Solids, the duals to the Archimedean solids, listed in the corresponding order
- ["triakis tetrahedron","catalan", 12, [3], 9/5, 5*sqrt(22)/44, 5*sqrt(2)/12, 5*sqrt(6)/12, 25*sqrt(2)/36,
- concat(
- _point_ref([9*sqrt(2)/20*[1,1,1]],sign="even"),
- _point_ref([3*sqrt(2)/4*[1,1,1]],sign="odd")
- )],
- ["tetrakis hexahedron", "catalan", 24, [3], 1, 2/sqrt(5), 2*sqrt(2)/3, 2/sqrt(3), 32/9,
- _point_ref(concat([[2/3,2/3,2/3]],_even_perms([1,0,0])))],
- ["triakis octahedron", "catalan", 24, [3], 2, sqrt(17*(23+16*sqrt(2)))/34, 1/2+sqrt(2)/4,(1+sqrt(2))/2,3/2+sqrt(2),
- _point_ref(concat([[1,1,1]],_even_perms([1+sqrt(2),0,0])))],
- ["pentakis dodecahedron", "catalan", 60, [3], 1,sqrt(477/436+97*sqrt(5)/218), sqrt(5)/4+11/12, sqrt(7/4+sqrt(5)/3), 125*sqrt(5)/36+205/36,
- _point_ref(concat(
- _even_perms([0,(5-PHI)/6, PHI/2+2/3]),
- _even_perms([0,(PHI+1)/2,PHI/2]),[(4*PHI-1)/6 * [1,1,1]]
- ))],
- ["triakis icosahedron", "catalan", 60, [3], 1, sqrt((139+199*PHI)/244), (8*PHI+1)/10, sqrt(13/8+19/8/sqrt(5)), (13*PHI+3)/2,
- _point_ref(concat(
- _even_perms([(PHI+7)/10, 0, (8*PHI+1)/10]),
- _even_perms([0, 1/2, (PHI+1)/2]),[PHI/2*[1,1,1]]
- ))],
- ["rhombic dodecahedron", "catalan", 12, [4], sqrt(3), sqrt(2/3), 2*sqrt(2)/3, 2/sqrt(3), 16*sqrt(3)/9,
- _point_ref(concat([[1,1,1]], _even_perms([2,0,0])))],
- ["rhombic triacontahedron", "catalan", 30,[4], 1, sqrt(1+2/sqrt(5)), 1+1/sqrt(5), (1+sqrt(5))/2, 4*sqrt(5+2*sqrt(5)),
- concat(
- _point_ref(_even_perms([0,sqrt(1+2/sqrt(5)), sqrt((5+sqrt(5))/10)])),
- _point_ref(_even_perms([0,sqrt(2/(5+sqrt(5))), sqrt(1+2/sqrt(5))])),
- _point_ref([sqrt((5+sqrt(5))/10)*[1,1,1]])
- )],
- ["deltoidal icositetrahedron", "catalan", 24, [4], 2*sqrt(10-sqrt(2))/7, 7*sqrt((7+4*sqrt(2))/(34 * (10-sqrt(2)))),
- 7*sqrt(2*(2+sqrt(2)))/sqrt(10-sqrt(2))/4, 7*sqrt(2)/sqrt(10-sqrt(2))/2,
- (14+21*sqrt(2))/sqrt(10-sqrt(2)),
- _point_ref(concat(
- _even_perms([0,1,1]), _even_perms([sqrt(2),0,0]),
- _even_perms((4+sqrt(2))/7*[1,1,1])
- ))],
- ["deltoidal hexecontahedron", "catalan", 60, [4], sqrt(5*(85-31*sqrt(5)))/11, sqrt(571/164+1269/164/sqrt(5)), 5/4+13/4/sqrt(5),
- sqrt(147+65*sqrt(5))/6, sqrt(29530+13204*sqrt(5))/3,
- _point_ref(concat(
- _even_perms([0,0,sqrt(5)]),
- _even_perms([0,(15+sqrt(5))/22, (25+9*sqrt(5))/22]),
- _even_perms([0,(5+3*sqrt(5))/6, (5+sqrt(5))/6]),
- _even_perms([(5-sqrt(5))/4, sqrt(5)/2, (5+sqrt(5))/4]),
- [(5+4*sqrt(5))/11*[1,1,1]]
- ))],
- ["disdyakis dodecahedron", "catalan", 48, [3], 1,sqrt(249/194+285/194/sqrt(2)) ,(2+3*sqrt(2))/4, sqrt(183/98+213/98/sqrt(2)),
- sqrt(6582+4539*sqrt(2))/7,
- _point_ref(concat(
- _even_perms([sqrt(183/98+213/98/sqrt(2)),0,0]),
- _even_perms(sqrt(3+3/sqrt(2))/2 * [1,1,0]),[7/sqrt(6*(10-sqrt(2)))*[1,1,1]]
- ))],
- ["disdyakis triacontahedron","catalan", 120, [3], sqrt(15*(85-31*sqrt(5)))/11, sqrt(3477/964+7707/964/sqrt(5)), 5/4+13/4/sqrt(5),
- sqrt(441+195*sqrt(5))/10,sqrt(17718/5+39612/5/sqrt(5)),
- _point_ref(concat(
- _even_perms([0,0,3*(5+4*sqrt(5))/11]),
- _even_perms([0,(5-sqrt(5))/2,(5+sqrt(5))/2]),
- _even_perms([0,(15+9*sqrt(5))/10,3*(5+sqrt(5))/10]),
- _even_perms([3*(15+sqrt(5))/44,3*(5+4*sqrt(5))/22, (75+27*sqrt(5))/44]), [sqrt(5)*[1,1,1]]
- ))],
- ["pentagonal icositetrahedron","catalan",24, [5], 0.593465355971, 1.950681331784, 2.1015938932963, 2.29400105368695, 35.6302020120713,
- concat(
- _point_ref(_even_perms([0.21879664300048044,0.740183741369857,1.0236561781126901]),sign="even"),
- _point_ref(_even_perms([0.21879664300048044,1.0236561781126901,0.740183741369857]),sign="odd"),
- _point_ref(_even_perms([1.3614101519264425,0,0])),
- _point_ref([0.7401837413698572*[1,1,1]])
- )],
- ["pentagonal hexecontahedron", "catalan", 60,[5], 0.58289953474498, 3.499527848905764,3.597624822551189,3.80854772878239, 189.789852066885,
- concat(
- _point_ref(_even_perms([0.192893711352359,0.218483370127321,2.097053835252087]), sign="even"),
- _point_ref(_even_perms([0,0.7554672605165955,1.9778389654202186])),
- _point_ref(_even_perms([0,1.888445389283669154,1.1671234364753339])),
- _point_ref(_even_perms([0.56771536946692131,0.824957552676275846,1.8654013108176956657]),sign="odd"),
- _point_ref(_even_perms([0.37482165811456229,1.13706613386050418,1.746186440985826345]), sign="even"),
- _point_ref(_even_perms([0.921228888309550,0.95998770139158,1.6469179406903744]),sign="even"),
- _point_ref(_even_perms([0.7283351769571914773,1.2720962825758121,1.5277030708585051]),sign="odd"),
- _point_ref([1.222371704903623092*[1,1,1]])
- )],
+ ["triakis tetrahedron","catalan", 12, [3], 9/5, 5*sqrt(22)/44, 5*sqrt(2)/12, 5*sqrt(6)/12, 25*sqrt(2)/36,
+ concat(
+ _point_ref([9*sqrt(2)/20*[1,1,1]],sign="even"),
+ _point_ref([3*sqrt(2)/4*[1,1,1]],sign="odd")
+ )],
+ ["tetrakis hexahedron", "catalan", 24, [3], 1, 2/sqrt(5), 2*sqrt(2)/3, 2/sqrt(3), 32/9,
+ _point_ref(concat([[2/3,2/3,2/3]],_even_perms([1,0,0])))],
+ ["triakis octahedron", "catalan", 24, [3], 2, sqrt(17*(23+16*sqrt(2)))/34, 1/2+sqrt(2)/4,(1+sqrt(2))/2,3/2+sqrt(2),
+ _point_ref(concat([[1,1,1]],_even_perms([1+sqrt(2),0,0])))],
+ ["pentakis dodecahedron", "catalan", 60, [3], 1,sqrt(477/436+97*sqrt(5)/218), sqrt(5)/4+11/12, sqrt(7/4+sqrt(5)/3), 125*sqrt(5)/36+205/36,
+ _point_ref(concat(
+ _even_perms([0,(5-PHI)/6, PHI/2+2/3]),
+ _even_perms([0,(PHI+1)/2,PHI/2]),[(4*PHI-1)/6 * [1,1,1]]
+ ))],
+ ["triakis icosahedron", "catalan", 60, [3], 1, sqrt((139+199*PHI)/244), (8*PHI+1)/10, sqrt(13/8+19/8/sqrt(5)), (13*PHI+3)/2,
+ _point_ref(concat(
+ _even_perms([(PHI+7)/10, 0, (8*PHI+1)/10]),
+ _even_perms([0, 1/2, (PHI+1)/2]),[PHI/2*[1,1,1]]
+ ))],
+ ["rhombic dodecahedron", "catalan", 12, [4], sqrt(3), sqrt(2/3), 2*sqrt(2)/3, 2/sqrt(3), 16*sqrt(3)/9,
+ _point_ref(concat([[1,1,1]], _even_perms([2,0,0])))],
+ ["rhombic triacontahedron", "catalan", 30,[4], 1, sqrt(1+2/sqrt(5)), 1+1/sqrt(5), (1+sqrt(5))/2, 4*sqrt(5+2*sqrt(5)),
+ concat(
+ _point_ref(_even_perms([0,sqrt(1+2/sqrt(5)), sqrt((5+sqrt(5))/10)])),
+ _point_ref(_even_perms([0,sqrt(2/(5+sqrt(5))), sqrt(1+2/sqrt(5))])),
+ _point_ref([sqrt((5+sqrt(5))/10)*[1,1,1]])
+ )],
+ ["deltoidal icositetrahedron", "catalan", 24, [4], 2*sqrt(10-sqrt(2))/7, 7*sqrt((7+4*sqrt(2))/(34 * (10-sqrt(2)))),
+ 7*sqrt(2*(2+sqrt(2)))/sqrt(10-sqrt(2))/4, 7*sqrt(2)/sqrt(10-sqrt(2))/2,
+ (14+21*sqrt(2))/sqrt(10-sqrt(2)),
+ _point_ref(concat(
+ _even_perms([0,1,1]), _even_perms([sqrt(2),0,0]),
+ _even_perms((4+sqrt(2))/7*[1,1,1])
+ ))],
+ ["deltoidal hexecontahedron", "catalan", 60, [4], sqrt(5*(85-31*sqrt(5)))/11, sqrt(571/164+1269/164/sqrt(5)), 5/4+13/4/sqrt(5),
+ sqrt(147+65*sqrt(5))/6, sqrt(29530+13204*sqrt(5))/3,
+ _point_ref(concat(
+ _even_perms([0,0,sqrt(5)]),
+ _even_perms([0,(15+sqrt(5))/22, (25+9*sqrt(5))/22]),
+ _even_perms([0,(5+3*sqrt(5))/6, (5+sqrt(5))/6]),
+ _even_perms([(5-sqrt(5))/4, sqrt(5)/2, (5+sqrt(5))/4]),
+ [(5+4*sqrt(5))/11*[1,1,1]]
+ ))],
+ ["disdyakis dodecahedron", "catalan", 48, [3], 1,sqrt(249/194+285/194/sqrt(2)) ,(2+3*sqrt(2))/4, sqrt(183/98+213/98/sqrt(2)),
+ sqrt(6582+4539*sqrt(2))/7,
+ _point_ref(concat(
+ _even_perms([sqrt(183/98+213/98/sqrt(2)),0,0]),
+ _even_perms(sqrt(3+3/sqrt(2))/2 * [1,1,0]),[7/sqrt(6*(10-sqrt(2)))*[1,1,1]]
+ ))],
+ ["disdyakis triacontahedron","catalan", 120, [3], sqrt(15*(85-31*sqrt(5)))/11, sqrt(3477/964+7707/964/sqrt(5)), 5/4+13/4/sqrt(5),
+ sqrt(441+195*sqrt(5))/10,sqrt(17718/5+39612/5/sqrt(5)),
+ _point_ref(concat(
+ _even_perms([0,0,3*(5+4*sqrt(5))/11]),
+ _even_perms([0,(5-sqrt(5))/2,(5+sqrt(5))/2]),
+ _even_perms([0,(15+9*sqrt(5))/10,3*(5+sqrt(5))/10]),
+ _even_perms([3*(15+sqrt(5))/44,3*(5+4*sqrt(5))/22, (75+27*sqrt(5))/44]), [sqrt(5)*[1,1,1]]
+ ))],
+ ["pentagonal icositetrahedron","catalan",24, [5], 0.593465355971, 1.950681331784, 2.1015938932963, 2.29400105368695, 35.6302020120713,
+ concat(
+ _point_ref(_even_perms([0.21879664300048044,0.740183741369857,1.0236561781126901]),sign="even"),
+ _point_ref(_even_perms([0.21879664300048044,1.0236561781126901,0.740183741369857]),sign="odd"),
+ _point_ref(_even_perms([1.3614101519264425,0,0])),
+ _point_ref([0.7401837413698572*[1,1,1]])
+ )],
+ ["pentagonal hexecontahedron", "catalan", 60,[5], 0.58289953474498, 3.499527848905764,3.597624822551189,3.80854772878239, 189.789852066885,
+ concat(
+ _point_ref(_even_perms([0.192893711352359,0.218483370127321,2.097053835252087]), sign="even"),
+ _point_ref(_even_perms([0,0.7554672605165955,1.9778389654202186])),
+ _point_ref(_even_perms([0,1.888445389283669154,1.1671234364753339])),
+ _point_ref(_even_perms([0.56771536946692131,0.824957552676275846,1.8654013108176956657]),sign="odd"),
+ _point_ref(_even_perms([0.37482165811456229,1.13706613386050418,1.746186440985826345]), sign="even"),
+ _point_ref(_even_perms([0.921228888309550,0.95998770139158,1.6469179406903744]),sign="even"),
+ _point_ref(_even_perms([0.7283351769571914773,1.2720962825758121,1.5277030708585051]),sign="odd"),
+ _point_ref([1.222371704903623092*[1,1,1]])
+ )],
];
_stellated_polyhedra_ = [
- ["great dodecahedron", "icosahedron", -sqrt(5/3-PHI)],
- ["small stellated dodecahedron", "dodecahedron", sqrt((5+2*sqrt(5))/5)],
- ["great stellated dodecahedron", "icosahedron", sqrt(2/3+PHI)],
+ ["great dodecahedron", "icosahedron", -sqrt(5/3-PHI)],
+ ["small stellated dodecahedron", "dodecahedron", sqrt((5+2*sqrt(5))/5)],
+ ["great stellated dodecahedron", "icosahedron", sqrt(2/3+PHI)],
];
@@ -587,130 +587,130 @@ _stellated_polyhedra_ = [
// longside = Specify the long side length for a trapezohedron. Ignored for other shapes.
// h = Specify the height of the apex for a trapezohedron. Ignored for other shapes.
function regular_polyhedron_info(
- info=undef, name=undef,
- index=undef, type=undef,
- faces=undef, facetype=undef,
- hasfaces=undef, side=1,
- ir=undef, mr=undef, or=undef,
- r=undef, d=undef,
- anchor=[0,0,0], center=undef,
- facedown=true, stellate=false,
- longside=undef, h=undef // special parameters for trapezohedron
+ info=undef, name=undef,
+ index=undef, type=undef,
+ faces=undef, facetype=undef,
+ hasfaces=undef, side=1,
+ ir=undef, mr=undef, or=undef,
+ r=undef, d=undef,
+ anchor=[0,0,0], center=undef,
+ facedown=true, stellate=false,
+ longside=undef, h=undef // special parameters for trapezohedron
) = let(
- anchor = !is_undef(center) ? [0,0,0] : anchor,
- argcount = num_defined([ir,mr,or,r,d])
- )
- assert(argcount<=1, "You must specify only one of 'ir', 'mr', 'or', 'r', and 'd'")
- let(
- //////////////////////
- //Index values into the _polyhedra_ array
- //
- pname = 0, // name of polyhedron
- class = 1, // class name (e.g. platonic, archimedean)
- facecount = 2, // number of faces
- facevertices = 3, // vertices on the faces, e.g. [3] for all triangles, [3,4] for triangles and squares
- edgelen = 4, // length of the edge for the vertex list in the database
- in_radius = 5, // in radius for unit polyhedron (shortest side 1)
- mid_radius = 6, // mid radius for unit polyhedron
- out_radius = 7, // out radius for unit polyhedron
- volume = 8, // volume of unit polyhedron (data not validated, not used right now)
- vertices = 9, // vertex list (in arbitrary order)
- //////////////////////
- r = !is_undef(d) ? d/2 : r,
- or = !is_undef(r) ? r : or,
- stellate_index = search([name], _stellated_polyhedra_, 1, 0)[0],
- name = stellate_index==[] ? name : _stellated_polyhedra_[stellate_index][1],
- stellate = stellate_index==[] ? stellate : _stellated_polyhedra_[stellate_index][2],
- indexlist = (
- name=="trapezohedron" ? [0] : [ // dumy list of one item
- for(i=[0:1:len(_polyhedra_)-1]) (
- if (
- (is_undef(name) || _polyhedra_[i][pname]==name) &&
- (is_undef(type) || _polyhedra_[i][class]==type) &&
- (is_undef(faces) || _polyhedra_[i][facecount]==faces) &&
- (
- is_undef(facetype) || 0==compare_lists(
- is_list(facetype)? reverse(sort(facetype)) : [facetype],
- _polyhedra_[i][facevertices]
- )
- ) &&
- (is_undef(hasfaces) || any([for (ft=hasfaces) in_list(ft,_polyhedra_[i][facevertices])]))
- ) i
- )
- ]
- )
- )
- assert(len(indexlist)>0, "No polyhedra meet your specification")
- let(validindex = is_undef(index) || (index>=0 && index0, "No polyhedra meet your specification")
+ let(validindex = is_undef(index) || (index>=0 && index0 ? 1 : -1],
- maxvertex = len(vertices),
- newpts = [for(i=[0:1:len(faces)-1]) mean(select(vertices,faces[i]))+stellate*scalefactor*faces_normals[1][i]],
- newfaces = [for(i=[0:1:len(faces)-1], j=[0:len(faces[i])-1]) concat([i+maxvertex],select(faces[i], [j, j+direction[i]]))],
- allpts = concat(vertices, newpts),
- normals = [for(face=newfaces) _facenormal(allpts,face)]
- ) [newfaces, normals, allpts];
+ (stellate == false || stellate == 0)? concat(faces_normals,[vertices]) :
+ let(
+ faces = [for(face=faces_normals[0]) select(face,hull(select(vertices,face)))],
+ direction = [for(i=[0:1:len(faces)-1]) _facenormal(vertices, faces[i])*faces_normals[1][i]>0 ? 1 : -1],
+ maxvertex = len(vertices),
+ newpts = [for(i=[0:1:len(faces)-1]) mean(select(vertices,faces[i]))+stellate*scalefactor*faces_normals[1][i]],
+ newfaces = [for(i=[0:1:len(faces)-1], j=[0:len(faces[i])-1]) concat([i+maxvertex],select(faces[i], [j, j+direction[i]]))],
+ allpts = concat(vertices, newpts),
+ normals = [for(face=newfaces) _facenormal(allpts,face)]
+ ) [newfaces, normals, allpts];
function trapezohedron(faces, r, side, longside, h) =
- assert(faces%2==0, "Number of faces must be even")
- let(
- N = faces/2,
- parmcount = num_defined([r,side,longside,h])
- )
- assert(parmcount==2,"Must define exactly two of 'r', 'side', 'longside', and 'height'")
- let(
- separation = (
- !is_undef(h) ? 2*h*sqr(tan(90/N)) :
- (!is_undef(r) && !is_undef(side))? sqrt(side*side+2*r*r*(cos(180/N)-1)) :
- (!is_undef(r) && !is_undef(longside))? 2 * sqrt(sqr(longside)-sqr(r)) / (1-sqr(tan(90/N))) * sqr(tan(90/N)) :
- 2*sqr(sin(90/N))*sqrt((sqr(side) + 2*sqr(longside)*(cos(180/N)-1)) / (cos(180/N)-1) / (cos(180/N)+cos(360/N)))
- )
- )
- assert(separation==separation, "Impossible trapezohedron specification")
- let(
- h = !is_undef(h) ? h : 0.5*separation / sqr(tan(90/N)),
- r = (
- !is_undef(r) ? r :
- !is_undef(side) ? sqrt((sqr(separation) - sqr(side))/2/(cos(180/N)-1)) :
- sqrt(sqr(longside) - sqr(h-separation/2))
- ),
- top = [for(i=[0:1:N-1]) [r*cos(360/N*i), r*sin(360/N*i),separation/2]],
- bot = [for(i=[0:1:N-1]) [r*cos(180/N+360/N*i), r*sin(180/N+360/N*i),-separation/2]],
- vertices = concat([[0,0,h],[0,0,-h]],top,bot)
- ) [
- "trapezohedron", "trapezohedron", faces, [4],
- !is_undef(side)? side : sqrt(sqr(separation)-2*r*(cos(180/N)-1)), // actual side length
- h*r/sqrt(r*r+sqr(h+separation/2)), // in_radius
- h*r/sqrt(r*r+sqr(h-separation/2)), // mid_radius
- max(h,sqrt(r*r+sqr(separation/2))), // out_radius
- undef, // volume
- vertices
- ];
+ assert(faces%2==0, "Number of faces must be even")
+ let(
+ N = faces/2,
+ parmcount = num_defined([r,side,longside,h])
+ )
+ assert(parmcount==2,"Must define exactly two of 'r', 'side', 'longside', and 'height'")
+ let(
+ separation = (
+ !is_undef(h) ? 2*h*sqr(tan(90/N)) :
+ (!is_undef(r) && !is_undef(side))? sqrt(side*side+2*r*r*(cos(180/N)-1)) :
+ (!is_undef(r) && !is_undef(longside))? 2 * sqrt(sqr(longside)-sqr(r)) / (1-sqr(tan(90/N))) * sqr(tan(90/N)) :
+ 2*sqr(sin(90/N))*sqrt((sqr(side) + 2*sqr(longside)*(cos(180/N)-1)) / (cos(180/N)-1) / (cos(180/N)+cos(360/N)))
+ )
+ )
+ assert(separation==separation, "Impossible trapezohedron specification")
+ let(
+ h = !is_undef(h) ? h : 0.5*separation / sqr(tan(90/N)),
+ r = (
+ !is_undef(r) ? r :
+ !is_undef(side) ? sqrt((sqr(separation) - sqr(side))/2/(cos(180/N)-1)) :
+ sqrt(sqr(longside) - sqr(h-separation/2))
+ ),
+ top = [for(i=[0:1:N-1]) [r*cos(360/N*i), r*sin(360/N*i),separation/2]],
+ bot = [for(i=[0:1:N-1]) [r*cos(180/N+360/N*i), r*sin(180/N+360/N*i),-separation/2]],
+ vertices = concat([[0,0,h],[0,0,-h]],top,bot)
+ ) [
+ "trapezohedron", "trapezohedron", faces, [4],
+ !is_undef(side)? side : sqrt(sqr(separation)-2*r*(cos(180/N)-1)), // actual side length
+ h*r/sqrt(r*r+sqr(h+separation/2)), // in_radius
+ h*r/sqrt(r*r+sqr(h-separation/2)), // mid_radius
+ max(h,sqrt(r*r+sqr(separation/2))), // out_radius
+ undef, // volume
+ vertices
+ ];
function _facenormal(pts, face) = unit(cross(pts[face[2]]-pts[face[0]], pts[face[1]]-pts[face[0]]));
-// hull() function returns triangulated faces. This function identifies the vertices that belong to each face
-// by grouping together the face triangles that share normal vectors. The output gives the face polygon
+// hull() function returns triangulated faces. This function identifies the vertices that belong to each face
+// by grouping together the face triangles that share normal vectors. The output gives the face polygon
// point indices in arbitrary order (not usable as input to a polygon call) and a normal vector.
function _full_faces(pts,faces) =
- let(
- normals = [for(face=faces) quant(_facenormal(pts,face),1e-12)],
- groups = _unique_groups(normals),
- faces = [for(entry=groups) unique(flatten(select(faces, entry)))],
- facenormals = [for(entry=groups) normals[entry[0]]]
- ) [faces, facenormals];
+ let(
+ normals = [for(face=faces) quant(_facenormal(pts,face),1e-12)],
+ groups = _unique_groups(normals),
+ faces = [for(entry=groups) unique(flatten(select(faces, entry)))],
+ facenormals = [for(entry=groups) normals[entry[0]]]
+ ) [faces, facenormals];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/primitives.scad b/primitives.scad
index e6bb936..60f6e5a 100644
--- a/primitives.scad
+++ b/primitives.scad
@@ -32,16 +32,16 @@
// stroke(path, closed=true);
// move_copies(path) color("blue") circle(d=2,$fn=8);
function square(size=1, center, anchor, spin=0) =
- let(
- anchor = get_anchor(anchor, center, [-1,-1], [-1,-1]),
- size = is_num(size)? [size,size] : point2d(size),
- path = [
- [ size.x,-size.y],
- [-size.x,-size.y],
- [-size.x, size.y],
- [ size.x, size.y]
- ] / 2
- ) reorient(anchor,spin, two_d=true, size=size, p=path);
+ let(
+ anchor = get_anchor(anchor, center, [-1,-1], [-1,-1]),
+ size = is_num(size)? [size,size] : point2d(size),
+ path = [
+ [ size.x,-size.y],
+ [-size.x,-size.y],
+ [-size.x, size.y],
+ [ size.x, size.y]
+ ] / 2
+ ) reorient(anchor,spin, two_d=true, size=size, p=path);
// Function&Module: circle()
@@ -62,11 +62,11 @@ function square(size=1, center, anchor, spin=0) =
// Example(NORENDER): Called as Function
// path = circle(d=50, anchor=FRONT, spin=45);
function circle(r, d, anchor=CENTER, spin=0) =
- let(
- r = get_radius(r=r, d=d, dflt=1),
- sides = segs(r),
- path = [for (i=[0:1:sides-1]) let(a=360-i*360/sides) r*[cos(a),sin(a)]]
- ) reorient(anchor,spin, two_d=true, r=r, p=path);
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ sides = segs(r),
+ path = [for (i=[0:1:sides-1]) let(a=360-i*360/sides) r*[cos(a),sin(a)]]
+ ) reorient(anchor,spin, two_d=true, r=r, p=path);
@@ -105,36 +105,36 @@ function circle(r, d, anchor=CENTER, spin=0) =
// vnf_polyhedron(vnf);
module cube(size=1, center, anchor, spin=0, orient=UP)
{
- anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
- size = scalar_vec3(size);
- attachable(anchor,spin,orient, size=size) {
- linear_extrude(height=size.z, center=true, convexity=2) {
- square([size.x,size.y], center=true);
- }
- children();
- }
+ anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
+ size = scalar_vec3(size);
+ attachable(anchor,spin,orient, size=size) {
+ linear_extrude(height=size.z, center=true, convexity=2) {
+ square([size.x,size.y], center=true);
+ }
+ children();
+ }
}
function cube(size=1, center, anchor, spin=0, orient=UP) =
- let(
- siz = scalar_vec3(size),
- anchor = get_anchor(anchor, center, ALLNEG, ALLNEG),
- unscaled = [
- [-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1],
- [-1,-1, 1],[1,-1, 1],[1,1, 1],[-1,1, 1],
- ]/2,
- verts = is_num(size)? unscaled * size :
- is_vector(size,3)? [for (p=unscaled) vmul(p,size)] :
- assert(is_num(size) || is_vector(size,3)),
- faces = [
- [0,1,2], [0,2,3], //BOTTOM
- [0,4,5], [0,5,1], //FRONT
- [1,5,6], [1,6,2], //RIGHT
- [2,6,7], [2,7,3], //BACK
- [3,7,4], [3,4,0], //LEFT
- [6,4,7], [6,5,4] //TOP
- ]
- ) [reorient(anchor,spin,orient, size=siz, p=verts), faces];
+ let(
+ siz = scalar_vec3(size),
+ anchor = get_anchor(anchor, center, ALLNEG, ALLNEG),
+ unscaled = [
+ [-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1],
+ [-1,-1, 1],[1,-1, 1],[1,1, 1],[-1,1, 1],
+ ]/2,
+ verts = is_num(size)? unscaled * size :
+ is_vector(size,3)? [for (p=unscaled) vmul(p,size)] :
+ assert(is_num(size) || is_vector(size,3)),
+ faces = [
+ [0,1,2], [0,2,3], //BOTTOM
+ [0,4,5], [0,5,1], //FRONT
+ [1,5,6], [1,6,2], //RIGHT
+ [2,6,7], [2,7,3], //BACK
+ [3,7,4], [3,4,0], //LEFT
+ [6,4,7], [6,5,4] //TOP
+ ]
+ ) [reorient(anchor,spin,orient, size=siz, p=verts), faces];
// Function&Module: cylinder()
@@ -183,45 +183,45 @@ function cube(size=1, center, anchor, spin=0, orient=UP) =
// }
module cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
{
- anchor = get_anchor(anchor, center, BOTTOM, BOTTOM);
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
- l = first_defined([h, l, 1]);
- sides = segs(max(r1,r2));
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- if(r1>r2) {
- linear_extrude(height=l, center=true, convexity=2, scale=r2/r1) {
- circle(r=r1);
- }
- } else {
- zflip() {
- linear_extrude(height=l, center=true, convexity=2, scale=r1/r2) {
- circle(r=r2);
- }
- }
- }
- children();
- }
+ anchor = get_anchor(anchor, center, BOTTOM, BOTTOM);
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
+ l = first_defined([h, l, 1]);
+ sides = segs(max(r1,r2));
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ if(r1>r2) {
+ linear_extrude(height=l, center=true, convexity=2, scale=r2/r1) {
+ circle(r=r1);
+ }
+ } else {
+ zflip() {
+ linear_extrude(height=l, center=true, convexity=2, scale=r1/r2) {
+ circle(r=r2);
+ }
+ }
+ }
+ children();
+ }
}
function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP) =
- let(
- anchor = get_anchor(anchor, center, BOTTOM, BOTTOM),
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
- l = first_defined([h, l, 1]),
- sides = segs(max(r1,r2)),
- verts = [
- for (i=[0:1:sides-1]) let(a=360*(1-i/sides)) [r1*cos(a),r1*sin(a),-l/2],
- for (i=[0:1:sides-1]) let(a=360*(1-i/sides)) [r2*cos(a),r2*sin(a), l/2],
- ],
- faces = [
- [for (i=[0:1:sides-1]) sides-1-i],
- for (i=[0:1:sides-1]) [i, ((i+1)%sides)+sides, i+sides],
- for (i=[0:1:sides-1]) [i, (i+1)%sides, ((i+1)%sides)+sides],
- [for (i=[0:1:sides-1]) sides+i]
- ]
- ) [reorient(anchor,spin,orient, l=l, r1=r1, r2=r2, p=verts), faces];
+ let(
+ anchor = get_anchor(anchor, center, BOTTOM, BOTTOM),
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
+ l = first_defined([h, l, 1]),
+ sides = segs(max(r1,r2)),
+ verts = [
+ for (i=[0:1:sides-1]) let(a=360*(1-i/sides)) [r1*cos(a),r1*sin(a),-l/2],
+ for (i=[0:1:sides-1]) let(a=360*(1-i/sides)) [r2*cos(a),r2*sin(a), l/2],
+ ],
+ faces = [
+ [for (i=[0:1:sides-1]) sides-1-i],
+ for (i=[0:1:sides-1]) [i, ((i+1)%sides)+sides, i+sides],
+ for (i=[0:1:sides-1]) [i, (i+1)%sides, ((i+1)%sides)+sides],
+ [for (i=[0:1:sides-1]) sides+i]
+ ]
+ ) [reorient(anchor,spin,orient, l=l, r1=r1, r2=r2, p=verts), faces];
@@ -268,11 +268,11 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// vnf = sphere(d=100, style="icosa");
// vnf_polyhedron(vnf);
module sphere(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP)
- spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient) children();
+ spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient) children();
function sphere(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP) =
- spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
+ spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/quaternions.scad b/quaternions.scad
index 0f9db2d..40712d9 100644
--- a/quaternions.scad
+++ b/quaternions.scad
@@ -65,12 +65,12 @@ function QuatZ(a=0) = Quat([0,0,1],a);
// Arguments:
// a = The triplet of rotation angles, [X,Y,Z]
function QuatXYZ(a=[0,0,0]) =
- let(
- qx = QuatX(a[0]),
- qy = QuatY(a[1]),
- qz = QuatZ(a[2])
- )
- Q_Mul(qz, Q_Mul(qy, qx));
+ let(
+ qx = QuatX(a[0]),
+ qy = QuatY(a[1]),
+ qz = QuatZ(a[2])
+ )
+ Q_Mul(qz, Q_Mul(qy, qx));
// Function: Q_Ident()
@@ -125,10 +125,10 @@ function Q_Sub(a, b) = a-b;
// Q_Mul(a, b)
// Description: Multiplies quaternion `a` by quaternion `b`.
function Q_Mul(a, b) = [
- a[3]*b.x + a.x*b[3] + a.y*b.z - a.z*b.y,
- a[3]*b.y - a.x*b.z + a.y*b[3] + a.z*b.x,
- a[3]*b.z + a.x*b.y - a.y*b.x + a.z*b[3],
- a[3]*b[3] - a.x*b.x - a.y*b.y - a.z*b.z,
+ a[3]*b.x + a.x*b[3] + a.y*b.z - a.z*b.y,
+ a[3]*b.y - a.x*b.z + a.y*b[3] + a.z*b.x,
+ a[3]*b.z + a.x*b.y - a.y*b.x + a.z*b[3],
+ a[3]*b[3] - a.x*b.x - a.y*b.y - a.z*b.z,
];
@@ -140,14 +140,14 @@ function Q_Mul(a, b) = [
// of each cumulative Quaternion product. It starts with the first quaternion
// given in the list, and applies successive quaternion rotations in list order.
function Q_Cumulative(v, _i=0, _acc=[]) =
- _i==len(v) ? _acc :
- Q_Cumulative(
- v, _i+1,
- concat(
- _acc,
- [_i==0 ? v[_i] : Q_Mul(v[_i], select(_acc,-1))]
- )
- );
+ _i==len(v) ? _acc :
+ Q_Cumulative(
+ v, _i+1,
+ concat(
+ _acc,
+ [_i==0 ? v[_i] : Q_Mul(v[_i], select(_acc,-1))]
+ )
+ );
// Function: Q_Dot()
@@ -215,23 +215,23 @@ function Q_Dist(q1, q2) = norm(q2-q1);
// Qrot(q) right(80) cube([10,10,1]);
// #sphere(r=80);
function Q_Slerp(q1, q2, u) =
- assert(is_num(u) || is_num(u[0]))
- !is_num(u)? [for (uu=u) Q_Slerp(q1,q2,uu)] :
+ assert(is_num(u) || is_num(u[0]))
+ !is_num(u)? [for (uu=u) Q_Slerp(q1,q2,uu)] :
let(
- q1 = Q_Normalize(q1),
- q2 = Q_Normalize(q2),
- dot = Q_Dot(q1, q2)
- ) let(
- q2 = dot<0? Q_Neg(q2) : q2,
- dot = dot<0? -dot : dot
- ) (dot>0.9995)? Q_Normalize(q1 + (u * (q2-q1))) :
- let(
- dot = constrain(dot,-1,1),
- theta_0 = acos(dot),
- theta = theta_0 * u,
- q3 = Q_Normalize(q2 - q1*dot),
- out = q1*cos(theta) + q3*sin(theta)
- ) out;
+ q1 = Q_Normalize(q1),
+ q2 = Q_Normalize(q2),
+ dot = Q_Dot(q1, q2)
+ ) let(
+ q2 = dot<0? Q_Neg(q2) : q2,
+ dot = dot<0? -dot : dot
+ ) (dot>0.9995)? Q_Normalize(q1 + (u * (q2-q1))) :
+ let(
+ dot = constrain(dot,-1,1),
+ theta_0 = acos(dot),
+ theta = theta_0 * u,
+ q3 = Q_Normalize(q2 - q1*dot),
+ out = q1*cos(theta) + q3*sin(theta)
+ ) out;
// Function: Q_Matrix3()
@@ -240,9 +240,9 @@ function Q_Slerp(q1, q2, u) =
// Description:
// Returns the 3x3 rotation matrix for the given normalized quaternion q.
function Q_Matrix3(q) = [
- [1-2*q[1]*q[1]-2*q[2]*q[2], 2*q[0]*q[1]-2*q[2]*q[3], 2*q[0]*q[2]+2*q[1]*q[3]],
- [ 2*q[0]*q[1]+2*q[2]*q[3], 1-2*q[0]*q[0]-2*q[2]*q[2], 2*q[1]*q[2]-2*q[0]*q[3]],
- [ 2*q[0]*q[2]-2*q[1]*q[3], 2*q[1]*q[2]+2*q[0]*q[3], 1-2*q[0]*q[0]-2*q[1]*q[1]]
+ [1-2*q[1]*q[1]-2*q[2]*q[2], 2*q[0]*q[1]-2*q[2]*q[3], 2*q[0]*q[2]+2*q[1]*q[3]],
+ [ 2*q[0]*q[1]+2*q[2]*q[3], 1-2*q[0]*q[0]-2*q[2]*q[2], 2*q[1]*q[2]-2*q[0]*q[3]],
+ [ 2*q[0]*q[2]-2*q[1]*q[3], 2*q[1]*q[2]+2*q[0]*q[3], 1-2*q[0]*q[0]-2*q[1]*q[1]]
];
@@ -252,10 +252,10 @@ function Q_Matrix3(q) = [
// Description:
// Returns the 4x4 rotation matrix for the given normalized quaternion q.
function Q_Matrix4(q) = [
- [1-2*q[1]*q[1]-2*q[2]*q[2], 2*q[0]*q[1]-2*q[2]*q[3], 2*q[0]*q[2]+2*q[1]*q[3], 0],
- [ 2*q[0]*q[1]+2*q[2]*q[3], 1-2*q[0]*q[0]-2*q[2]*q[2], 2*q[1]*q[2]-2*q[0]*q[3], 0],
- [ 2*q[0]*q[2]-2*q[1]*q[3], 2*q[1]*q[2]+2*q[0]*q[3], 1-2*q[0]*q[0]-2*q[1]*q[1], 0],
- [ 0, 0, 0, 1]
+ [1-2*q[1]*q[1]-2*q[2]*q[2], 2*q[0]*q[1]-2*q[2]*q[3], 2*q[0]*q[2]+2*q[1]*q[3], 0],
+ [ 2*q[0]*q[1]+2*q[2]*q[3], 1-2*q[0]*q[0]-2*q[2]*q[2], 2*q[1]*q[2]-2*q[0]*q[3], 0],
+ [ 2*q[0]*q[2]-2*q[1]*q[3], 2*q[1]*q[2]+2*q[0]*q[3], 1-2*q[0]*q[0]-2*q[1]*q[1], 0],
+ [ 0, 0, 0, 1]
];
@@ -299,15 +299,15 @@ function Q_Angle(q) = 2 * acos(q[3]);
// q = QuatXYZ([45,35,10]);
// pts = Qrot(q, p=[[2,3,4], [4,5,6], [9,2,3]]);
module Qrot(q) {
- multmatrix(Q_Matrix4(q)) {
- children();
- }
+ multmatrix(Q_Matrix4(q)) {
+ children();
+ }
}
function Qrot(q,p) =
- is_undef(p)? Q_Matrix4(q) :
- is_vector(p)? Qrot(q,[p])[0] :
- apply(Q_Matrix4(q), p);
+ is_undef(p)? Q_Matrix4(q) :
+ is_vector(p)? Qrot(q,[p])[0] :
+ apply(Q_Matrix4(q), p);
// Module: Qrot_copies()
@@ -327,4 +327,4 @@ function Qrot(q,p) =
module Qrot_copies(quats) for (q=quats) Qrot(q) children();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/queues.scad b/queues.scad
index cb346c0..f2e2d00 100644
--- a/queues.scad
+++ b/queues.scad
@@ -39,8 +39,8 @@ function queue_init() = [];
// queue2 = queue_add(queue, "foo");
// is_empty2 = queue_empty(queue2); // Returns: false
function queue_empty(queue) =
- assert(is_list(queue))
- len(queue)==0;
+ assert(is_list(queue))
+ len(queue)==0;
// Function: queue_size()
@@ -58,8 +58,8 @@ function queue_empty(queue) =
// queue3 = queue_add(queue2, ["bar","baz","qux"]);
// depth3 = queue_size(queue3); // Returns: 4
function queue_size(queue) =
- assert(is_list(queue))
- len(queue);
+ assert(is_list(queue))
+ len(queue);
// Function: queue_head()
@@ -76,16 +76,16 @@ function queue_size(queue) =
// item = queue_head(queue); // Returns: 4
// list = queue_head(queue,n=3); // Returns: [4,5,6]
function queue_head(queue,n=undef) =
- assert(is_list(queue))
- is_undef(n)? (
- queue[0]
- ) : (
- let(queuesize = len(queue))
- assert(is_num(n))
- assert(n>=0)
- assert(queuesize>=n, "queue underflow")
- [for (i=[0:1:n-1]) queue[i]]
- );
+ assert(is_list(queue))
+ is_undef(n)? (
+ queue[0]
+ ) : (
+ let(queuesize = len(queue))
+ assert(is_num(n))
+ assert(n>=0)
+ assert(queuesize>=n, "queue underflow")
+ [for (i=[0:1:n-1]) queue[i]]
+ );
// Function: queue_tail()
@@ -102,16 +102,16 @@ function queue_head(queue,n=undef) =
// item = queue_tail(queue); // Returns: 9
// list = queue_tail(queue,n=3); // Returns: [7,8,9]
function queue_tail(queue,n=undef) =
- assert(is_list(queue))
- let(queuesize = len(queue))
- is_undef(n)? (
- queue[queuesize-1]
- ) : (
- assert(is_num(n))
- assert(n>=0)
- assert(queuesize>=n, "queue underflow")
- [for (i=[0:1:n-1]) queue[queuesize-n+i]]
- );
+ assert(is_list(queue))
+ let(queuesize = len(queue))
+ is_undef(n)? (
+ queue[queuesize-1]
+ ) : (
+ assert(is_num(n))
+ assert(n>=0)
+ assert(queuesize>=n, "queue underflow")
+ [for (i=[0:1:n-1]) queue[queuesize-n+i]]
+ );
// Function: queue_peek()
@@ -131,19 +131,19 @@ function queue_tail(queue,n=undef) =
// item2 = queue_peek(queue, 3); // Returns: 5
// list = queue_peek(queue, 4, 3); // Returns: [6,7,8]
function queue_peek(queue,pos=0,n=undef) =
- assert(is_list(queue))
- assert(is_num(pos))
- assert(pos>=0)
- let(queuesize = len(queue))
- assert(queuesize>=pos, "queue underflow")
- is_undef(n)? (
- queue[pos]
- ) : (
- assert(is_num(n))
- assert(n>=0)
- assert(n=0)
+ let(queuesize = len(queue))
+ assert(queuesize>=pos, "queue underflow")
+ is_undef(n)? (
+ queue[pos]
+ ) : (
+ assert(is_num(n))
+ assert(n>=0)
+ assert(n=0)
- let(queuesize = len(queue))
- assert(queuesize>=n, "queue underflow")
- [for (i = [n:1:queuesize-1]) queue[i]];
+ assert(is_list(queue))
+ assert(is_num(n))
+ assert(n>=0)
+ let(queuesize = len(queue))
+ assert(queuesize>=n, "queue underflow")
+ [for (i = [n:1:queuesize-1]) queue[i]];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/regions.scad b/regions.scad
index f2b7996..5a64ff9 100644
--- a/regions.scad
+++ b/regions.scad
@@ -48,13 +48,13 @@ function close_region(region, eps=EPSILON) = [for (path=region) close_path(path,
// region(rgn);
module region(r)
{
- points = flatten(r);
- paths = [
- for (i=[0:1:len(r)-1]) let(
- start = default(sum([for (j=[0:1:i-1]) len(r[j])]),0)
- ) [for (k=[0:1:len(r[i])-1]) start+k]
- ];
- polygon(points=points, paths=paths);
+ points = flatten(r);
+ paths = [
+ for (i=[0:1:len(r)-1]) let(
+ start = default(sum([for (j=[0:1:i-1]) len(r[j])]),0)
+ ) [for (k=[0:1:len(r[i])-1]) start+k]
+ ];
+ polygon(points=points, paths=paths);
}
@@ -70,28 +70,28 @@ module region(r)
// valid_dim = list of allowed dimensions for the points in the path, e.g. [2,3] to require 2 or 3 dimensional input. If left undefined do not perform this check. Default: undef
// closed = set to true if the path is closed, which enables a check for endpoint duplication
function check_and_fix_path(path, valid_dim=undef, closed=false) =
- let(
- path = is_region(path)? (
- assert(len(path)==1,"Region supplied as path does not have exactly one component")
- path[0]
- ) : (
- assert(is_path(path), "Input is not a path")
- path
- ),
- dim = array_dim(path)
- )
- assert(dim[0]>1,"Path must have at least 2 points")
- assert(len(dim)==2,"Invalid path: path is either a list of scalars or a list of matrices")
- assert(is_def(dim[1]), "Invalid path: entries in the path have variable length")
- let(valid=is_undef(valid_dim) || in_list(dim[1],valid_dim))
- assert(
- valid, str(
- "The points on the path have length ",
- dim[1], " but length must be ",
- len(valid_dim)==1? valid_dim[0] : str("one of ",valid_dim)
- )
- )
- closed && approx(path[0],select(path,-1))? slice(path,0,-2) : path;
+ let(
+ path = is_region(path)? (
+ assert(len(path)==1,"Region supplied as path does not have exactly one component")
+ path[0]
+ ) : (
+ assert(is_path(path), "Input is not a path")
+ path
+ ),
+ dim = array_dim(path)
+ )
+ assert(dim[0]>1,"Path must have at least 2 points")
+ assert(len(dim)==2,"Invalid path: path is either a list of scalars or a list of matrices")
+ assert(is_def(dim[1]), "Invalid path: entries in the path have variable length")
+ let(valid=is_undef(valid_dim) || in_list(dim[1],valid_dim))
+ assert(
+ valid, str(
+ "The points on the path have length ",
+ dim[1], " but length must be ",
+ len(valid_dim)==1? valid_dim[0] : str("one of ",valid_dim)
+ )
+ )
+ closed && approx(path[0],select(path,-1))? slice(path,0,-2) : path;
// Function: cleanup_region()
@@ -103,7 +103,7 @@ function check_and_fix_path(path, valid_dim=undef, closed=false) =
// region = The region to clean up. Given as a list of polygon paths.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function cleanup_region(region, eps=EPSILON) =
- [for (path=region) cleanup_path(path, eps=eps)];
+ [for (path=region) cleanup_path(path, eps=eps)];
// Function: point_in_region()
@@ -119,9 +119,9 @@ function cleanup_region(region, eps=EPSILON) =
// region = The region to test against. Given as a list of polygon paths.
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function point_in_region(point, region, eps=EPSILON, _i=0, _cnt=0) =
- (_i >= len(region))? ((_cnt%2==1)? 1 : -1) : let(
- pip = point_in_polygon(point, region[_i], eps=eps)
- ) pip==0? 0 : point_in_region(point, region, eps=eps, _i=_i+1, _cnt = _cnt + (pip>0? 1 : 0));
+ (_i >= len(region))? ((_cnt%2==1)? 1 : -1) : let(
+ pip = point_in_polygon(point, region[_i], eps=eps)
+ ) pip==0? 0 : point_in_region(point, region, eps=eps, _i=_i+1, _cnt = _cnt + (pip>0? 1 : 0));
// Function: region_path_crossings()
@@ -135,20 +135,20 @@ function point_in_region(point, region, eps=EPSILON, _i=0, _cnt=0) =
// closed = If true, treat path as a closed polygon. Default: true
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
function region_path_crossings(path, region, closed=true, eps=EPSILON) = sort([
- let(
- segs = pair(closed? close_path(path) : cleanup_path(path))
- ) for (
- si = idx(segs),
- p = close_region(region),
- s2 = pair(p)
- ) let (
- isect = _general_line_intersection(segs[si], s2, eps=eps)
- ) if (
- !is_undef(isect) &&
- isect[1] >= 0-eps && isect[1] < 1+eps &&
- isect[2] >= 0-eps && isect[2] < 1+eps
- )
- [si, isect[1]]
+ let(
+ segs = pair(closed? close_path(path) : cleanup_path(path))
+ ) for (
+ si = idx(segs),
+ p = close_region(region),
+ s2 = pair(p)
+ ) let (
+ isect = _general_line_intersection(segs[si], s2, eps=eps)
+ ) if (
+ !is_undef(isect) &&
+ isect[1] >= 0-eps && isect[1] < 1+eps &&
+ isect[2] >= 0-eps && isect[2] < 1+eps
+ )
+ [si, isect[1]]
]);
@@ -170,22 +170,22 @@ function region_path_crossings(path, region, closed=true, eps=EPSILON) = sort([
// color("#aaa") region(region);
// rainbow(polylines) stroke($item, closed=false, width=2);
function split_path_at_region_crossings(path, region, closed=true, eps=EPSILON) =
- let(
- path = deduplicate(path, eps=eps),
- region = [for (path=region) deduplicate(path, eps=eps)],
- xings = region_path_crossings(path, region, closed=closed, eps=eps),
- crossings = deduplicate(
- concat([[0,0]], xings, [[len(path)-1,1]]),
- eps=eps
- ),
- subpaths = [
- for (p = pair(crossings))
- deduplicate(eps=eps,
- path_subselect(path, p[0][0], p[0][1], p[1][0], p[1][1], closed=closed)
- )
- ]
- )
- subpaths;
+ let(
+ path = deduplicate(path, eps=eps),
+ region = [for (path=region) deduplicate(path, eps=eps)],
+ xings = region_path_crossings(path, region, closed=closed, eps=eps),
+ crossings = deduplicate(
+ concat([[0,0]], xings, [[len(path)-1,1]]),
+ eps=eps
+ ),
+ subpaths = [
+ for (p = pair(crossings))
+ deduplicate(eps=eps,
+ path_subselect(path, p[0][0], p[0][1], p[1][0], p[1][1], closed=closed)
+ )
+ ]
+ )
+ subpaths;
// Function: split_nested_region()
@@ -196,75 +196,75 @@ function split_path_at_region_crossings(path, region, closed=true, eps=EPSILON)
// Returns a list of regions, such that each returned region has exactly one positive outline
// and zero or more void outlines.
function split_nested_region(region) =
- let(
- paths = sort(idx=0, [
- for(i = idx(region)) let(
- cnt = sum([
- for (j = idx(region)) if (i!=j)
- let(pt = lerp(region[i][0],region[i][1],0.5))
- point_in_polygon(pt, region[j]) >=0 ? 1 : 0
- ])
- ) [cnt, region[i]]
- ]),
- outs = [
- for (candout = paths) let(
- lev = candout[0],
- parent = candout[1]
- ) if (lev % 2 == 0) [
- clockwise_polygon(parent),
- for (path = paths) if (
- path[0] == lev+1 &&
- point_in_polygon(
- lerp(path[1][0], path[1][1], 0.5),
- parent
- ) >= 0
- ) ccw_polygon(path[1])
- ]
- ]
- ) outs;
+ let(
+ paths = sort(idx=0, [
+ for(i = idx(region)) let(
+ cnt = sum([
+ for (j = idx(region)) if (i!=j)
+ let(pt = lerp(region[i][0],region[i][1],0.5))
+ point_in_polygon(pt, region[j]) >=0 ? 1 : 0
+ ])
+ ) [cnt, region[i]]
+ ]),
+ outs = [
+ for (candout = paths) let(
+ lev = candout[0],
+ parent = candout[1]
+ ) if (lev % 2 == 0) [
+ clockwise_polygon(parent),
+ for (path = paths) if (
+ path[0] == lev+1 &&
+ point_in_polygon(
+ lerp(path[1][0], path[1][1], 0.5),
+ parent
+ ) >= 0
+ ) ccw_polygon(path[1])
+ ]
+ ]
+ ) outs;
// Section: Region Extrusion and VNFs
function _path_path_closest_vertices(path1,path2) =
- let(
- dists = [for (i=idx(path1)) let(j=closest_point(path1[i],path2)) [j,norm(path2[j]-path1[i])]],
- i1 = min_index(subindex(dists,1)),
- i2 = dists[i1][0]
- ) [dists[i1][1], i1, i2];
+ let(
+ dists = [for (i=idx(path1)) let(j=closest_point(path1[i],path2)) [j,norm(path2[j]-path1[i])]],
+ i1 = min_index(subindex(dists,1)),
+ i2 = dists[i1][0]
+ ) [dists[i1][1], i1, i2];
function _join_paths_at_vertices(path1,path2,seg1,seg2) =
- let(
- path1 = close_path(clockwise_polygon(polygon_shift(path1, seg1))),
- path2 = close_path(ccw_polygon(polygon_shift(path2, seg2)))
- ) cleanup_path(deduplicate([each path1, each path2]));
+ let(
+ path1 = close_path(clockwise_polygon(polygon_shift(path1, seg1))),
+ path2 = close_path(ccw_polygon(polygon_shift(path2, seg2)))
+ ) cleanup_path(deduplicate([each path1, each path2]));
function _cleave_simple_region(region) =
- len(region)==0? [] :
- len(region)<=1? clockwise_polygon(region[0]) :
- let(
- dists = [
- for (i=[1:1:len(region)-1])
- _path_path_closest_vertices(region[0],region[i])
- ],
- idxi = min_index(subindex(dists,0)),
- newoline = _join_paths_at_vertices(
- region[0], region[idxi+1],
- dists[idxi][1], dists[idxi][2]
- )
- ) len(region)==2? clockwise_polygon(newoline) :
- let(
- orgn = [
- newoline,
- for (i=idx(region))
- if (i>0 && i!=idxi+1)
- region[i]
- ]
- )
- assert(len(orgn)0 && i!=idxi+1)
+ region[i]
+ ]
+ )
+ assert(len(orgn)maxind)? true :
- _segment_good(path,pathseg_unit,pathseg_len, d - 1e-7, shiftsegs[i], alpha)
- ];
+ let(
+ maxind = len(path)-(closed ? 1 : 2),
+ pathseg = [for(i=[0:maxind]) select(path,i+1)-path[i]],
+ pathseg_len = [for(seg=pathseg) norm(seg)],
+ pathseg_unit = [for(i=[0:maxind]) pathseg[i]/pathseg_len[i]],
+ // Order matters because as soon as a valid point is found, the test stops
+ // This order works better for circular paths because they succeed in the center
+ alpha = concat([for(i=[1:1:quality]) i/(quality+1)],[0,1])
+ ) [
+ for (i=[0:len(shiftsegs)-1])
+ (i>maxind)? true :
+ _segment_good(path,pathseg_unit,pathseg_len, d - 1e-7, shiftsegs[i], alpha)
+ ];
// Determine if a segment is good (approximately)
@@ -486,60 +486,60 @@ function _good_segments(path, d, shiftsegs, closed, quality) =
// This test is approximate because it only samples the points listed in alpha. Listing more points
// will make the test more accurate, but slower.
function _segment_good(path,pathseg_unit,pathseg_len, d, seg,alpha ,index=0) =
- index == len(alpha) ? false :
- _point_dist(path,pathseg_unit,pathseg_len, alpha[index]*seg[0]+(1-alpha[index])*seg[1]) > d ? true :
- _segment_good(path,pathseg_unit,pathseg_len,d,seg,alpha,index+1);
+ index == len(alpha) ? false :
+ _point_dist(path,pathseg_unit,pathseg_len, alpha[index]*seg[0]+(1-alpha[index])*seg[1]) > d ? true :
+ _segment_good(path,pathseg_unit,pathseg_len,d,seg,alpha,index+1);
// Input is the path, the path segments normalized to unit length, the length of each path segment
// and a test point. Computes the (minimum) distance from the path to the point, taking into
// account that the minimal distance may be anywhere along a path segment, not just at the ends.
function _point_dist(path,pathseg_unit,pathseg_len,pt) =
- min([
- for(i=[0:len(pathseg_unit)-1]) let(
- v = pt-path[i],
- projection = v*pathseg_unit[i],
- segdist = projection < 0? norm(pt-path[i]) :
- projection > pathseg_len[i]? norm(pt-select(path,i+1)) :
- norm(v-projection*pathseg_unit[i])
- ) segdist
- ]);
+ min([
+ for(i=[0:len(pathseg_unit)-1]) let(
+ v = pt-path[i],
+ projection = v*pathseg_unit[i],
+ segdist = projection < 0? norm(pt-path[i]) :
+ projection > pathseg_len[i]? norm(pt-select(path,i+1)) :
+ norm(v-projection*pathseg_unit[i])
+ ) segdist
+ ]);
function _offset_region(
- paths, r, delta, chamfer, closed,
- maxstep, check_valid, quality,
- return_faces, firstface_index,
- flip_faces, _acc=[], _i=0
+ paths, r, delta, chamfer, closed,
+ maxstep, check_valid, quality,
+ return_faces, firstface_index,
+ flip_faces, _acc=[], _i=0
) =
- _i>=len(paths)? _acc :
- _offset_region(
- paths, _i=_i+1,
- _acc = (paths[_i].x % 2 == 0)? (
- union(_acc, [
- offset(
- paths[_i].y,
- r=r, delta=delta, chamfer=chamfer, closed=closed,
- maxstep=maxstep, check_valid=check_valid, quality=quality,
- return_faces=return_faces, firstface_index=firstface_index,
- flip_faces=flip_faces
- )
- ])
- ) : (
- difference(_acc, [
- offset(
- paths[_i].y,
- r=-r, delta=-delta, chamfer=chamfer, closed=closed,
- maxstep=maxstep, check_valid=check_valid, quality=quality,
- return_faces=return_faces, firstface_index=firstface_index,
- flip_faces=flip_faces
- )
- ])
- ),
- r=r, delta=delta, chamfer=chamfer, closed=closed,
- maxstep=maxstep, check_valid=check_valid, quality=quality,
- return_faces=return_faces, firstface_index=firstface_index, flip_faces=flip_faces
- );
+ _i>=len(paths)? _acc :
+ _offset_region(
+ paths, _i=_i+1,
+ _acc = (paths[_i].x % 2 == 0)? (
+ union(_acc, [
+ offset(
+ paths[_i].y,
+ r=r, delta=delta, chamfer=chamfer, closed=closed,
+ maxstep=maxstep, check_valid=check_valid, quality=quality,
+ return_faces=return_faces, firstface_index=firstface_index,
+ flip_faces=flip_faces
+ )
+ ])
+ ) : (
+ difference(_acc, [
+ offset(
+ paths[_i].y,
+ r=-r, delta=-delta, chamfer=chamfer, closed=closed,
+ maxstep=maxstep, check_valid=check_valid, quality=quality,
+ return_faces=return_faces, firstface_index=firstface_index,
+ flip_faces=flip_faces
+ )
+ ])
+ ),
+ r=r, delta=delta, chamfer=chamfer, closed=closed,
+ maxstep=maxstep, check_valid=check_valid, quality=quality,
+ return_faces=return_faces, firstface_index=firstface_index, flip_faces=flip_faces
+ );
// Function: offset()
@@ -635,162 +635,162 @@ function _offset_region(
// #linear_extrude(height=1.1) for (p=rgn) stroke(closed=true, width=0.5, p);
// region(offset(rgn, r=-5));
function offset(
- path, r=undef, delta=undef, chamfer=false,
- maxstep=0.1, closed=false, check_valid=true,
- quality=1, return_faces=false, firstface_index=0,
- flip_faces=false
+ path, r=undef, delta=undef, chamfer=false,
+ maxstep=0.1, closed=false, check_valid=true,
+ quality=1, return_faces=false, firstface_index=0,
+ flip_faces=false
) =
- is_region(path)? (
- assert(!return_faces, "return_faces not supported for regions.")
- let(
- path = [for (p=path) polygon_is_clockwise(p)? p : reverse(p)],
- rgn = exclusive_or([for (p = path) [p]]),
- pathlist = sort(idx=0,[
- for (i=[0:1:len(rgn)-1]) [
- sum(concat([0],[
- for (j=[0:1:len(rgn)-1]) if (i!=j)
- point_in_polygon(rgn[i][0],rgn[j])>=0? 1 : 0
- ])),
- rgn[i]
- ]
- ])
- ) _offset_region(
- pathlist, r=r, delta=delta, chamfer=chamfer, closed=true,
- maxstep=maxstep, check_valid=check_valid, quality=quality,
- return_faces=return_faces, firstface_index=firstface_index,
- flip_faces=flip_faces
- )
- ) : let(rcount = num_defined([r,delta]))
- assert(rcount==1,"Must define exactly one of 'delta' and 'r'")
- let(
- chamfer = is_def(r) ? false : chamfer,
- quality = max(0,round(quality)),
- flip_dir = closed && !polygon_is_clockwise(path)? -1 : 1,
- d = flip_dir * (is_def(r) ? r : delta),
- shiftsegs = [for(i=[0:len(path)-1]) _shift_segment(select(path,i,i+1), d)],
- // good segments are ones where no point on the segment is less than distance d from any point on the path
- good = check_valid ? _good_segments(path, abs(d), shiftsegs, closed, quality) : repeat(true,len(shiftsegs)),
- goodsegs = bselect(shiftsegs, good),
- goodpath = bselect(path,good)
- )
- assert(len(goodsegs)>0,"Offset of path is degenerate")
- let(
- // Extend the shifted segments to their intersection points
- sharpcorners = [for(i=[0:len(goodsegs)-1]) _segment_extension(select(goodsegs,i-1), select(goodsegs,i))],
- // If some segments are parallel then the extended segments are undefined. This case is not handled
- // Note if !closed the last corner doesn't matter, so exclude it
- parallelcheck =
- (len(sharpcorners)==2 && !closed) ||
- all_defined(select(sharpcorners,closed?0:1,-1))
- )
- assert(parallelcheck, "Path turns back on itself (180 deg turn)")
- let(
- // This is a boolean array that indicates whether a corner is an outside or inside corner
- // For outside corners, the newcorner is an extension (angle 0), for inside corners, it turns backward
- // If either side turns back it is an inside corner---must check both.
- // Outside corners can get rounded (if r is specified and there is space to round them)
- outsidecorner = [
- for(i=[0:len(goodsegs)-1]) let(
- prevseg=select(goodsegs,i-1)
- ) (
- (goodsegs[i][1]-goodsegs[i][0]) *
- (goodsegs[i][0]-sharpcorners[i]) > 0
- ) && (
- (prevseg[1]-prevseg[0]) *
- (sharpcorners[i]-prevseg[1]) > 0
- )
- ],
- steps = is_def(delta) ? [] : [
- for(i=[0:len(goodsegs)-1])
+ is_region(path)? (
+ assert(!return_faces, "return_faces not supported for regions.")
+ let(
+ path = [for (p=path) polygon_is_clockwise(p)? p : reverse(p)],
+ rgn = exclusive_or([for (p = path) [p]]),
+ pathlist = sort(idx=0,[
+ for (i=[0:1:len(rgn)-1]) [
+ sum(concat([0],[
+ for (j=[0:1:len(rgn)-1]) if (i!=j)
+ point_in_polygon(rgn[i][0],rgn[j])>=0? 1 : 0
+ ])),
+ rgn[i]
+ ]
+ ])
+ ) _offset_region(
+ pathlist, r=r, delta=delta, chamfer=chamfer, closed=true,
+ maxstep=maxstep, check_valid=check_valid, quality=quality,
+ return_faces=return_faces, firstface_index=firstface_index,
+ flip_faces=flip_faces
+ )
+ ) : let(rcount = num_defined([r,delta]))
+ assert(rcount==1,"Must define exactly one of 'delta' and 'r'")
+ let(
+ chamfer = is_def(r) ? false : chamfer,
+ quality = max(0,round(quality)),
+ flip_dir = closed && !polygon_is_clockwise(path)? -1 : 1,
+ d = flip_dir * (is_def(r) ? r : delta),
+ shiftsegs = [for(i=[0:len(path)-1]) _shift_segment(select(path,i,i+1), d)],
+ // good segments are ones where no point on the segment is less than distance d from any point on the path
+ good = check_valid ? _good_segments(path, abs(d), shiftsegs, closed, quality) : repeat(true,len(shiftsegs)),
+ goodsegs = bselect(shiftsegs, good),
+ goodpath = bselect(path,good)
+ )
+ assert(len(goodsegs)>0,"Offset of path is degenerate")
+ let(
+ // Extend the shifted segments to their intersection points
+ sharpcorners = [for(i=[0:len(goodsegs)-1]) _segment_extension(select(goodsegs,i-1), select(goodsegs,i))],
+ // If some segments are parallel then the extended segments are undefined. This case is not handled
+ // Note if !closed the last corner doesn't matter, so exclude it
+ parallelcheck =
+ (len(sharpcorners)==2 && !closed) ||
+ all_defined(select(sharpcorners,closed?0:1,-1))
+ )
+ assert(parallelcheck, "Path turns back on itself (180 deg turn)")
+ let(
+ // This is a boolean array that indicates whether a corner is an outside or inside corner
+ // For outside corners, the newcorner is an extension (angle 0), for inside corners, it turns backward
+ // If either side turns back it is an inside corner---must check both.
+ // Outside corners can get rounded (if r is specified and there is space to round them)
+ outsidecorner = [
+ for(i=[0:len(goodsegs)-1]) let(
+ prevseg=select(goodsegs,i-1)
+ ) (
+ (goodsegs[i][1]-goodsegs[i][0]) *
+ (goodsegs[i][0]-sharpcorners[i]) > 0
+ ) && (
+ (prevseg[1]-prevseg[0]) *
+ (sharpcorners[i]-prevseg[1]) > 0
+ )
+ ],
+ steps = is_def(delta) ? [] : [
+ for(i=[0:len(goodsegs)-1])
r==0 ? 0 :
- ceil(
- abs(r)*vector_angle(
- select(goodsegs,i-1)[1]-goodpath[i],
- goodsegs[i][0]-goodpath[i]
- )*PI/180/maxstep
- )
- ],
- // If rounding is true then newcorners replaces sharpcorners with rounded arcs where needed
- // Otherwise it's the same as sharpcorners
- // If rounding is on then newcorners[i] will be the point list that replaces goodpath[i] and newcorners later
- // gets flattened. If rounding is off then we set it to [sharpcorners] so we can later flatten it and get
- // plain sharpcorners back.
- newcorners = is_def(delta) && !chamfer ? [sharpcorners] : [
- for(i=[0:len(goodsegs)-1]) (
- (!chamfer && steps[i] <=2) //Chamfer all points but only round if steps is 3 or more
- || !outsidecorner[i] // Don't round inside corners
- || (!closed && (i==0 || i==len(goodsegs)-1)) // Don't round ends of an open path
- )? [sharpcorners[i]] : (
- chamfer?
- _offset_chamfer(
- goodpath[i], [
- select(goodsegs,i-1)[1],
- sharpcorners[i],
- goodsegs[i][0]
- ], d
- ) :
- arc(
- cp=goodpath[i],
- points=[
- select(goodsegs,i-1)[1],
- goodsegs[i][0]
- ],
- N=steps[i]
- )
- )
- ],
- pointcount = (is_def(delta) && !chamfer)?
- repeat(1,len(sharpcorners)) :
- [for(i=[0:len(goodsegs)-1]) len(newcorners[i])],
- start = [goodsegs[0][0]],
- end = [goodsegs[len(goodsegs)-2][1]],
- edges = closed?
- flatten(newcorners) :
- concat(start,slice(flatten(newcorners),1,-2),end),
- faces = !return_faces? [] :
- _makefaces(
- flip_faces, firstface_index, good,
- pointcount, closed
- )
- ) return_faces? [edges,faces] : edges;
+ ceil(
+ abs(r)*vector_angle(
+ select(goodsegs,i-1)[1]-goodpath[i],
+ goodsegs[i][0]-goodpath[i]
+ )*PI/180/maxstep
+ )
+ ],
+ // If rounding is true then newcorners replaces sharpcorners with rounded arcs where needed
+ // Otherwise it's the same as sharpcorners
+ // If rounding is on then newcorners[i] will be the point list that replaces goodpath[i] and newcorners later
+ // gets flattened. If rounding is off then we set it to [sharpcorners] so we can later flatten it and get
+ // plain sharpcorners back.
+ newcorners = is_def(delta) && !chamfer ? [sharpcorners] : [
+ for(i=[0:len(goodsegs)-1]) (
+ (!chamfer && steps[i] <=2) //Chamfer all points but only round if steps is 3 or more
+ || !outsidecorner[i] // Don't round inside corners
+ || (!closed && (i==0 || i==len(goodsegs)-1)) // Don't round ends of an open path
+ )? [sharpcorners[i]] : (
+ chamfer?
+ _offset_chamfer(
+ goodpath[i], [
+ select(goodsegs,i-1)[1],
+ sharpcorners[i],
+ goodsegs[i][0]
+ ], d
+ ) :
+ arc(
+ cp=goodpath[i],
+ points=[
+ select(goodsegs,i-1)[1],
+ goodsegs[i][0]
+ ],
+ N=steps[i]
+ )
+ )
+ ],
+ pointcount = (is_def(delta) && !chamfer)?
+ repeat(1,len(sharpcorners)) :
+ [for(i=[0:len(goodsegs)-1]) len(newcorners[i])],
+ start = [goodsegs[0][0]],
+ end = [goodsegs[len(goodsegs)-2][1]],
+ edges = closed?
+ flatten(newcorners) :
+ concat(start,slice(flatten(newcorners),1,-2),end),
+ faces = !return_faces? [] :
+ _makefaces(
+ flip_faces, firstface_index, good,
+ pointcount, closed
+ )
+ ) return_faces? [edges,faces] : edges;
function _tag_subpaths(path, region, eps=EPSILON) =
- let(
- subpaths = split_path_at_region_crossings(path, region, eps=eps),
- tagged = [
- for (sub = subpaths) let(
- subpath = deduplicate(sub)
- ) if (len(sub)>1) let(
- midpt = lerp(subpath[0], subpath[1], 0.5),
- rel = point_in_region(midpt,region,eps=eps)
- ) rel<0? ["O", subpath] : rel>0? ["I", subpath] : let(
- vec = unit(subpath[1]-subpath[0]),
- perp = rot(90, planar=true, p=vec),
- sidept = midpt + perp*0.01,
- rel1 = point_in_polygon(sidept,path,eps=eps)>0,
- rel2 = point_in_region(sidept,region,eps=eps)>0
- ) rel1==rel2? ["S", subpath] : ["U", subpath]
- ]
- ) tagged;
+ let(
+ subpaths = split_path_at_region_crossings(path, region, eps=eps),
+ tagged = [
+ for (sub = subpaths) let(
+ subpath = deduplicate(sub)
+ ) if (len(sub)>1) let(
+ midpt = lerp(subpath[0], subpath[1], 0.5),
+ rel = point_in_region(midpt,region,eps=eps)
+ ) rel<0? ["O", subpath] : rel>0? ["I", subpath] : let(
+ vec = unit(subpath[1]-subpath[0]),
+ perp = rot(90, planar=true, p=vec),
+ sidept = midpt + perp*0.01,
+ rel1 = point_in_polygon(sidept,path,eps=eps)>0,
+ rel2 = point_in_region(sidept,region,eps=eps)>0
+ ) rel1==rel2? ["S", subpath] : ["U", subpath]
+ ]
+ ) tagged;
function _tag_region_subpaths(region1, region2, eps=EPSILON) =
- [for (path=region1) each _tag_subpaths(path, region2, eps=eps)];
+ [for (path=region1) each _tag_subpaths(path, region2, eps=eps)];
function _tagged_region(region1,region2,keep1,keep2,eps=EPSILON) =
- let(
- region1 = close_region(region1, eps=eps),
- region2 = close_region(region2, eps=eps),
- tagged1 = _tag_region_subpaths(region1, region2, eps=eps),
- tagged2 = _tag_region_subpaths(region2, region1, eps=eps),
- tagged = concat(
- [for (tagpath = tagged1) if (in_list(tagpath[0], keep1)) tagpath[1]],
- [for (tagpath = tagged2) if (in_list(tagpath[0], keep2)) tagpath[1]]
- ),
- outregion = assemble_path_fragments(tagged, eps=eps)
- ) outregion;
+ let(
+ region1 = close_region(region1, eps=eps),
+ region2 = close_region(region2, eps=eps),
+ tagged1 = _tag_region_subpaths(region1, region2, eps=eps),
+ tagged2 = _tag_region_subpaths(region2, region1, eps=eps),
+ tagged = concat(
+ [for (tagpath = tagged1) if (in_list(tagpath[0], keep1)) tagpath[1]],
+ [for (tagpath = tagged2) if (in_list(tagpath[0], keep2)) tagpath[1]]
+ ),
+ outregion = assemble_path_fragments(tagged, eps=eps)
+ ) outregion;
@@ -812,16 +812,16 @@ function _tagged_region(region1,region2,keep1,keep2,eps=EPSILON) =
// for (shape = [shape1,shape2]) color("red") stroke(shape, width=0.5, closed=true);
// color("green") region(union(shape1,shape2));
function union(regions=[],b=undef,c=undef,eps=EPSILON) =
- b!=undef? union(concat([regions],[b],c==undef?[]:[c]), eps=eps) :
- len(regions)<=1? regions[0] :
- union(
- let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
- concat(
- [_tagged_region(regions[0],regions[1],["O","S"],["O"], eps=eps)],
- [for (i=[2:1:len(regions)-1]) regions[i]]
- ),
- eps=eps
- );
+ b!=undef? union(concat([regions],[b],c==undef?[]:[c]), eps=eps) :
+ len(regions)<=1? regions[0] :
+ union(
+ let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
+ concat(
+ [_tagged_region(regions[0],regions[1],["O","S"],["O"], eps=eps)],
+ [for (i=[2:1:len(regions)-1]) regions[i]]
+ ),
+ eps=eps
+ );
// Function&Module: difference()
@@ -843,16 +843,16 @@ function union(regions=[],b=undef,c=undef,eps=EPSILON) =
// for (shape = [shape1,shape2]) color("red") stroke(shape, width=0.5, closed=true);
// color("green") region(difference(shape1,shape2));
function difference(regions=[],b=undef,c=undef,eps=EPSILON) =
- b!=undef? difference(concat([regions],[b],c==undef?[]:[c]), eps=eps) :
- len(regions)<=1? regions[0] :
- difference(
- let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
- concat(
- [_tagged_region(regions[0],regions[1],["O","U"],["I"], eps=eps)],
- [for (i=[2:1:len(regions)-1]) regions[i]]
- ),
- eps=eps
- );
+ b!=undef? difference(concat([regions],[b],c==undef?[]:[c]), eps=eps) :
+ len(regions)<=1? regions[0] :
+ difference(
+ let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
+ concat(
+ [_tagged_region(regions[0],regions[1],["O","U"],["I"], eps=eps)],
+ [for (i=[2:1:len(regions)-1]) regions[i]]
+ ),
+ eps=eps
+ );
// Function&Module: intersection()
@@ -873,16 +873,16 @@ function difference(regions=[],b=undef,c=undef,eps=EPSILON) =
// for (shape = [shape1,shape2]) color("red") stroke(shape, width=0.5, closed=true);
// color("green") region(intersection(shape1,shape2));
function intersection(regions=[],b=undef,c=undef,eps=EPSILON) =
- b!=undef? intersection(concat([regions],[b],c==undef?[]:[c]),eps=eps) :
- len(regions)<=1? regions[0] :
- intersection(
- let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
- concat(
- [_tagged_region(regions[0],regions[1],["I","S"],["I"],eps=eps)],
- [for (i=[2:1:len(regions)-1]) regions[i]]
- ),
- eps=eps
- );
+ b!=undef? intersection(concat([regions],[b],c==undef?[]:[c]),eps=eps) :
+ len(regions)<=1? regions[0] :
+ intersection(
+ let(regions=[for (r=regions) quant(is_path(r)? [r] : r, 1/65536)])
+ concat(
+ [_tagged_region(regions[0],regions[1],["I","S"],["I"],eps=eps)],
+ [for (i=[2:1:len(regions)-1]) regions[i]]
+ ),
+ eps=eps
+ );
// Function&Module: exclusive_or()
@@ -909,137 +909,137 @@ function intersection(regions=[],b=undef,c=undef,eps=EPSILON) =
// circle(d=40);
// }
function exclusive_or(regions=[],b=undef,c=undef,eps=EPSILON) =
- b!=undef? exclusive_or(concat([regions],[b],c==undef?[]:[c]),eps=eps) :
- len(regions)<=1? regions[0] :
- exclusive_or(
- let(regions=[for (r=regions) is_path(r)? [r] : r])
- concat(
- [union([
- difference([regions[0],regions[1]], eps=eps),
- difference([regions[1],regions[0]], eps=eps)
- ], eps=eps)],
- [for (i=[2:1:len(regions)-1]) regions[i]]
- ),
- eps=eps
- );
+ b!=undef? exclusive_or(concat([regions],[b],c==undef?[]:[c]),eps=eps) :
+ len(regions)<=1? regions[0] :
+ exclusive_or(
+ let(regions=[for (r=regions) is_path(r)? [r] : r])
+ concat(
+ [union([
+ difference([regions[0],regions[1]], eps=eps),
+ difference([regions[1],regions[0]], eps=eps)
+ ], eps=eps)],
+ [for (i=[2:1:len(regions)-1]) regions[i]]
+ ),
+ eps=eps
+ );
module exclusive_or() {
- if ($children==1) {
- children();
- } else if ($children==2) {
- difference() {
- children(0);
- children(1);
- }
- difference() {
- children(1);
- children(0);
- }
- } else if ($children==3) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- }
- children(2);
- }
- } else if ($children==4) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- }
- exclusive_or() {
- children(2);
- children(3);
- }
- }
- } else if ($children==5) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- children(4);
- }
- } else if ($children==6) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- children(4);
- children(5);
- }
- } else if ($children==7) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- children(4);
- children(5);
- children(6);
- }
- } else if ($children==8) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- exclusive_or() {
- children(4);
- children(5);
- children(6);
- children(7);
- }
- }
- } else if ($children==9) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- exclusive_or() {
- children(4);
- children(5);
- children(6);
- children(7);
- }
- children(8);
- }
- } else if ($children==10) {
- exclusive_or() {
- exclusive_or() {
- children(0);
- children(1);
- children(2);
- children(3);
- }
- exclusive_or() {
- children(4);
- children(5);
- children(6);
- children(7);
- }
- children(8);
- children(9);
- }
- } else {
- assert($children<=10, "exclusive_or() can only handle up to 10 children.");
- }
+ if ($children==1) {
+ children();
+ } else if ($children==2) {
+ difference() {
+ children(0);
+ children(1);
+ }
+ difference() {
+ children(1);
+ children(0);
+ }
+ } else if ($children==3) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ }
+ children(2);
+ }
+ } else if ($children==4) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ }
+ exclusive_or() {
+ children(2);
+ children(3);
+ }
+ }
+ } else if ($children==5) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ children(4);
+ }
+ } else if ($children==6) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ children(4);
+ children(5);
+ }
+ } else if ($children==7) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ children(4);
+ children(5);
+ children(6);
+ }
+ } else if ($children==8) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ exclusive_or() {
+ children(4);
+ children(5);
+ children(6);
+ children(7);
+ }
+ }
+ } else if ($children==9) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ exclusive_or() {
+ children(4);
+ children(5);
+ children(6);
+ children(7);
+ }
+ children(8);
+ }
+ } else if ($children==10) {
+ exclusive_or() {
+ exclusive_or() {
+ children(0);
+ children(1);
+ children(2);
+ children(3);
+ }
+ exclusive_or() {
+ children(4);
+ children(5);
+ children(6);
+ children(7);
+ }
+ children(8);
+ children(9);
+ }
+ } else {
+ assert($children<=10, "exclusive_or() can only handle up to 10 children.");
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/rounding.scad b/rounding.scad
index 266318e..e890ddc 100644
--- a/rounding.scad
+++ b/rounding.scad
@@ -1548,10 +1548,10 @@ function rounded_prism(bottom, top, joint_bot, joint_top, joint_sides, k_bot, k_
if (norm(top[i]-top_patch[i][4][2]) + norm(bottom[i]-bot_patch[i][4][2]) > norm(bottom[i]-top[i])) i],
topbad = [for(i=[0:N-1])
if (norm(top_patch[i][2][4]-top_patch[i][2][2]) + norm(select(top_patch,i+1)[2][0]-select(top_patch,i+1)[2][2])
- > norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
+ > norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
botbad = [for(i=[0:N-1])
if (norm(bot_patch[i][2][4]-bot_patch[i][2][2]) + norm(select(bot_patch,i+1)[2][0]-select(bot_patch,i+1)[2][2])
- > norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
+ > norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
topinbad = [for(i=[0:N-1])
if (norm(top_patch[i][0][2]-top_patch[i][0][4]) + norm(select(top_patch,i+1)[0][0]-select(top_patch,i+1)[0][2])
> norm(top_patch[i][0][2]-select(top_patch,i+1)[0][2])) [i,(i+1)%N]],
@@ -1619,7 +1619,7 @@ function rounded_prism(bottom, top, joint_bot, joint_top, joint_sides, k_bot, k_
each subindex(bot_samples,1),
for(pts=edge_points) vnf_vertex_array(pts),
vnf_triangulate(vnf_add_faces(EMPTY_VNF,faces))
- ])
+ ])
)
debug ? [concat(top_patch, bot_patch), vnf] : vnf;
@@ -1942,4 +1942,4 @@ module bent_cutout_mask(r, thickness, path, convexity=10)
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/screws.scad b/screws.scad
index 58d799d..c9e9a57 100644
--- a/screws.scad
+++ b/screws.scad
@@ -493,55 +493,55 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
tind=struct_val([["coarse",0],
["fine",1],
["extra fine",2],["extrafine",2],
- ["super fine",3],["superfine",3]],
+ ["super fine",3],["superfine",3]],
downcase(thread)),
// coarse fine xfine superfine
ISO_thread = [
- [1 , [0.25, 0.2 , undef, undef,]],
- [1.2, [0.25, 0.2 , undef, undef,]],
- [1.4, [0.3 , 0.2 , undef, undef,]],
- [1.6, [0.35, 0.2 , undef, undef,]],
- [1.7, [0.35, undef, undef, undef,]],
- [1.8, [0.35, 0.2 , undef, undef,]],
- [2 , [0.4 , 0.25, undef, undef,]],
- [2.2, [0.45, 0.25, undef, undef,]],
- [2.3, [0.4 , undef, undef, undef,]],
- [2.5, [0.45, 0.35, undef, undef,]],
- [2.6, [0.45, undef, undef, undef,]],
- [3 , [0.5 , 0.35, undef, undef,]],
- [3.5, [0.6 , 0.35, undef, undef,]],
- [4 , [0.7 , 0.5 , undef, undef,]],
- [5 , [0.8 , 0.5 , undef, undef,]],
- [6 , [1 , 0.75, undef, undef,]],
- [7 , [1 , 0.75, undef, undef,]],
- [8 , [1.25, 1 , 0.75, undef,]],
- [9 , [1.25, 1 , 0.75, undef,]],
- [10 , [1.5 , 1.25, 1 , 0.75,]],
- [11 , [1.5 , 1 , 0.75, undef,]],
- [12 , [1.75, 1.5 , 1.25, 1, ]],
- [14 , [2 , 1.5 , 1.25, 1, ]],
- [16 , [2 , 1.5 , 1 , undef,]],
- [18 , [2.5 , 2 , 1.5 , 1, ]],
- [20 , [2.5 , 2 , 1.5 , 1, ]],
- [22 , [2.5 , 2 , 1.5 , 1,]],
- [24 , [3 , 2 , 1.5 , 1,]],
- [27 , [3 , 2 , 1.5 , 1,]],
- [30 , [3.5 , 3 , 2 , 1.5,]],
- [33 , [3.5 , 3 , 2 , 1.5,]],
- [36 , [4 , 3 , 2 , 1.5,]],
- [39 , [4 , 3 , 2 , 1.5,]],
- [42 , [4.5 , 4 , 3 , 2,]],
- [45 , [4.5 , 4 , 3 , 2,]],
- [48 , [5 , 4 , 3 , 2,]],
- [52 , [5 , 4 , 3 , 2,]],
- [56 , [5.5 , 4 , 3 , 2,]],
- [60 , [5.5 , 4 , 3 , 2,]],
- [64 , [6 , 4 , 3 , 2,]],
- [68 , [6 , 4 , 3 , 2,]],
- [72 , [6 , 4 , 3 , 2,]],
- [80 , [6 , 4 , 3 , 2,]],
- [90 , [6 , 4 , 3 , 2,]],
- [100, [6 , 4 , 3 , 2,]],
+ [1 , [0.25, 0.2 , undef, undef,]],
+ [1.2, [0.25, 0.2 , undef, undef,]],
+ [1.4, [0.3 , 0.2 , undef, undef,]],
+ [1.6, [0.35, 0.2 , undef, undef,]],
+ [1.7, [0.35, undef, undef, undef,]],
+ [1.8, [0.35, 0.2 , undef, undef,]],
+ [2 , [0.4 , 0.25, undef, undef,]],
+ [2.2, [0.45, 0.25, undef, undef,]],
+ [2.3, [0.4 , undef, undef, undef,]],
+ [2.5, [0.45, 0.35, undef, undef,]],
+ [2.6, [0.45, undef, undef, undef,]],
+ [3 , [0.5 , 0.35, undef, undef,]],
+ [3.5, [0.6 , 0.35, undef, undef,]],
+ [4 , [0.7 , 0.5 , undef, undef,]],
+ [5 , [0.8 , 0.5 , undef, undef,]],
+ [6 , [1 , 0.75, undef, undef,]],
+ [7 , [1 , 0.75, undef, undef,]],
+ [8 , [1.25, 1 , 0.75, undef,]],
+ [9 , [1.25, 1 , 0.75, undef,]],
+ [10 , [1.5 , 1.25, 1 , 0.75,]],
+ [11 , [1.5 , 1 , 0.75, undef,]],
+ [12 , [1.75, 1.5 , 1.25, 1, ]],
+ [14 , [2 , 1.5 , 1.25, 1, ]],
+ [16 , [2 , 1.5 , 1 , undef,]],
+ [18 , [2.5 , 2 , 1.5 , 1, ]],
+ [20 , [2.5 , 2 , 1.5 , 1, ]],
+ [22 , [2.5 , 2 , 1.5 , 1,]],
+ [24 , [3 , 2 , 1.5 , 1,]],
+ [27 , [3 , 2 , 1.5 , 1,]],
+ [30 , [3.5 , 3 , 2 , 1.5,]],
+ [33 , [3.5 , 3 , 2 , 1.5,]],
+ [36 , [4 , 3 , 2 , 1.5,]],
+ [39 , [4 , 3 , 2 , 1.5,]],
+ [42 , [4.5 , 4 , 3 , 2,]],
+ [45 , [4.5 , 4 , 3 , 2,]],
+ [48 , [5 , 4 , 3 , 2,]],
+ [52 , [5 , 4 , 3 , 2,]],
+ [56 , [5.5 , 4 , 3 , 2,]],
+ [60 , [5.5 , 4 , 3 , 2,]],
+ [64 , [6 , 4 , 3 , 2,]],
+ [68 , [6 , 4 , 3 , 2,]],
+ [72 , [6 , 4 , 3 , 2,]],
+ [80 , [6 , 4 , 3 , 2,]],
+ [90 , [6 , 4 , 3 , 2,]],
+ [100, [6 , 4 , 3 , 2,]],
]
)
struct_val(ISO_thread, diam)[tind],
@@ -550,19 +550,19 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
metric_setscrew =
[
[1.4, [0.7]],
- [1.6, [0.7]],
- [1.8, [0.7]],
- [2, [0.9]],
- [2.5, [1.3]],
- [3, [1.5, 6, 0.77]],
- [4, [2, 8, 1.05]],
- [5, [2.5, 10, 1.24]],
- [6, [3, 15, 1.74]],
- [8, [4, 25, 2.24]],
- [10, [5, 40, 2.97]],
- [12, [6, 45, 3.48]],
- [16, [8, 55, 5.15]],
- [20, [10, undef, undef]],
+ [1.6, [0.7]],
+ [1.8, [0.7]],
+ [2, [0.9]],
+ [2.5, [1.3]],
+ [3, [1.5, 6, 0.77]],
+ [4, [2, 8, 1.05]],
+ [5, [2.5, 10, 1.24]],
+ [6, [3, 15, 1.74]],
+ [8, [4, 25, 2.24]],
+ [10, [5, 40, 2.97]],
+ [12, [6, 45, 3.48]],
+ [16, [8, 55, 5.15]],
+ [20, [10, undef, undef]],
],
entry = struct_val(metric_setscrew, diam),
drive_dim = drive=="hex" ? [["drive_size", entry[0]], ["drive_depth", diam/2]] :
@@ -572,17 +572,17 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
head=="hex" ? let(
metric_hex = [
// flat to flat width, height
- [5, [8, 3.5]],
- [6, [10,4]],
- [8, [13, 5.3]],
- [10, [17, 6.4]],
- [12, [19, 7.5]],
- [14, [22, 8.8]],
- [16, [24, 10]],
- [18, [27,11.5]],
- [20, [30, 12.5]],
- [24, [36, 15]],
- [30, [46, 18.7]],
+ [5, [8, 3.5]],
+ [6, [10,4]],
+ [8, [13, 5.3]],
+ [10, [17, 6.4]],
+ [12, [19, 7.5]],
+ [14, [22, 8.8]],
+ [16, [24, 10]],
+ [18, [27,11.5]],
+ [20, [30, 12.5]],
+ [24, [36, 15]],
+ [30, [46, 18.7]],
],
entry = struct_val(metric_hex, diam)
)
@@ -591,31 +591,31 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
metric_socket = [ // height = screw diameter
//diam, hex
[1.4, [2.5, 1.3]],
- [1.6, [3, 1.5]],
- [2, [3.8, 1.5, 6, 0.77]],
- [2.5, [4.5, 2, 8, 1.05]],
- [2.6, [5, 2, 8, 1.05]],
- [3, [5.5, 2.5, 10, 1.24]],
- [3.5, [6.2, 2.5]],
- [4, [7, 3, 25, 1.76]],
- [5, [8.5, 4, 27, 2.24]],
- [6, [10, 5, 30, 2.47]],
- [7, [12, 6]],
- [8, [13, 6, 45, 3.48]],
- [10, [16, 8, 50, 3.93]],
- [12, [18, 10, 55, 5.15]],
- [14, [21, 12]],
- [16, [24, 14, 70, 7.39]],
- [18, [27, 14]],
- [20, [30, 17, 90, 9.67]],
- [22, [33, 17]],
- [24, [36, 19, 100, 10.79]],
- [27, [40, 19]],
- [30, [45, 22]],
- [33, [50, 24]],
- [36, [54, 27]],
- [42, [63, 32]],
- [48, [72, 36]],
+ [1.6, [3, 1.5]],
+ [2, [3.8, 1.5, 6, 0.77]],
+ [2.5, [4.5, 2, 8, 1.05]],
+ [2.6, [5, 2, 8, 1.05]],
+ [3, [5.5, 2.5, 10, 1.24]],
+ [3.5, [6.2, 2.5]],
+ [4, [7, 3, 25, 1.76]],
+ [5, [8.5, 4, 27, 2.24]],
+ [6, [10, 5, 30, 2.47]],
+ [7, [12, 6]],
+ [8, [13, 6, 45, 3.48]],
+ [10, [16, 8, 50, 3.93]],
+ [12, [18, 10, 55, 5.15]],
+ [14, [21, 12]],
+ [16, [24, 14, 70, 7.39]],
+ [18, [27, 14]],
+ [20, [30, 17, 90, 9.67]],
+ [22, [33, 17]],
+ [24, [36, 19, 100, 10.79]],
+ [27, [40, 19]],
+ [30, [45, 22]],
+ [33, [50, 24]],
+ [36, [54, 27]],
+ [42, [63, 32]],
+ [48, [72, 36]],
],
entry = struct_val(metric_socket, diam),
drive_size = drive=="hex" ? [["drive_size",entry[1]],["drive_depth",diam/2]] :
@@ -626,16 +626,16 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
starts_with(head,"pan") ? let (
metric_pan = [ // pan head for phillips or slotted
// diam, slotted diam, phillips diam, phillips depth, ph width, slot width,slot depth
- [1.6,[3.2, 1 , 1.3, 0, undef,undef,undef, 0.4, 0.35]],
- [2, [4, 1.3, 1.6, 1, 1.82, 1.19, 0.48, 0.5, 0.5]],
- [2.5,[5, 1.5, 2, 1, 2.68, 1.53, 0.70, 0.6, 0.6]],
- [3, [5.6, 1.8, 2.4, 1, 2.90, 1.76, 0.74, 0.8, 0.7]],
- [3.5,[7, 2.1, 3.1, 2, 3.92, 1.95, 0.87, 1.0, 0.8]],
+ [1.6,[3.2, 1 , 1.3, 0, undef,undef,undef, 0.4, 0.35]],
+ [2, [4, 1.3, 1.6, 1, 1.82, 1.19, 0.48, 0.5, 0.5]],
+ [2.5,[5, 1.5, 2, 1, 2.68, 1.53, 0.70, 0.6, 0.6]],
+ [3, [5.6, 1.8, 2.4, 1, 2.90, 1.76, 0.74, 0.8, 0.7]],
+ [3.5,[7, 2.1, 3.1, 2, 3.92, 1.95, 0.87, 1.0, 0.8]],
[4, [8, 2.4 , 3.1, 2, 4.40, 2.45, 0.93, 1.2, 1.0]],
- [5, [9.5, 3, 3.8, 2, 4.90, 2.95, 1.00, 1.2, 1.2]],
- [6, [12, 3.6, 4.6, 3, 6.92, 3.81, 1.14, 1.6, 1.4]],
- [8, [16, 4.8, 6, 4, 9.02, 4.88, 1.69, 2.0, 1.9]],
- [10, [20, 6.0, 7.5, 4, 10.18, 5.09, 1.84,2.5, 2.4]],
+ [5, [9.5, 3, 3.8, 2, 4.90, 2.95, 1.00, 1.2, 1.2]],
+ [6, [12, 3.6, 4.6, 3, 6.92, 3.81, 1.14, 1.6, 1.4]],
+ [8, [16, 4.8, 6, 4, 9.02, 4.88, 1.69, 2.0, 1.9]],
+ [10, [20, 6.0, 7.5, 4, 10.18, 5.09, 1.84,2.5, 2.4]],
],
type = head=="pan" ? (drive=="slot" ? "pan flat" : "pan round") : head,
htind = drive=="slot" ? 1 : 2,
@@ -648,34 +648,34 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
metric_button = [ // button, hex drive
// head diam, height, hex, phillips, hex drive depth
[1.6, [2.9, 0.8, 0.9, undef, 0.55]], // These four cases,
- [2, [3.5, 1.3, 1.3, undef, 0.69]], // extrapolated hex depth
- [2.2, [3.8, 0.9, 1.3, undef, 0.76]], //
- [2.5, [4.6, 1.5, 1.5, undef, 0.87]], //
- [3, [5.7, 1.65, 2, undef, 1.04, 8, 0.81]],
- [3.5, [5.7, 1.65, 2, undef, 1.21]], // interpolated hex depth
- [4, [7.6, 2.2, 2.5, undef, 1.30, 15, 1.3]],
- [5, [9.5, 2.75, 3, undef, 1.56, 25, 1.56]],
- [6, [10.5,3.3, 4, undef, 2.08, 27, 2.08]],
- [8, [14, 4.4, 5, undef, 2.60, 40, 2.3]],
- [10, [17.5,5.5, 6, undef, 3.21, 45, 2.69]],
- [12, [21, 6.6, 8, undef, 4.16, 55, 4.02]],
- [16, [28, 8.8, 10, undef, 5.55]], // interpolated hex depth
+ [2, [3.5, 1.3, 1.3, undef, 0.69]], // extrapolated hex depth
+ [2.2, [3.8, 0.9, 1.3, undef, 0.76]], //
+ [2.5, [4.6, 1.5, 1.5, undef, 0.87]], //
+ [3, [5.7, 1.65, 2, undef, 1.04, 8, 0.81]],
+ [3.5, [5.7, 1.65, 2, undef, 1.21]], // interpolated hex depth
+ [4, [7.6, 2.2, 2.5, undef, 1.30, 15, 1.3]],
+ [5, [9.5, 2.75, 3, undef, 1.56, 25, 1.56]],
+ [6, [10.5,3.3, 4, undef, 2.08, 27, 2.08]],
+ [8, [14, 4.4, 5, undef, 2.60, 40, 2.3]],
+ [10, [17.5,5.5, 6, undef, 3.21, 45, 2.69]],
+ [12, [21, 6.6, 8, undef, 4.16, 55, 4.02]],
+ [16, [28, 8.8, 10, undef, 5.55]], // interpolated hex depth
],
metric_cheese = [ // slotted, phillips ISO 1207, ISO 7048
// head diam, head height, hex drive, phillips drive, slot width, slight depth, ph diam
- [1, [2, 0.7, undef, undef]],
- [1.2, [2.3,0.8, undef, undef]],
- [1.4, [2.6,0.9, undef, undef]],
- [1.6, [3, 1, undef, undef, 0.4, 0.45]],
- [2, [3.8,1.3, undef, 1 , 0.5, 0.6]],
- [2.5, [4.5,1.6, undef, 1 , 0.6, 0.7, 2.7,1.2]],
- [3, [5.5,2, undef, 2 , 0.8, 0.85, 3.5,0.86]],
- [3.5, [6, 2.4, undef, 2 , 1.0, 1.0, 3.8, 1.15]],
- [4, [7, 2.6, undef, 2 , 1.2, 1.1, 4.1, 1.45]],
- [5, [8.5,3.3, undef, 2 , 1.2, 1.3, 4.8, 2.14]],
- [6, [10, 3.9, undef, 3 , 1.6, 1.6, 6.2, 2.25]],
- [8, [13, 5, undef, 3 , 2.0, 2.0, 7.7, 3.73]],
- [10, [16, 6, undef, undef, 2.5, 2.4]]
+ [1, [2, 0.7, undef, undef]],
+ [1.2, [2.3,0.8, undef, undef]],
+ [1.4, [2.6,0.9, undef, undef]],
+ [1.6, [3, 1, undef, undef, 0.4, 0.45]],
+ [2, [3.8,1.3, undef, 1 , 0.5, 0.6]],
+ [2.5, [4.5,1.6, undef, 1 , 0.6, 0.7, 2.7,1.2]],
+ [3, [5.5,2, undef, 2 , 0.8, 0.85, 3.5,0.86]],
+ [3.5, [6, 2.4, undef, 2 , 1.0, 1.0, 3.8, 1.15]],
+ [4, [7, 2.6, undef, 2 , 1.2, 1.1, 4.1, 1.45]],
+ [5, [8.5,3.3, undef, 2 , 1.2, 1.3, 4.8, 2.14]],
+ [6, [10, 3.9, undef, 3 , 1.6, 1.6, 6.2, 2.25]],
+ [8, [13, 5, undef, 3 , 2.0, 2.0, 7.7, 3.73]],
+ [10, [16, 6, undef, undef, 2.5, 2.4]]
],
entry = struct_val(head=="button" ? metric_button : metric_cheese, diam),
drive_index = drive=="phillips" ? 3 :
@@ -693,18 +693,18 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
small = head == "flat small" || (head=="flat" && (drive!="hex" && drive!="torx")),
metric_flat_large = [ // for hex drive
[2, [4, 1.3,undef]],
- [2.5,[5, 1.5, undef]],
- [3, [6, 2 , 1.1, 10, 0.96]],
- [4, [8, 2.5, 1.5, 20, 1.34]],
- [5, [10, 3 , 1.9, 25, 1.54]],
- [6, [12, 4 , 2.2, 30, 1.91]],
- [8, [16, 5 , 3.0, 40, 2.3]],
- [10, [20, 6 , 3.6, 50, 3.04]],
- [12, [24, 8 ,undef]],
- [14, [27, 10 ,undef]],
- [16, [30, 10 ,undef]],
- [18, [33, 12 ,undef]],
- [20, [36, 12 ,undef]],
+ [2.5,[5, 1.5, undef]],
+ [3, [6, 2 , 1.1, 10, 0.96]],
+ [4, [8, 2.5, 1.5, 20, 1.34]],
+ [5, [10, 3 , 1.9, 25, 1.54]],
+ [6, [12, 4 , 2.2, 30, 1.91]],
+ [8, [16, 5 , 3.0, 40, 2.3]],
+ [10, [20, 6 , 3.6, 50, 3.04]],
+ [12, [24, 8 ,undef]],
+ [14, [27, 10 ,undef]],
+ [16, [30, 10 ,undef]],
+ [18, [33, 12 ,undef]],
+ [20, [36, 12 ,undef]],
],
metric_flat_small = [ // for phillips, slotted
// Phillips from ASME B18.6.7M (ISO 7046 gives different values),
@@ -715,20 +715,20 @@ function _screw_info_metric(diam, pitch, head, thread, drive) =
[1.6, [2.6, 0,undef,undef,undef, 0.3, 0.28]],
[1.6, [3, 0,undef,undef,undef, 0.4, 0.32]],
[2, [3.8, 0, 2.14, 1.54, 0.53, 0.5, 0.4]],
- [2.5, [4.7, 1, 2.80, 1.78, 0.74, 0.6, 0.5]],
- [2.6, [4.7, 1, 2.80, 1.78, 0.74, 0.6, 0.5]],
- [3, [5.6, 1, 3.10, 2.08, 0.79, 0.8, 0.6]],
- [3.5, [6.5, 1, 4.06, 2.25, 0.91, 0.8, 0.7]],
- [4, [7.5, 2, 4.46, 2.65, 0.96, 1.0, 0.8]],
- [5, [9.2, 2, 5.06, 3.25, 1.04, 1.2, 1.0]],
- [6, [11, 3, 6.62, 3.61, 1.12, 1.6, 1.2]],
- [8, [14.5,4, 8.78, 4.88, 1.80, 2.0, 1.6]],
- [10, [18,undef,undef,undef,undef,2.5,2 ]],
- [12, [22,undef,undef,undef,undef,3,2.4 ]],
- [14, [25,undef,undef,undef,undef,3,2.8 ]],
- [16, [29,undef,undef,undef,undef,4,3.2 ]],
- [18, [33,undef,undef,undef,undef,4,3.6 ]],
- [20, [36,undef,undef,undef,undef,5,4 ]],
+ [2.5, [4.7, 1, 2.80, 1.78, 0.74, 0.6, 0.5]],
+ [2.6, [4.7, 1, 2.80, 1.78, 0.74, 0.6, 0.5]],
+ [3, [5.6, 1, 3.10, 2.08, 0.79, 0.8, 0.6]],
+ [3.5, [6.5, 1, 4.06, 2.25, 0.91, 0.8, 0.7]],
+ [4, [7.5, 2, 4.46, 2.65, 0.96, 1.0, 0.8]],
+ [5, [9.2, 2, 5.06, 3.25, 1.04, 1.2, 1.0]],
+ [6, [11, 3, 6.62, 3.61, 1.12, 1.6, 1.2]],
+ [8, [14.5,4, 8.78, 4.88, 1.80, 2.0, 1.6]],
+ [10, [18,undef,undef,undef,undef,2.5,2 ]],
+ [12, [22,undef,undef,undef,undef,3,2.4 ]],
+ [14, [25,undef,undef,undef,undef,3,2.8 ]],
+ [16, [29,undef,undef,undef,undef,4,3.2 ]],
+ [18, [33,undef,undef,undef,undef,4,3.6 ]],
+ [20, [36,undef,undef,undef,undef,5,4 ]],
],
entry = struct_val(small ? metric_flat_small : metric_flat_large, diam),
driveind = small && drive=="phillips" || !small && drive=="hex" ? 1 : !small && drive=="torx" ? 3 : undef,
@@ -1330,10 +1330,10 @@ module nut(name, thread="coarse", oversize=0, spec, diameter, thickness, toleran
echo(threadspec=threadspec,"for nut threads");
echo(nut_minor_diam = mean(struct_val(threadspec,"d_minor")));
trapezoidal_threaded_nut(
- od=diameter, id=mean(struct_val(threadspec, "d_major")), h=thickness,
- pitch=struct_val(threadspec, "pitch"),
- profile=_thread_profile(threadspec),
- bevel=false,anchor=anchor,spin=spin,orient=orient);
+ od=diameter, id=mean(struct_val(threadspec, "d_major")), h=thickness,
+ pitch=struct_val(threadspec, "pitch"),
+ profile=_thread_profile(threadspec),
+ bevel=false,anchor=anchor,spin=spin,orient=orient);
}
diff --git a/shapes.scad b/shapes.scad
index d80476a..fe6e3ee 100644
--- a/shapes.scad
+++ b/shapes.scad
@@ -62,242 +62,242 @@
// Example: Standard Connectors
// cuboid(40) show_anchors();
module cuboid(
- size=[1,1,1],
- p1=undef, p2=undef,
- chamfer=undef,
- rounding=undef,
- edges=EDGES_ALL,
- except_edges=[],
- trimcorners=true,
- anchor=CENTER,
- spin=0,
- orient=UP
+ size=[1,1,1],
+ p1=undef, p2=undef,
+ chamfer=undef,
+ rounding=undef,
+ edges=EDGES_ALL,
+ except_edges=[],
+ trimcorners=true,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- size = scalar_vec3(size);
- edges = edges(edges, except=except_edges);
- if (!is_undef(p1)) {
- if (!is_undef(p2)) {
- translate(pointlist_bounds([p1,p2])[0]) {
- cuboid(size=vabs(p2-p1), chamfer=chamfer, rounding=rounding, edges=edges, trimcorners=trimcorners, anchor=ALLNEG) children();
- }
- } else {
- translate(p1) {
- cuboid(size=size, chamfer=chamfer, rounding=rounding, edges=edges, trimcorners=trimcorners, anchor=ALLNEG) children();
- }
- }
- } else {
- if (chamfer != undef) {
- if (any(edges[0])) assert(chamfer <= size.y/2 && chamfer <=size.z/2, "chamfer must be smaller than half the cube length or height.");
- if (any(edges[1])) assert(chamfer <= size.x/2 && chamfer <=size.z/2, "chamfer must be smaller than half the cube width or height.");
- if (any(edges[2])) assert(chamfer <= size.x/2 && chamfer <=size.y/2, "chamfer must be smaller than half the cube width or length.");
- }
- if (rounding != undef) {
- if (any(edges[0])) assert(rounding <= size.y/2 && rounding<=size.z/2, "rounding radius must be smaller than half the cube length or height.");
- if (any(edges[1])) assert(rounding <= size.x/2 && rounding<=size.z/2, "rounding radius must be smaller than half the cube width or height.");
- if (any(edges[2])) assert(rounding <= size.x/2 && rounding<=size.y/2, "rounding radius must be smaller than half the cube width or length.");
- }
- majrots = [[0,90,0], [90,0,0], [0,0,0]];
- attachable(anchor,spin,orient, size=size) {
- if (chamfer != undef) {
- if (edges == EDGES_ALL && trimcorners) {
- if (chamfer<0) {
- cube(size, center=true) {
- attach(TOP) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
- attach(BOT) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
- }
- } else {
- isize = [for (v = size) max(0.001, v-2*chamfer)];
- hull() {
- cube([size.x, isize.y, isize.z], center=true);
- cube([isize.x, size.y, isize.z], center=true);
- cube([isize.x, isize.y, size.z], center=true);
- }
- }
- } else if (chamfer<0) {
- ach = abs(chamfer);
- cube(size, center=true);
+ size = scalar_vec3(size);
+ edges = edges(edges, except=except_edges);
+ if (!is_undef(p1)) {
+ if (!is_undef(p2)) {
+ translate(pointlist_bounds([p1,p2])[0]) {
+ cuboid(size=vabs(p2-p1), chamfer=chamfer, rounding=rounding, edges=edges, trimcorners=trimcorners, anchor=ALLNEG) children();
+ }
+ } else {
+ translate(p1) {
+ cuboid(size=size, chamfer=chamfer, rounding=rounding, edges=edges, trimcorners=trimcorners, anchor=ALLNEG) children();
+ }
+ }
+ } else {
+ if (chamfer != undef) {
+ if (any(edges[0])) assert(chamfer <= size.y/2 && chamfer <=size.z/2, "chamfer must be smaller than half the cube length or height.");
+ if (any(edges[1])) assert(chamfer <= size.x/2 && chamfer <=size.z/2, "chamfer must be smaller than half the cube width or height.");
+ if (any(edges[2])) assert(chamfer <= size.x/2 && chamfer <=size.y/2, "chamfer must be smaller than half the cube width or length.");
+ }
+ if (rounding != undef) {
+ if (any(edges[0])) assert(rounding <= size.y/2 && rounding<=size.z/2, "rounding radius must be smaller than half the cube length or height.");
+ if (any(edges[1])) assert(rounding <= size.x/2 && rounding<=size.z/2, "rounding radius must be smaller than half the cube width or height.");
+ if (any(edges[2])) assert(rounding <= size.x/2 && rounding<=size.y/2, "rounding radius must be smaller than half the cube width or length.");
+ }
+ majrots = [[0,90,0], [90,0,0], [0,0,0]];
+ attachable(anchor,spin,orient, size=size) {
+ if (chamfer != undef) {
+ if (edges == EDGES_ALL && trimcorners) {
+ if (chamfer<0) {
+ cube(size, center=true) {
+ attach(TOP) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
+ attach(BOT) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
+ }
+ } else {
+ isize = [for (v = size) max(0.001, v-2*chamfer)];
+ hull() {
+ cube([size.x, isize.y, isize.z], center=true);
+ cube([isize.x, size.y, isize.z], center=true);
+ cube([isize.x, isize.y, size.z], center=true);
+ }
+ }
+ } else if (chamfer<0) {
+ ach = abs(chamfer);
+ cube(size, center=true);
- // External-Chamfer mask edges
- difference() {
- union() {
- for (i = [0:3], axis=[0:1]) {
- if (edges[axis][i]>0) {
- vec = EDGE_OFFSETS[axis][i];
- translate(vmul(vec/2, size+[ach,ach,-ach])) {
- rotate(majrots[axis]) {
- cube([ach, ach, size[axis]], center=true);
- }
- }
- }
- }
+ // External-Chamfer mask edges
+ difference() {
+ union() {
+ for (i = [0:3], axis=[0:1]) {
+ if (edges[axis][i]>0) {
+ vec = EDGE_OFFSETS[axis][i];
+ translate(vmul(vec/2, size+[ach,ach,-ach])) {
+ rotate(majrots[axis]) {
+ cube([ach, ach, size[axis]], center=true);
+ }
+ }
+ }
+ }
- // Add multi-edge corners.
- if (trimcorners) {
- for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
- if (corner_edge_count(edges, [xa,ya,za]) > 1) {
- translate(vmul([xa,ya,za]/2, size+[ach-0.01,ach-0.01,-ach])) {
- cube([ach+0.01,ach+0.01,ach], center=true);
- }
- }
- }
- }
- }
+ // Add multi-edge corners.
+ if (trimcorners) {
+ for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
+ if (corner_edge_count(edges, [xa,ya,za]) > 1) {
+ translate(vmul([xa,ya,za]/2, size+[ach-0.01,ach-0.01,-ach])) {
+ cube([ach+0.01,ach+0.01,ach], center=true);
+ }
+ }
+ }
+ }
+ }
- // Remove bevels from overhangs.
- for (i = [0:3], axis=[0:1]) {
- if (edges[axis][i]>0) {
- vec = EDGE_OFFSETS[axis][i];
- translate(vmul(vec/2, size+[2*ach,2*ach,-2*ach])) {
- rotate(majrots[axis]) {
- zrot(45) cube([ach*sqrt(2), ach*sqrt(2), size[axis]+2.1*ach], center=true);
- }
- }
- }
- }
- }
- } else {
- difference() {
- cube(size, center=true);
+ // Remove bevels from overhangs.
+ for (i = [0:3], axis=[0:1]) {
+ if (edges[axis][i]>0) {
+ vec = EDGE_OFFSETS[axis][i];
+ translate(vmul(vec/2, size+[2*ach,2*ach,-2*ach])) {
+ rotate(majrots[axis]) {
+ zrot(45) cube([ach*sqrt(2), ach*sqrt(2), size[axis]+2.1*ach], center=true);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ difference() {
+ cube(size, center=true);
- // Chamfer edges
- for (i = [0:3], axis=[0:2]) {
- if (edges[axis][i]>0) {
- translate(vmul(EDGE_OFFSETS[axis][i], size/2)) {
- rotate(majrots[axis]) {
- zrot(45) cube([chamfer*sqrt(2), chamfer*sqrt(2), size[axis]+0.01], center=true);
- }
- }
- }
- }
+ // Chamfer edges
+ for (i = [0:3], axis=[0:2]) {
+ if (edges[axis][i]>0) {
+ translate(vmul(EDGE_OFFSETS[axis][i], size/2)) {
+ rotate(majrots[axis]) {
+ zrot(45) cube([chamfer*sqrt(2), chamfer*sqrt(2), size[axis]+0.01], center=true);
+ }
+ }
+ }
+ }
- // Chamfer triple-edge corners.
- if (trimcorners) {
- for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
- if (corner_edge_count(edges, [xa,ya,za]) > 2) {
- translate(vmul([xa,ya,za]/2, size-[1,1,1]*chamfer*4/3)) {
- rot(from=UP, to=[xa,ya,za]) {
- cube(chamfer*3, anchor=BOTTOM);
- }
- }
- }
- }
- }
- }
- }
- } else if (rounding != undef) {
- sides = quantup(segs(rounding),4);
- if (edges == EDGES_ALL) {
- if(rounding<0) {
- cube(size, center=true);
- zflip_copy() {
- up(size.z/2) {
- difference() {
- down(-rounding/2) cube([size.x-2*rounding, size.y-2*rounding, -rounding], center=true);
- down(-rounding) {
- ycopies(size.y-2*rounding) xcyl(l=size.x-3*rounding, r=-rounding);
- xcopies(size.x-2*rounding) ycyl(l=size.y-3*rounding, r=-rounding);
- }
- }
- }
- }
- } else {
- isize = [for (v = size) max(0.001, v-2*rounding)];
- minkowski() {
- cube(isize, center=true);
- if (trimcorners) {
- spheroid(r=rounding, $fn=sides);
- } else {
- intersection() {
- cyl(r=rounding, h=rounding*2, $fn=sides);
- rotate([90,0,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
- rotate([0,90,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
- }
- }
- }
- }
- } else if (rounding<0) {
- ard = abs(rounding);
- cube(size, center=true);
+ // Chamfer triple-edge corners.
+ if (trimcorners) {
+ for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
+ if (corner_edge_count(edges, [xa,ya,za]) > 2) {
+ translate(vmul([xa,ya,za]/2, size-[1,1,1]*chamfer*4/3)) {
+ rot(from=UP, to=[xa,ya,za]) {
+ cube(chamfer*3, anchor=BOTTOM);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (rounding != undef) {
+ sides = quantup(segs(rounding),4);
+ if (edges == EDGES_ALL) {
+ if(rounding<0) {
+ cube(size, center=true);
+ zflip_copy() {
+ up(size.z/2) {
+ difference() {
+ down(-rounding/2) cube([size.x-2*rounding, size.y-2*rounding, -rounding], center=true);
+ down(-rounding) {
+ ycopies(size.y-2*rounding) xcyl(l=size.x-3*rounding, r=-rounding);
+ xcopies(size.x-2*rounding) ycyl(l=size.y-3*rounding, r=-rounding);
+ }
+ }
+ }
+ }
+ } else {
+ isize = [for (v = size) max(0.001, v-2*rounding)];
+ minkowski() {
+ cube(isize, center=true);
+ if (trimcorners) {
+ spheroid(r=rounding, $fn=sides);
+ } else {
+ intersection() {
+ cyl(r=rounding, h=rounding*2, $fn=sides);
+ rotate([90,0,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
+ rotate([0,90,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
+ }
+ }
+ }
+ }
+ } else if (rounding<0) {
+ ard = abs(rounding);
+ cube(size, center=true);
- // External-Chamfer mask edges
- difference() {
- union() {
- for (i = [0:3], axis=[0:1]) {
- if (edges[axis][i]>0) {
- vec = EDGE_OFFSETS[axis][i];
- translate(vmul(vec/2, size+[ard,ard,-ard])) {
- rotate(majrots[axis]) {
- cube([ard, ard, size[axis]], center=true);
- }
- }
- }
- }
+ // External-Chamfer mask edges
+ difference() {
+ union() {
+ for (i = [0:3], axis=[0:1]) {
+ if (edges[axis][i]>0) {
+ vec = EDGE_OFFSETS[axis][i];
+ translate(vmul(vec/2, size+[ard,ard,-ard])) {
+ rotate(majrots[axis]) {
+ cube([ard, ard, size[axis]], center=true);
+ }
+ }
+ }
+ }
- // Add multi-edge corners.
- if (trimcorners) {
- for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
- if (corner_edge_count(edges, [xa,ya,za]) > 1) {
- translate(vmul([xa,ya,za]/2, size+[ard-0.01,ard-0.01,-ard])) {
- cube([ard+0.01,ard+0.01,ard], center=true);
- }
- }
- }
- }
- }
+ // Add multi-edge corners.
+ if (trimcorners) {
+ for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
+ if (corner_edge_count(edges, [xa,ya,za]) > 1) {
+ translate(vmul([xa,ya,za]/2, size+[ard-0.01,ard-0.01,-ard])) {
+ cube([ard+0.01,ard+0.01,ard], center=true);
+ }
+ }
+ }
+ }
+ }
- // Remove roundings from overhangs.
- for (i = [0:3], axis=[0:1]) {
- if (edges[axis][i]>0) {
- vec = EDGE_OFFSETS[axis][i];
- translate(vmul(vec/2, size+[2*ard,2*ard,-2*ard])) {
- rotate(majrots[axis]) {
- cyl(l=size[axis]+2.1*ard, r=ard);
- }
- }
- }
- }
- }
- } else {
- difference() {
- cube(size, center=true);
+ // Remove roundings from overhangs.
+ for (i = [0:3], axis=[0:1]) {
+ if (edges[axis][i]>0) {
+ vec = EDGE_OFFSETS[axis][i];
+ translate(vmul(vec/2, size+[2*ard,2*ard,-2*ard])) {
+ rotate(majrots[axis]) {
+ cyl(l=size[axis]+2.1*ard, r=ard);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ difference() {
+ cube(size, center=true);
- // Round edges.
- for (i = [0:3], axis=[0:2]) {
- if (edges[axis][i]>0) {
- difference() {
- translate(vmul(EDGE_OFFSETS[axis][i], size/2)) {
- rotate(majrots[axis]) cube([rounding*2, rounding*2, size[axis]+0.1], center=true);
- }
- translate(vmul(EDGE_OFFSETS[axis][i], size/2 - [1,1,1]*rounding)) {
- rotate(majrots[axis]) cyl(h=size[axis]+0.2, r=rounding, $fn=sides);
- }
- }
- }
- }
+ // Round edges.
+ for (i = [0:3], axis=[0:2]) {
+ if (edges[axis][i]>0) {
+ difference() {
+ translate(vmul(EDGE_OFFSETS[axis][i], size/2)) {
+ rotate(majrots[axis]) cube([rounding*2, rounding*2, size[axis]+0.1], center=true);
+ }
+ translate(vmul(EDGE_OFFSETS[axis][i], size/2 - [1,1,1]*rounding)) {
+ rotate(majrots[axis]) cyl(h=size[axis]+0.2, r=rounding, $fn=sides);
+ }
+ }
+ }
+ }
- // Round triple-edge corners.
- if (trimcorners) {
- for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
- if (corner_edge_count(edges, [xa,ya,za]) > 2) {
- difference() {
- translate(vmul([xa,ya,za], size/2)) {
- cube(rounding*2, center=true);
- }
- translate(vmul([xa,ya,za], size/2-[1,1,1]*rounding)) {
- spheroid(r=rounding, $fn=sides);
- }
- }
- }
- }
- }
- }
- }
- } else {
- cube(size=size, center=true);
- }
- children();
- }
- }
+ // Round triple-edge corners.
+ if (trimcorners) {
+ for (za=[-1,1], ya=[-1,1], xa=[-1,1]) {
+ if (corner_edge_count(edges, [xa,ya,za]) > 2) {
+ difference() {
+ translate(vmul([xa,ya,za], size/2)) {
+ cube(rounding*2, center=true);
+ }
+ translate(vmul([xa,ya,za], size/2-[1,1,1]*rounding)) {
+ spheroid(r=rounding, $fn=sides);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ cube(size=size, center=true);
+ }
+ children();
+ }
+ }
}
@@ -383,97 +383,97 @@ module cuboid(
// prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5])
// show_anchors();
module prismoid(
- size1, size2, h, shift=[0,0],
- rounding=0, rounding1, rounding2,
- chamfer=0, chamfer1, chamfer2,
- l, center,
- anchor, spin=0, orient=UP
+ size1, size2, h, shift=[0,0],
+ rounding=0, rounding1, rounding2,
+ chamfer=0, chamfer1, chamfer2,
+ l, center,
+ anchor, spin=0, orient=UP
) {
- assert(is_num(size1) || is_vector(size1,2));
- assert(is_num(size2) || is_vector(size2,2));
- assert(is_num(h) || is_num(l));
- assert(is_vector(shift,2));
- assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.");
- assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.");
- assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.");
- assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.");
- assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.");
- assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.");
- eps = pow(2,-14);
- size1 = is_num(size1)? [size1,size1] : size1;
- size2 = is_num(size2)? [size2,size2] : size2;
- s1 = [max(size1.x, eps), max(size1.y, eps)];
- s2 = [max(size2.x, eps), max(size2.y, eps)];
- rounding1 = default(rounding1, rounding);
- rounding2 = default(rounding2, rounding);
- chamfer1 = default(chamfer1, chamfer);
- chamfer2 = default(chamfer2, chamfer);
- anchor = get_anchor(anchor, center, BOT, BOT);
- vnf = prismoid(
- size1=size1, size2=size2, h=h, shift=shift,
- rounding=rounding, rounding1=rounding1, rounding2=rounding2,
- chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
- l=l, center=CENTER
- );
- attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) {
- vnf_polyhedron(vnf, convexity=4);
- children();
- }
+ assert(is_num(size1) || is_vector(size1,2));
+ assert(is_num(size2) || is_vector(size2,2));
+ assert(is_num(h) || is_num(l));
+ assert(is_vector(shift,2));
+ assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.");
+ assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.");
+ assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.");
+ assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.");
+ assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.");
+ assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.");
+ eps = pow(2,-14);
+ size1 = is_num(size1)? [size1,size1] : size1;
+ size2 = is_num(size2)? [size2,size2] : size2;
+ s1 = [max(size1.x, eps), max(size1.y, eps)];
+ s2 = [max(size2.x, eps), max(size2.y, eps)];
+ rounding1 = default(rounding1, rounding);
+ rounding2 = default(rounding2, rounding);
+ chamfer1 = default(chamfer1, chamfer);
+ chamfer2 = default(chamfer2, chamfer);
+ anchor = get_anchor(anchor, center, BOT, BOT);
+ vnf = prismoid(
+ size1=size1, size2=size2, h=h, shift=shift,
+ rounding=rounding, rounding1=rounding1, rounding2=rounding2,
+ chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
+ l=l, center=CENTER
+ );
+ attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) {
+ vnf_polyhedron(vnf, convexity=4);
+ children();
+ }
}
function prismoid(
- size1, size2, h, shift=[0,0],
- rounding=0, rounding1, rounding2,
- chamfer=0, chamfer1, chamfer2,
- l, center,
- anchor=DOWN, spin=0, orient=UP
+ size1, size2, h, shift=[0,0],
+ rounding=0, rounding1, rounding2,
+ chamfer=0, chamfer1, chamfer2,
+ l, center,
+ anchor=DOWN, spin=0, orient=UP
) =
- assert(is_vector(size1,2))
- assert(is_vector(size2,2))
- assert(is_num(h) || is_num(l))
- assert(is_vector(shift,2))
- assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.")
- assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.")
- assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.")
- assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.")
- assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.")
- assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.")
- let(
- eps = pow(2,-14),
- h = first_defined([h,l,1]),
- shiftby = point3d(point2d(shift)),
- s1 = [max(size1.x, eps), max(size1.y, eps)],
- s2 = [max(size2.x, eps), max(size2.y, eps)],
- rounding1 = default(rounding1, rounding),
- rounding2 = default(rounding2, rounding),
- chamfer1 = default(chamfer1, chamfer),
- chamfer2 = default(chamfer2, chamfer),
- anchor = get_anchor(anchor, center, BOT, BOT),
- vnf = (rounding1==0 && rounding2==0 && chamfer1==0 && chamfer2==0)? (
- let(
- corners = [[1,1],[1,-1],[-1,-1],[-1,1]] * 0.5,
- points = [
- for (p=corners) point3d(vmul(s2,p), +h/2) + shiftby,
- for (p=corners) point3d(vmul(s1,p), -h/2)
- ],
- faces=[
- [0,1,2], [0,2,3], [0,4,5], [0,5,1],
- [1,5,6], [1,6,2], [2,6,7], [2,7,3],
- [3,7,4], [3,4,0], [4,7,6], [4,6,5],
- ]
- ) [points, faces]
- ) : (
- let(
- path1 = rect(size1, rounding=rounding1, chamfer=chamfer1, anchor=CTR),
- path2 = rect(size2, rounding=rounding2, chamfer=chamfer2, anchor=CTR),
- points = [
- each path3d(path1, -h/2),
- each path3d(move(shiftby, p=path2), +h/2),
- ],
- faces = hull(points)
- ) [points, faces]
- )
- ) reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf);
+ assert(is_vector(size1,2))
+ assert(is_vector(size2,2))
+ assert(is_num(h) || is_num(l))
+ assert(is_vector(shift,2))
+ assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.")
+ assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.")
+ assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.")
+ assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.")
+ assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.")
+ assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.")
+ let(
+ eps = pow(2,-14),
+ h = first_defined([h,l,1]),
+ shiftby = point3d(point2d(shift)),
+ s1 = [max(size1.x, eps), max(size1.y, eps)],
+ s2 = [max(size2.x, eps), max(size2.y, eps)],
+ rounding1 = default(rounding1, rounding),
+ rounding2 = default(rounding2, rounding),
+ chamfer1 = default(chamfer1, chamfer),
+ chamfer2 = default(chamfer2, chamfer),
+ anchor = get_anchor(anchor, center, BOT, BOT),
+ vnf = (rounding1==0 && rounding2==0 && chamfer1==0 && chamfer2==0)? (
+ let(
+ corners = [[1,1],[1,-1],[-1,-1],[-1,1]] * 0.5,
+ points = [
+ for (p=corners) point3d(vmul(s2,p), +h/2) + shiftby,
+ for (p=corners) point3d(vmul(s1,p), -h/2)
+ ],
+ faces=[
+ [0,1,2], [0,2,3], [0,4,5], [0,5,1],
+ [1,5,6], [1,6,2], [2,6,7], [2,7,3],
+ [3,7,4], [3,4,0], [4,7,6], [4,6,5],
+ ]
+ ) [points, faces]
+ ) : (
+ let(
+ path1 = rect(size1, rounding=rounding1, chamfer=chamfer1, anchor=CTR),
+ path2 = rect(size2, rounding=rounding2, chamfer=chamfer2, anchor=CTR),
+ points = [
+ each path3d(path1, -h/2),
+ each path3d(move(shiftby, p=path2), +h/2),
+ ],
+ faces = hull(points)
+ ) [points, faces]
+ )
+ ) reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf);
// Module: right_triangle()
@@ -498,14 +498,14 @@ function prismoid(
// right_triangle([60, 40, 15]) show_anchors();
module right_triangle(size=[1, 1, 1], center, anchor, spin=0, orient=UP)
{
- size = scalar_vec3(size);
- anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
- attachable(anchor,spin,orient, size=size) {
- linear_extrude(height=size.z, convexity=2, center=true) {
- polygon([[-size.x/2,-size.y/2], [-size.x/2,size.y/2], [size.x/2,-size.y/2]]);
- }
- children();
- }
+ size = scalar_vec3(size);
+ anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
+ attachable(anchor,spin,orient, size=size) {
+ linear_extrude(height=size.z, convexity=2, center=true) {
+ polygon([[-size.x/2,-size.y/2], [-size.x/2,size.y/2], [size.x/2,-size.y/2]]);
+ }
+ children();
+ }
}
@@ -611,100 +611,100 @@ module right_triangle(size=[1, 1, 1], center, anchor, spin=0, orient=UP)
// }
//
module cyl(
- l=undef, h=undef,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- chamfer=undef, chamfer1=undef, chamfer2=undef,
- chamfang=undef, chamfang1=undef, chamfang2=undef,
- rounding=undef, rounding1=undef, rounding2=undef,
- circum=false, realign=false, from_end=false,
- center, anchor, spin=0, orient=UP
+ l=undef, h=undef,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ chamfer=undef, chamfer1=undef, chamfer2=undef,
+ chamfang=undef, chamfang1=undef, chamfang2=undef,
+ rounding=undef, rounding1=undef, rounding2=undef,
+ circum=false, realign=false, from_end=false,
+ center, anchor, spin=0, orient=UP
) {
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
- l = first_defined([l, h, 1]);
- sides = segs(max(r1,r2));
- sc = circum? 1/cos(180/sides) : 1;
- phi = atan2(l, r2-r1);
- anchor = get_anchor(anchor,center,BOT,CENTER);
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- zrot(realign? 180/sides : 0) {
- if (!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])) {
- cylinder(h=l, r1=r1*sc, r2=r2*sc, center=true, $fn=sides);
- } else {
- vang = atan2(l, r1-r2)/2;
- chang1 = 90-first_defined([chamfang1, chamfang, vang]);
- chang2 = 90-first_defined([chamfang2, chamfang, 90-vang]);
- cham1 = first_defined([chamfer1, chamfer]) * (from_end? 1 : tan(chang1));
- cham2 = first_defined([chamfer2, chamfer]) * (from_end? 1 : tan(chang2));
- fil1 = first_defined([rounding1, rounding]);
- fil2 = first_defined([rounding2, rounding]);
- if (chamfer != undef) {
- assert(chamfer <= r1, "chamfer is larger than the r1 radius of the cylinder.");
- assert(chamfer <= r2, "chamfer is larger than the r2 radius of the cylinder.");
- }
- if (cham1 != undef) {
- assert(cham1 <= r1, "chamfer1 is larger than the r1 radius of the cylinder.");
- }
- if (cham2 != undef) {
- assert(cham2 <= r2, "chamfer2 is larger than the r2 radius of the cylinder.");
- }
- if (rounding != undef) {
- assert(rounding <= r1, "rounding is larger than the r1 radius of the cylinder.");
- assert(rounding <= r2, "rounding is larger than the r2 radius of the cylinder.");
- }
- if (fil1 != undef) {
- assert(fil1 <= r1, "rounding1 is larger than the r1 radius of the cylinder.");
- }
- if (fil2 != undef) {
- assert(fil2 <= r2, "rounding2 is larger than the r1 radius of the cylinder.");
- }
- dy1 = abs(first_defined([cham1, fil1, 0]));
- dy2 = abs(first_defined([cham2, fil2, 0]));
- assert(dy1+dy2 <= l, "Sum of fillets and chamfer sizes must be less than the length of the cylinder.");
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
+ l = first_defined([l, h, 1]);
+ sides = segs(max(r1,r2));
+ sc = circum? 1/cos(180/sides) : 1;
+ phi = atan2(l, r2-r1);
+ anchor = get_anchor(anchor,center,BOT,CENTER);
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ zrot(realign? 180/sides : 0) {
+ if (!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])) {
+ cylinder(h=l, r1=r1*sc, r2=r2*sc, center=true, $fn=sides);
+ } else {
+ vang = atan2(l, r1-r2)/2;
+ chang1 = 90-first_defined([chamfang1, chamfang, vang]);
+ chang2 = 90-first_defined([chamfang2, chamfang, 90-vang]);
+ cham1 = first_defined([chamfer1, chamfer]) * (from_end? 1 : tan(chang1));
+ cham2 = first_defined([chamfer2, chamfer]) * (from_end? 1 : tan(chang2));
+ fil1 = first_defined([rounding1, rounding]);
+ fil2 = first_defined([rounding2, rounding]);
+ if (chamfer != undef) {
+ assert(chamfer <= r1, "chamfer is larger than the r1 radius of the cylinder.");
+ assert(chamfer <= r2, "chamfer is larger than the r2 radius of the cylinder.");
+ }
+ if (cham1 != undef) {
+ assert(cham1 <= r1, "chamfer1 is larger than the r1 radius of the cylinder.");
+ }
+ if (cham2 != undef) {
+ assert(cham2 <= r2, "chamfer2 is larger than the r2 radius of the cylinder.");
+ }
+ if (rounding != undef) {
+ assert(rounding <= r1, "rounding is larger than the r1 radius of the cylinder.");
+ assert(rounding <= r2, "rounding is larger than the r2 radius of the cylinder.");
+ }
+ if (fil1 != undef) {
+ assert(fil1 <= r1, "rounding1 is larger than the r1 radius of the cylinder.");
+ }
+ if (fil2 != undef) {
+ assert(fil2 <= r2, "rounding2 is larger than the r1 radius of the cylinder.");
+ }
+ dy1 = abs(first_defined([cham1, fil1, 0]));
+ dy2 = abs(first_defined([cham2, fil2, 0]));
+ assert(dy1+dy2 <= l, "Sum of fillets and chamfer sizes must be less than the length of the cylinder.");
- path = concat(
- [[0,l/2]],
+ path = concat(
+ [[0,l/2]],
- !is_undef(cham2)? (
- let(
- p1 = [r2-cham2/tan(chang2),l/2],
- p2 = lerp([r2,l/2],[r1,-l/2],abs(cham2)/l)
- ) [p1,p2]
- ) : !is_undef(fil2)? (
- let(
- cn = find_circle_2tangents([r2-fil2,l/2], [r2,l/2], [r1,-l/2], r=abs(fil2)),
- ang = fil2<0? phi : phi-180,
- steps = ceil(abs(ang)/360*segs(abs(fil2))),
- step = ang/steps,
- pts = [for (i=[0:1:steps]) let(a=90+i*step) cn[0]+abs(fil2)*[cos(a),sin(a)]]
- ) pts
- ) : [[r2,l/2]],
+ !is_undef(cham2)? (
+ let(
+ p1 = [r2-cham2/tan(chang2),l/2],
+ p2 = lerp([r2,l/2],[r1,-l/2],abs(cham2)/l)
+ ) [p1,p2]
+ ) : !is_undef(fil2)? (
+ let(
+ cn = find_circle_2tangents([r2-fil2,l/2], [r2,l/2], [r1,-l/2], r=abs(fil2)),
+ ang = fil2<0? phi : phi-180,
+ steps = ceil(abs(ang)/360*segs(abs(fil2))),
+ step = ang/steps,
+ pts = [for (i=[0:1:steps]) let(a=90+i*step) cn[0]+abs(fil2)*[cos(a),sin(a)]]
+ ) pts
+ ) : [[r2,l/2]],
- !is_undef(cham1)? (
- let(
- p1 = lerp([r1,-l/2],[r2,l/2],abs(cham1)/l),
- p2 = [r1-cham1/tan(chang1),-l/2]
- ) [p1,p2]
- ) : !is_undef(fil1)? (
- let(
- cn = find_circle_2tangents([r1-fil1,-l/2], [r1,-l/2], [r2,l/2], r=abs(fil1)),
- ang = fil1<0? 180-phi : -phi,
- steps = ceil(abs(ang)/360*segs(abs(fil1))),
- step = ang/steps,
- pts = [for (i=[0:1:steps]) let(a=(fil1<0?180:0)+(phi-90)+i*step) cn[0]+abs(fil1)*[cos(a),sin(a)]]
- ) pts
- ) : [[r1,-l/2]],
+ !is_undef(cham1)? (
+ let(
+ p1 = lerp([r1,-l/2],[r2,l/2],abs(cham1)/l),
+ p2 = [r1-cham1/tan(chang1),-l/2]
+ ) [p1,p2]
+ ) : !is_undef(fil1)? (
+ let(
+ cn = find_circle_2tangents([r1-fil1,-l/2], [r1,-l/2], [r2,l/2], r=abs(fil1)),
+ ang = fil1<0? 180-phi : -phi,
+ steps = ceil(abs(ang)/360*segs(abs(fil1))),
+ step = ang/steps,
+ pts = [for (i=[0:1:steps]) let(a=(fil1<0?180:0)+(phi-90)+i*step) cn[0]+abs(fil1)*[cos(a),sin(a)]]
+ ) pts
+ ) : [[r1,-l/2]],
- [[0,-l/2]]
- );
- rotate_extrude(convexity=2) {
- polygon(path);
- }
- }
- }
- children();
- }
+ [[0,-l/2]]
+ );
+ rotate_extrude(convexity=2) {
+ polygon(path);
+ }
+ }
+ }
+ children();
+ }
}
@@ -741,8 +741,8 @@ module cyl(
// }
module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
{
- anchor = rot(from=RIGHT, to=UP, p=anchor);
- cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=RIGHT, anchor=anchor) children();
+ anchor = rot(from=RIGHT, to=UP, p=anchor);
+ cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=RIGHT, anchor=anchor) children();
}
@@ -779,8 +779,8 @@ module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
// }
module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
{
- anchor = rot(from=BACK, to=UP, p=anchor);
- cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=BACK, anchor=anchor) children();
+ anchor = rot(from=BACK, to=UP, p=anchor);
+ cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=BACK, anchor=anchor) children();
}
@@ -817,7 +817,7 @@ module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
// }
module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
{
- cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=UP, anchor=anchor) children();
+ cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=UP, anchor=anchor) children();
}
@@ -869,34 +869,34 @@ module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
// Example: Standard Connectors
// tube(h=30, or=40, wall=5) show_anchors();
module tube(
- h, wall=undef,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- or=undef, or1=undef, or2=undef,
- od=undef, od1=undef, od2=undef,
- ir=undef, id=undef, ir1=undef,
- ir2=undef, id1=undef, id2=undef,
- anchor, spin=0, orient=UP,
- center, realign=false, l
+ h, wall=undef,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ or=undef, or1=undef, or2=undef,
+ od=undef, od1=undef, od2=undef,
+ ir=undef, id=undef, ir1=undef,
+ ir2=undef, id1=undef, id2=undef,
+ anchor, spin=0, orient=UP,
+ center, realign=false, l
) {
- h = first_defined([h,l,1]);
- r1 = first_defined([or1, od1/2, r1, d1/2, or, od/2, r, d/2, ir1+wall, id1/2+wall, ir+wall, id/2+wall]);
- r2 = first_defined([or2, od2/2, r2, d2/2, or, od/2, r, d/2, ir2+wall, id2/2+wall, ir+wall, id/2+wall]);
- ir1 = first_defined([ir1, id1/2, ir, id/2, r1-wall, d1/2-wall, r-wall, d/2-wall]);
- ir2 = first_defined([ir2, id2/2, ir, id/2, r2-wall, d2/2-wall, r-wall, d/2-wall]);
- assert(ir1 <= r1, "Inner radius is larger than outer radius.");
- assert(ir2 <= r2, "Inner radius is larger than outer radius.");
- sides = segs(max(r1,r2));
- anchor = get_anchor(anchor, center, BOT, BOT);
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
- zrot(realign? 180/sides : 0) {
- difference() {
- cyl(h=h, r1=r1, r2=r2, $fn=sides) children();
- cyl(h=h+0.05, r1=ir1, r2=ir2);
- }
- }
- children();
- }
+ h = first_defined([h,l,1]);
+ r1 = first_defined([or1, od1/2, r1, d1/2, or, od/2, r, d/2, ir1+wall, id1/2+wall, ir+wall, id/2+wall]);
+ r2 = first_defined([or2, od2/2, r2, d2/2, or, od/2, r, d/2, ir2+wall, id2/2+wall, ir+wall, id/2+wall]);
+ ir1 = first_defined([ir1, id1/2, ir, id/2, r1-wall, d1/2-wall, r-wall, d/2-wall]);
+ ir2 = first_defined([ir2, id2/2, ir, id/2, r2-wall, d2/2-wall, r-wall, d/2-wall]);
+ assert(ir1 <= r1, "Inner radius is larger than outer radius.");
+ assert(ir2 <= r2, "Inner radius is larger than outer radius.");
+ sides = segs(max(r1,r2));
+ anchor = get_anchor(anchor, center, BOT, BOT);
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
+ zrot(realign? 180/sides : 0) {
+ difference() {
+ cyl(h=h, r1=r1, r2=r2, $fn=sides) children();
+ cyl(h=h+0.05, r1=ir1, r2=ir2);
+ }
+ }
+ children();
+ }
}
@@ -983,80 +983,80 @@ module tube(
// rounding2=[0,5,0,10], irounding2=[0,3,0,8]
// );
module rect_tube(
- size, isize,
- h, shift=[0,0], wall,
- size1, size2,
- isize1, isize2,
- rounding=0, rounding1, rounding2,
- irounding=0, irounding1, irounding2,
- chamfer=0, chamfer1, chamfer2,
- ichamfer=0, ichamfer1, ichamfer2,
- anchor, spin=0, orient=UP,
- center, l
+ size, isize,
+ h, shift=[0,0], wall,
+ size1, size2,
+ isize1, isize2,
+ rounding=0, rounding1, rounding2,
+ irounding=0, irounding1, irounding2,
+ chamfer=0, chamfer1, chamfer2,
+ ichamfer=0, ichamfer1, ichamfer2,
+ anchor, spin=0, orient=UP,
+ center, l
) {
- h = first_defined([h,l,1]);
- assert(is_num(h), "l or h argument required.");
- assert(is_vector(shift,2));
- s1 = is_num(size1)? [size1, size1] :
- is_vector(size1,2)? size1 :
- is_num(size)? [size, size] :
- is_vector(size,2)? size :
- undef;
- s2 = is_num(size2)? [size2, size2] :
- is_vector(size2,2)? size2 :
- is_num(size)? [size, size] :
- is_vector(size,2)? size :
- undef;
- is1 = is_num(isize1)? [isize1, isize1] :
- is_vector(isize1,2)? isize1 :
- is_num(isize)? [isize, isize] :
- is_vector(isize,2)? isize :
- undef;
- is2 = is_num(isize2)? [isize2, isize2] :
- is_vector(isize2,2)? isize2 :
- is_num(isize)? [isize, isize] :
- is_vector(isize,2)? isize :
- undef;
- size1 = is_def(s1)? s1 :
- (is_def(wall) && is_def(is1))? (is1+2*[wall,wall]) :
- undef;
- size2 = is_def(s2)? s2 :
- (is_def(wall) && is_def(is2))? (is2+2*[wall,wall]) :
- undef;
- isize1 = is_def(is1)? is1 :
- (is_def(wall) && is_def(s1))? (s1-2*[wall,wall]) :
- undef;
- isize2 = is_def(is2)? is2 :
- (is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
- undef;
- assert(wall==undef || is_num(wall));
- assert(size1!=undef, "Bad size/size1 argument.");
- assert(size2!=undef, "Bad size/size2 argument.");
- assert(isize1!=undef, "Bad isize/isize1 argument.");
- assert(isize2!=undef, "Bad isize/isize2 argument.");
- assert(isize1.x < size1.x, "Inner size is larger than outer size.");
- assert(isize1.y < size1.y, "Inner size is larger than outer size.");
- assert(isize2.x < size2.x, "Inner size is larger than outer size.");
- assert(isize2.y < size2.y, "Inner size is larger than outer size.");
- anchor = get_anchor(anchor, center, BOT, BOT);
- attachable(anchor,spin,orient, size=[each size1, h], size2=size2, shift=shift) {
- diff("_H_o_L_e_")
- prismoid(
- size1, size2, h=h, shift=shift,
- rounding=rounding, rounding1=rounding1, rounding2=rounding2,
- chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
- anchor=CTR
- ) {
- children();
- tags("_H_o_L_e_") prismoid(
- isize1, isize2, h=h+0.05, shift=shift,
- rounding=irounding, rounding1=irounding1, rounding2=irounding2,
- chamfer=ichamfer, chamfer1=ichamfer1, chamfer2=ichamfer2,
- anchor=CTR
- );
- }
- children();
- }
+ h = first_defined([h,l,1]);
+ assert(is_num(h), "l or h argument required.");
+ assert(is_vector(shift,2));
+ s1 = is_num(size1)? [size1, size1] :
+ is_vector(size1,2)? size1 :
+ is_num(size)? [size, size] :
+ is_vector(size,2)? size :
+ undef;
+ s2 = is_num(size2)? [size2, size2] :
+ is_vector(size2,2)? size2 :
+ is_num(size)? [size, size] :
+ is_vector(size,2)? size :
+ undef;
+ is1 = is_num(isize1)? [isize1, isize1] :
+ is_vector(isize1,2)? isize1 :
+ is_num(isize)? [isize, isize] :
+ is_vector(isize,2)? isize :
+ undef;
+ is2 = is_num(isize2)? [isize2, isize2] :
+ is_vector(isize2,2)? isize2 :
+ is_num(isize)? [isize, isize] :
+ is_vector(isize,2)? isize :
+ undef;
+ size1 = is_def(s1)? s1 :
+ (is_def(wall) && is_def(is1))? (is1+2*[wall,wall]) :
+ undef;
+ size2 = is_def(s2)? s2 :
+ (is_def(wall) && is_def(is2))? (is2+2*[wall,wall]) :
+ undef;
+ isize1 = is_def(is1)? is1 :
+ (is_def(wall) && is_def(s1))? (s1-2*[wall,wall]) :
+ undef;
+ isize2 = is_def(is2)? is2 :
+ (is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
+ undef;
+ assert(wall==undef || is_num(wall));
+ assert(size1!=undef, "Bad size/size1 argument.");
+ assert(size2!=undef, "Bad size/size2 argument.");
+ assert(isize1!=undef, "Bad isize/isize1 argument.");
+ assert(isize2!=undef, "Bad isize/isize2 argument.");
+ assert(isize1.x < size1.x, "Inner size is larger than outer size.");
+ assert(isize1.y < size1.y, "Inner size is larger than outer size.");
+ assert(isize2.x < size2.x, "Inner size is larger than outer size.");
+ assert(isize2.y < size2.y, "Inner size is larger than outer size.");
+ anchor = get_anchor(anchor, center, BOT, BOT);
+ attachable(anchor,spin,orient, size=[each size1, h], size2=size2, shift=shift) {
+ diff("_H_o_L_e_")
+ prismoid(
+ size1, size2, h=h, shift=shift,
+ rounding=rounding, rounding1=rounding1, rounding2=rounding2,
+ chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
+ anchor=CTR
+ ) {
+ children();
+ tags("_H_o_L_e_") prismoid(
+ isize1, isize2, h=h+0.05, shift=shift,
+ rounding=irounding, rounding1=irounding1, rounding2=irounding2,
+ chamfer=ichamfer, chamfer1=ichamfer1, chamfer2=ichamfer2,
+ anchor=CTR
+ );
+ }
+ children();
+ }
}
@@ -1090,23 +1090,23 @@ module rect_tube(
// Example: Standard Connectors
// torus(od=60, id=30) show_anchors();
module torus(
- r=undef, d=undef,
- r2=undef, d2=undef,
- or=undef, od=undef,
- ir=undef, id=undef,
- center, anchor, spin=0, orient=UP
+ r=undef, d=undef,
+ r2=undef, d2=undef,
+ or=undef, od=undef,
+ ir=undef, id=undef,
+ center, anchor, spin=0, orient=UP
) {
- orr = get_radius(r=or, d=od, dflt=1.0);
- irr = get_radius(r=ir, d=id, dflt=0.5);
- majrad = get_radius(r=r, d=d, dflt=(orr+irr)/2);
- minrad = get_radius(r=r2, d=d2, dflt=(orr-irr)/2);
- anchor = get_anchor(anchor, center, BOT, CENTER);
- attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
- rotate_extrude(convexity=4) {
- right(majrad) circle(r=minrad);
- }
- children();
- }
+ orr = get_radius(r=or, d=od, dflt=1.0);
+ irr = get_radius(r=ir, d=id, dflt=0.5);
+ majrad = get_radius(r=r, d=d, dflt=(orr+irr)/2);
+ minrad = get_radius(r=r2, d=d2, dflt=(orr-irr)/2);
+ anchor = get_anchor(anchor, center, BOT, CENTER);
+ attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
+ rotate_extrude(convexity=4) {
+ right(majrad) circle(r=minrad);
+ }
+ children();
+ }
}
@@ -1158,124 +1158,124 @@ module torus(
// vnf_polyhedron(vnf);
module spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP)
{
- r = get_radius(r=r, d=d, dflt=1);
- sides = segs(r);
- attachable(anchor,spin,orient, r=r) {
- if (style=="orig") {
- rotate_extrude(convexity=2,$fn=sides) {
- difference() {
- oval(r=r, circum=circum, $fn=sides);
- left(r) square(2*r,center=true);
- }
- }
- } else if (style=="aligned") {
- rotate_extrude(convexity=2,$fn=sides) {
- difference() {
- zrot(180/sides) oval(r=r, circum=circum, $fn=sides);
- left(r) square(2*r,center=true);
- }
- }
- } else {
- vnf = spheroid(r=r, circum=circum, style=style);
- vnf_polyhedron(vnf, convexity=2);
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ sides = segs(r);
+ attachable(anchor,spin,orient, r=r) {
+ if (style=="orig") {
+ rotate_extrude(convexity=2,$fn=sides) {
+ difference() {
+ oval(r=r, circum=circum, $fn=sides);
+ left(r) square(2*r,center=true);
+ }
+ }
+ } else if (style=="aligned") {
+ rotate_extrude(convexity=2,$fn=sides) {
+ difference() {
+ zrot(180/sides) oval(r=r, circum=circum, $fn=sides);
+ left(r) square(2*r,center=true);
+ }
+ }
+ } else {
+ vnf = spheroid(r=r, circum=circum, style=style);
+ vnf_polyhedron(vnf, convexity=2);
+ }
+ children();
+ }
}
function spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP) =
- let(
- r = get_radius(r=r, d=d, dflt=1),
- hsides = segs(r),
- vsides = max(2,ceil(hsides/2)),
- icosa_steps = round(max(5,hsides)/5),
- rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r,
- stagger = style=="stagger",
- verts = style=="orig"? [
- for (i=[0:1:vsides-1]) let(phi = (i+0.5)*180/(vsides))
- for (j=[0:1:hsides-1]) let(theta = j*360/hsides)
- spherical_to_xyz(rr, theta, phi),
- ] : style=="aligned" || style=="stagger"? [
- spherical_to_xyz(rr, 0, 0),
- for (i=[1:1:vsides-1]) let(phi = i*180/vsides)
- for (j=[0:1:hsides-1]) let(theta = (j+((stagger && i%2!=0)?0.5:0))*360/hsides)
- spherical_to_xyz(rr, theta, phi),
- spherical_to_xyz(rr, 0, 180)
- ] : style=="icosa"? [
- for (tb=[0,1], j=[0,2], i = [0:1:4]) let(
- theta0 = i*360/5,
- theta1 = (i-0.5)*360/5,
- theta2 = (i+0.5)*360/5,
- phi0 = 180/3 * j,
- phi1 = 180/3,
- v0 = spherical_to_xyz(1,theta0,phi0),
- v1 = spherical_to_xyz(1,theta1,phi1),
- v2 = spherical_to_xyz(1,theta2,phi1),
- ax0 = vector_axis(v0, v1),
- ang0 = vector_angle(v0, v1),
- ax1 = vector_axis(v0, v2),
- ang1 = vector_angle(v0, v2)
- )
- for (k = [0:1:icosa_steps]) let(
- u = k/icosa_steps,
- vv0 = rot(ang0*u, ax0, p=v0),
- vv1 = rot(ang1*u, ax1, p=v0),
- ax2 = vector_axis(vv0, vv1),
- ang2 = vector_angle(vv0, vv1)
- )
- for (l = [0:1:k]) let(
- v = k? l/k : 0,
- pt = rot(ang2*v, v=ax2, p=vv0) * rr * (tb? -1 : 1)
- ) pt
- ] : assert(in_list(style,["orig","aligned","stagger","icosa"])),
- lv = len(verts),
- faces = style=="orig"? [
- [for (i=[0:1:hsides-1]) hsides-i-1],
- [for (i=[0:1:hsides-1]) lv-hsides+i],
- for (i=[0:1:vsides-2], j=[0:1:hsides-1]) each [
- [(i+1)*hsides+j, i*hsides+j, i*hsides+(j+1)%hsides],
- [(i+1)*hsides+j, i*hsides+(j+1)%hsides, (i+1)*hsides+(j+1)%hsides],
- ]
- ] : style=="aligned" || style=="stagger"? [
- for (i=[0:1:hsides-1]) let(
- b2 = lv-2-hsides
- ) each [
- [i+1, 0, ((i+1)%hsides)+1],
- [lv-1, b2+i+1, b2+((i+1)%hsides)+1],
- ],
- for (i=[0:1:vsides-3], j=[0:1:hsides-1]) let(
- base = 1 + hsides*i
- ) each (
- (stagger && i%2!=0)? [
- [base+j, base+hsides+j%hsides, base+hsides+(j+hsides-1)%hsides],
- [base+j, base+(j+1)%hsides, base+hsides+j],
- ] : [
- [base+j, base+(j+1)%hsides, base+hsides+(j+1)%hsides],
- [base+j, base+hsides+(j+1)%hsides, base+hsides+j],
- ]
- )
- ] : style=="icosa"? let(
- pyr = [for (x=[0:1:icosa_steps+1]) x],
- tri = sum(pyr),
- soff = cumsum(pyr)
- ) [
- for (tb=[0,1], j=[0,1], i = [0:1:4]) let(
- base = ((((tb*2) + j) * 5) + i) * tri
- )
- for (k = [0:1:icosa_steps-1])
- for (l = [0:1:k]) let(
- v1 = base + soff[k] + l,
- v2 = base + soff[k+1] + l,
- v3 = base + soff[k+1] + (l + 1),
- faces = [
- if(l>0) [v1-1,v1,v2],
- [v1,v3,v2],
- ],
- faces2 = (tb+j)%2? [for (f=faces) reverse(f)] : faces
- ) each faces2
- ] : []
- ) [reorient(anchor,spin,orient, r=r, p=verts), faces];
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ hsides = segs(r),
+ vsides = max(2,ceil(hsides/2)),
+ icosa_steps = round(max(5,hsides)/5),
+ rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r,
+ stagger = style=="stagger",
+ verts = style=="orig"? [
+ for (i=[0:1:vsides-1]) let(phi = (i+0.5)*180/(vsides))
+ for (j=[0:1:hsides-1]) let(theta = j*360/hsides)
+ spherical_to_xyz(rr, theta, phi),
+ ] : style=="aligned" || style=="stagger"? [
+ spherical_to_xyz(rr, 0, 0),
+ for (i=[1:1:vsides-1]) let(phi = i*180/vsides)
+ for (j=[0:1:hsides-1]) let(theta = (j+((stagger && i%2!=0)?0.5:0))*360/hsides)
+ spherical_to_xyz(rr, theta, phi),
+ spherical_to_xyz(rr, 0, 180)
+ ] : style=="icosa"? [
+ for (tb=[0,1], j=[0,2], i = [0:1:4]) let(
+ theta0 = i*360/5,
+ theta1 = (i-0.5)*360/5,
+ theta2 = (i+0.5)*360/5,
+ phi0 = 180/3 * j,
+ phi1 = 180/3,
+ v0 = spherical_to_xyz(1,theta0,phi0),
+ v1 = spherical_to_xyz(1,theta1,phi1),
+ v2 = spherical_to_xyz(1,theta2,phi1),
+ ax0 = vector_axis(v0, v1),
+ ang0 = vector_angle(v0, v1),
+ ax1 = vector_axis(v0, v2),
+ ang1 = vector_angle(v0, v2)
+ )
+ for (k = [0:1:icosa_steps]) let(
+ u = k/icosa_steps,
+ vv0 = rot(ang0*u, ax0, p=v0),
+ vv1 = rot(ang1*u, ax1, p=v0),
+ ax2 = vector_axis(vv0, vv1),
+ ang2 = vector_angle(vv0, vv1)
+ )
+ for (l = [0:1:k]) let(
+ v = k? l/k : 0,
+ pt = rot(ang2*v, v=ax2, p=vv0) * rr * (tb? -1 : 1)
+ ) pt
+ ] : assert(in_list(style,["orig","aligned","stagger","icosa"])),
+ lv = len(verts),
+ faces = style=="orig"? [
+ [for (i=[0:1:hsides-1]) hsides-i-1],
+ [for (i=[0:1:hsides-1]) lv-hsides+i],
+ for (i=[0:1:vsides-2], j=[0:1:hsides-1]) each [
+ [(i+1)*hsides+j, i*hsides+j, i*hsides+(j+1)%hsides],
+ [(i+1)*hsides+j, i*hsides+(j+1)%hsides, (i+1)*hsides+(j+1)%hsides],
+ ]
+ ] : style=="aligned" || style=="stagger"? [
+ for (i=[0:1:hsides-1]) let(
+ b2 = lv-2-hsides
+ ) each [
+ [i+1, 0, ((i+1)%hsides)+1],
+ [lv-1, b2+i+1, b2+((i+1)%hsides)+1],
+ ],
+ for (i=[0:1:vsides-3], j=[0:1:hsides-1]) let(
+ base = 1 + hsides*i
+ ) each (
+ (stagger && i%2!=0)? [
+ [base+j, base+hsides+j%hsides, base+hsides+(j+hsides-1)%hsides],
+ [base+j, base+(j+1)%hsides, base+hsides+j],
+ ] : [
+ [base+j, base+(j+1)%hsides, base+hsides+(j+1)%hsides],
+ [base+j, base+hsides+(j+1)%hsides, base+hsides+j],
+ ]
+ )
+ ] : style=="icosa"? let(
+ pyr = [for (x=[0:1:icosa_steps+1]) x],
+ tri = sum(pyr),
+ soff = cumsum(pyr)
+ ) [
+ for (tb=[0,1], j=[0,1], i = [0:1:4]) let(
+ base = ((((tb*2) + j) * 5) + i) * tri
+ )
+ for (k = [0:1:icosa_steps-1])
+ for (l = [0:1:k]) let(
+ v1 = base + soff[k] + l,
+ v2 = base + soff[k+1] + l,
+ v3 = base + soff[k+1] + (l + 1),
+ faces = [
+ if(l>0) [v1-1,v1,v2],
+ [v1,v3,v2],
+ ],
+ faces2 = (tb+j)%2? [for (f=faces) reverse(f)] : faces
+ ) each faces2
+ ] : []
+ ) [reorient(anchor,spin,orient, r=r, p=verts), faces];
@@ -1308,17 +1308,17 @@ function spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, or
// teardrop(r=30, h=10, ang=30, cap_h=20);
module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, anchor=CENTER, spin=0, orient=UP)
{
- r = get_radius(r=r, d=d, dflt=1);
- l = first_defined([l, h, 1]);
- size = [r*2,l,r*2];
- attachable(anchor,spin,orient, size=size) {
- rot(from=UP,to=FWD) {
- linear_extrude(height=l, center=true, slices=2) {
- teardrop2d(r=r, ang=ang, cap_h=cap_h);
- }
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ l = first_defined([l, h, 1]);
+ size = [r*2,l,r*2];
+ attachable(anchor,spin,orient, size=size) {
+ rot(from=UP,to=FWD) {
+ linear_extrude(height=l, center=true, slices=2) {
+ teardrop2d(r=r, ang=ang, cap_h=cap_h);
+ }
+ }
+ children();
+ }
}
@@ -1349,21 +1349,21 @@ module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, anchor=
// onion(r=30, maxang=30, cap_h=40) show_anchors();
module onion(cap_h=undef, r=undef, d=undef, maxang=45, h=undef, anchor=CENTER, spin=0, orient=UP)
{
- r = get_radius(r=r, d=d, dflt=1);
- h = first_defined([cap_h, h]);
- maxd = 3*r/tan(maxang);
- anchors = [
- ["cap", [0,0,h], UP, 0]
- ];
- attachable(anchor,spin,orient, r=r, anchors=anchors) {
- rotate_extrude(convexity=2) {
- difference() {
- teardrop2d(r=r, ang=maxang, cap_h=h);
- left(r) square(size=[2*r,maxd], center=true);
- }
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ h = first_defined([cap_h, h]);
+ maxd = 3*r/tan(maxang);
+ anchors = [
+ ["cap", [0,0,h], UP, 0]
+ ];
+ attachable(anchor,spin,orient, r=r, anchors=anchors) {
+ rotate_extrude(convexity=2) {
+ difference() {
+ teardrop2d(r=r, ang=maxang, cap_h=h);
+ left(r) square(size=[2*r,maxd], center=true);
+ }
+ }
+ children();
+ }
}
@@ -1418,28 +1418,28 @@ module noop(spin=0, orient=UP) attachable(CENTER,spin,orient, d=0.01) {nil(); ch
// Example: Conical Pie Slice
// pie_slice(ang=60, l=20, d1=50, d2=70);
module pie_slice(
- ang=30, l=undef,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef,
- h=undef, center,
- anchor, spin=0, orient=UP
+ ang=30, l=undef,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef,
+ h=undef, center,
+ anchor, spin=0, orient=UP
) {
- l = first_defined([l, h, 1]);
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
- maxd = max(r1,r2)+0.1;
- anchor = get_anchor(anchor, center, BOT, BOT);
- attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
- difference() {
- cyl(r1=r1, r2=r2, h=l);
- if (ang<180) rotate(ang) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
- difference() {
- fwd(maxd/2) cube([2*maxd, maxd, l+0.2], center=true);
- if (ang>180) rotate(ang-180) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
- }
- }
- children();
- }
+ l = first_defined([l, h, 1]);
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=10);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=10);
+ maxd = max(r1,r2)+0.1;
+ anchor = get_anchor(anchor, center, BOT, BOT);
+ attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
+ difference() {
+ cyl(r1=r1, r2=r2, h=l);
+ if (ang<180) rotate(ang) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
+ difference() {
+ fwd(maxd/2) cube([2*maxd, maxd, l+0.2], center=true);
+ if (ang>180) rotate(ang-180) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
+ }
+ }
+ children();
+ }
}
@@ -1479,19 +1479,19 @@ module pie_slice(
// interior_fillet(l=50, r=10, spin=180, orient=RIGHT);
// }
module interior_fillet(l=1.0, r=1.0, ang=90, overlap=0.01, anchor=FRONT+LEFT, spin=0, orient=UP) {
- dy = r/tan(ang/2);
- steps = ceil(segs(r)*ang/360);
- step = ang/steps;
- attachable(anchor,spin,orient, size=[r,r,l]) {
- linear_extrude(height=l, convexity=4, center=true) {
- path = concat(
- [[0,0]],
- [for (i=[0:1:steps]) let(a=270-i*step) r*[cos(a),sin(a)]+[dy,r]]
- );
- translate(-[r,r]/2) polygon(path);
- }
- children();
- }
+ dy = r/tan(ang/2);
+ steps = ceil(segs(r)*ang/360);
+ step = ang/steps;
+ attachable(anchor,spin,orient, size=[r,r,l]) {
+ linear_extrude(height=l, convexity=4, center=true) {
+ path = concat(
+ [[0,0]],
+ [for (i=[0:1:steps]) let(a=270-i*step) r*[cos(a),sin(a)]+[dy,r]]
+ );
+ translate(-[r,r]/2) polygon(path);
+ }
+ children();
+ }
}
@@ -1524,15 +1524,15 @@ module interior_fillet(l=1.0, r=1.0, ang=90, overlap=0.01, anchor=FRONT+LEFT, sp
// Example: By Length
// slot(l=50, r1=5, r2=10, h=5);
module slot(
- p1=undef, p2=undef, h=10, l=undef,
- r=undef, r1=undef, r2=undef,
- d=undef, d1=undef, d2=undef
+ p1=undef, p2=undef, h=10, l=undef,
+ r=undef, r1=undef, r2=undef,
+ d=undef, d1=undef, d2=undef
) {
- r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=5);
- r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=5);
- sides = quantup(segs(max(r1, r2)), 4);
- // TODO: implement orient and anchors.
- hull() line_of(p1=p1, p2=p2, l=l, n=2) cyl(l=h, r1=r1, r2=r2, center=true, $fn=sides);
+ r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=5);
+ r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=5);
+ sides = quantup(segs(max(r1, r2)), 4);
+ // TODO: implement orient and anchors.
+ hull() line_of(p1=p1, p2=p2, l=l, n=2) cyl(l=h, r1=r1, r2=r2, center=true, $fn=sides);
}
@@ -1568,31 +1568,31 @@ module slot(
// Example(Med): Conical Arced Slot
// arced_slot(r=60, h=5, sd1=10, sd2=15, sa=45, ea=180);
module arced_slot(
- r=undef, d=undef, h=1.0,
- sr=undef, sr1=undef, sr2=undef,
- sd=undef, sd1=undef, sd2=undef,
- sa=0, ea=90, cp=[0,0,0],
- anchor=TOP, spin=0, orient=UP,
- $fn2 = undef
+ r=undef, d=undef, h=1.0,
+ sr=undef, sr1=undef, sr2=undef,
+ sd=undef, sd1=undef, sd2=undef,
+ sa=0, ea=90, cp=[0,0,0],
+ anchor=TOP, spin=0, orient=UP,
+ $fn2 = undef
) {
- r = get_radius(r=r, d=d, dflt=2);
- sr1 = get_radius(r1=sr1, r=sr, d1=sd1, d=sd, dflt=2);
- sr2 = get_radius(r1=sr2, r=sr, d1=sd2, d=sd, dflt=2);
- fn_minor = first_defined([$fn2, $fn]);
- da = ea - sa;
- attachable(anchor,spin,orient, r1=r+sr1, r2=r+sr2, l=h) {
- translate(cp) {
- zrot(sa) {
- difference() {
- pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=UP, anchor=CENTER);
- cyl(h=h+0.1, r1=r-sr1, r2=r-sr2);
- }
- right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
- zrot(da) right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
- }
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=2);
+ sr1 = get_radius(r1=sr1, r=sr, d1=sd1, d=sd, dflt=2);
+ sr2 = get_radius(r1=sr2, r=sr, d1=sd2, d=sd, dflt=2);
+ fn_minor = first_defined([$fn2, $fn]);
+ da = ea - sa;
+ attachable(anchor,spin,orient, r1=r+sr1, r2=r+sr2, l=h) {
+ translate(cp) {
+ zrot(sa) {
+ difference() {
+ pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=UP, anchor=CENTER);
+ cyl(h=h+0.1, r1=r-sr1, r2=r-sr2);
+ }
+ right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
+ zrot(da) right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
+ }
+ }
+ children();
+ }
}
@@ -1620,88 +1620,88 @@ module arced_slot(
// }
module heightfield(heightfield, size=[100,100], bottom=0, convexity=10)
{
- size = is_num(size)? [size,size] : point2d(size);
- dim = array_dim(heightfield);
- assert(dim.x!=undef);
- assert(dim.y!=undef);
- assert(bottom0, "Width must be postive")
assert(thickness>0, "Thickness must be positive")
- arc(N,points=[[width/2,0], [0,thickness], [-width/2,0]],wedge=wedge)
- ) : is_def(angle)? (
- let(
- parmok = !any_defined([points,width,thickness]) &&
- ((is_vector(angle,2) && is_undef(start)) || is_num(angle))
- )
- assert(parmok,"Invalid parameters in arc")
- let(
- cp = first_defined([cp,[0,0]]),
- start = is_def(start)? start : is_vector(angle) ? angle[0] : 0,
- angle = is_vector(angle)? angle[1]-angle[0] : angle,
- r = get_radius(r=r, d=d)
+ arc(N,points=[[width/2,0], [0,thickness], [-width/2,0]],wedge=wedge)
+ ) : is_def(angle)? (
+ let(
+ parmok = !any_defined([points,width,thickness]) &&
+ ((is_vector(angle,2) && is_undef(start)) || is_num(angle))
+ )
+ assert(parmok,"Invalid parameters in arc")
+ let(
+ cp = first_defined([cp,[0,0]]),
+ start = is_def(start)? start : is_vector(angle) ? angle[0] : 0,
+ angle = is_vector(angle)? angle[1]-angle[0] : angle,
+ r = get_radius(r=r, d=d)
)
assert(is_vector(cp,2),"Centerpoint must be a 2d vector")
assert(angle!=0, "Arc has zero length")
assert(r>0, "Arc radius invalid")
let(
- N = max(3, is_undef(N)? ceil(segs(r)*abs(angle)/360) : N),
- arcpoints = [for(i=[0:N-1]) let(theta = start + i*angle/(N-1)) r*[cos(theta),sin(theta)]+cp],
- extra = wedge? [cp] : []
- )
- concat(extra,arcpoints)
- ) :
- assert(is_path(points,[2,3]),"Point list is invalid")
- // Arc is 3D, so transform points to 2D and make a recursive call, then remap back to 3D
- len(points[0])==3? (
+ N = max(3, is_undef(N)? ceil(segs(r)*abs(angle)/360) : N),
+ arcpoints = [for(i=[0:N-1]) let(theta = start + i*angle/(N-1)) r*[cos(theta),sin(theta)]+cp],
+ extra = wedge? [cp] : []
+ )
+ concat(extra,arcpoints)
+ ) :
+ assert(is_path(points,[2,3]),"Point list is invalid")
+ // Arc is 3D, so transform points to 2D and make a recursive call, then remap back to 3D
+ len(points[0])==3? (
assert(!(cw || ccw), "(Counter)clockwise isn't meaningful in 3d, so `cw` and `ccw` must be false")
assert(is_undef(cp) || is_vector(cp,3),"points are 3d so cp must be 3d")
- let(
- thirdpoint = is_def(cp) ? cp : points[2],
- center2d = is_def(cp) ? project_plane(cp,thirdpoint,points[0],points[1]) : undef,
- points2d = project_plane(points,thirdpoint,points[0],points[1])
- )
- lift_plane(arc(N,cp=center2d,points=points2d,wedge=wedge,long=long),thirdpoint,points[0],points[1])
- ) : is_def(cp)? (
- // Arc defined by center plus two points, will have radius defined by center and points[0]
- // and extent defined by direction of point[1] from the center
+ let(
+ thirdpoint = is_def(cp) ? cp : points[2],
+ center2d = is_def(cp) ? project_plane(cp,thirdpoint,points[0],points[1]) : undef,
+ points2d = project_plane(points,thirdpoint,points[0],points[1])
+ )
+ lift_plane(arc(N,cp=center2d,points=points2d,wedge=wedge,long=long),thirdpoint,points[0],points[1])
+ ) : is_def(cp)? (
+ // Arc defined by center plus two points, will have radius defined by center and points[0]
+ // and extent defined by direction of point[1] from the center
assert(is_vector(cp,2), "Centerpoint must be a 2d vector")
assert(len(points)==2, "When pointlist has length 3 centerpoint is not allowed")
assert(points[0]!=points[1], "Arc endpoints are equal")
assert(cp!=points[0]&&cp!=points[1], "Centerpoint equals an arc endpoint")
assert(count_true([long,cw,ccw])<=1, str("Only one of `long`, `cw` and `ccw` can be true",cw,ccw,long))
- let(
- angle = vector_angle(points[0], cp, points[1]),
- v1 = points[0]-cp,
- v2 = points[1]-cp,
- prelim_dir = sign(det2([v1,v2])), // z component of cross product
+ let(
+ angle = vector_angle(points[0], cp, points[1]),
+ v1 = points[0]-cp,
+ v2 = points[1]-cp,
+ prelim_dir = sign(det2([v1,v2])), // z component of cross product
dir = prelim_dir != 0
? prelim_dir
: assert(cw || ccw, "Collinear inputs don't define a unique arc")
1,
- r=norm(v1),
+ r=norm(v1),
final_angle = long || (ccw && dir<0) || (cw && dir>0) ? -dir*(360-angle) : dir*angle
- )
- arc(N,cp=cp,r=r,start=atan2(v1.y,v1.x),angle=final_angle,wedge=wedge)
- ) : (
- // Final case is arc passing through three points, starting at point[0] and ending at point[3]
- let(col = collinear(points[0],points[1],points[2]))
- assert(!col, "Collinear inputs do not define an arc")
- let(
- cp = line_intersection(_normal_segment(points[0],points[1]),_normal_segment(points[1],points[2])),
- // select order to be counterclockwise
- dir = det2([points[1]-points[0],points[2]-points[1]]) > 0,
- points = dir? select(points,[0,2]) : select(points,[2,0]),
- r = norm(points[0]-cp),
- theta_start = atan2(points[0].y-cp.y, points[0].x-cp.x),
- theta_end = atan2(points[1].y-cp.y, points[1].x-cp.x),
- angle = posmod(theta_end-theta_start, 360),
- arcpts = arc(N,cp=cp,r=r,start=theta_start,angle=angle,wedge=wedge)
- )
- dir ? arcpts : reverse(arcpts)
- );
+ )
+ arc(N,cp=cp,r=r,start=atan2(v1.y,v1.x),angle=final_angle,wedge=wedge)
+ ) : (
+ // Final case is arc passing through three points, starting at point[0] and ending at point[3]
+ let(col = collinear(points[0],points[1],points[2]))
+ assert(!col, "Collinear inputs do not define an arc")
+ let(
+ cp = line_intersection(_normal_segment(points[0],points[1]),_normal_segment(points[1],points[2])),
+ // select order to be counterclockwise
+ dir = det2([points[1]-points[0],points[2]-points[1]]) > 0,
+ points = dir? select(points,[0,2]) : select(points,[2,0]),
+ r = norm(points[0]-cp),
+ theta_start = atan2(points[0].y-cp.y, points[0].x-cp.x),
+ theta_end = atan2(points[1].y-cp.y, points[1].x-cp.x),
+ angle = posmod(theta_end-theta_start, 360),
+ arcpts = arc(N,cp=cp,r=r,start=theta_start,angle=angle,wedge=wedge)
+ )
+ dir ? arcpts : reverse(arcpts)
+ );
module arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false)
{
- path = arc(N=N, r=r, angle=angle, d=d, cp=cp, points=points, width=width, thickness=thickness, start=start, wedge=wedge);
- polygon(path);
+ path = arc(N=N, r=r, angle=angle, d=d, cp=cp, points=points, width=width, thickness=thickness, start=start, wedge=wedge);
+ polygon(path);
}
function _normal_segment(p1,p2) =
- let(center = (p1+p2)/2)
- [center, center + norm(p1-p2)/2 * line_normal(p1,p2)];
+ let(center = (p1+p2)/2)
+ [center, center + norm(p1-p2)/2 * line_normal(p1,p2)];
// Function: turtle()
@@ -574,145 +574,145 @@ function _normal_segment(p1,p2) =
// koch=concat(["angle",60,"repeat",3],[concat(koch_unit(3),["left","left"])]);
// polygon(turtle(koch));
function turtle(commands, state=[[[0,0]],[1,0],90,0], full_state=false, repeat=1) =
- let( state = is_vector(state) ? [[state],[1,0],90,0] : state )
- repeat == 1?
- _turtle(commands,state,full_state) :
- _turtle_repeat(commands, state, full_state, repeat);
+ let( state = is_vector(state) ? [[state],[1,0],90,0] : state )
+ repeat == 1?
+ _turtle(commands,state,full_state) :
+ _turtle_repeat(commands, state, full_state, repeat);
function _turtle_repeat(commands, state, full_state, repeat) =
- repeat==1?
- _turtle(commands,state,full_state) :
- _turtle_repeat(commands, _turtle(commands, state, true), full_state, repeat-1);
+ repeat==1?
+ _turtle(commands,state,full_state) :
+ _turtle_repeat(commands, _turtle(commands, state, true), full_state, repeat-1);
function _turtle_command_len(commands, index) =
- let( one_or_two_arg = ["arcleft","arcright", "arcleftto", "arcrightto"] )
- commands[index] == "repeat"? 3 : // Repeat command requires 2 args
- // For these, the first arg is required, second arg is present if it is not a string
- in_list(commands[index], one_or_two_arg) && len(commands)>index+2 && !is_string(commands[index+2]) ? 3 :
- is_string(commands[index+1])? 1 : // If 2nd item is a string it's must be a new command
- 2; // Otherwise we have command and arg
+ let( one_or_two_arg = ["arcleft","arcright", "arcleftto", "arcrightto"] )
+ commands[index] == "repeat"? 3 : // Repeat command requires 2 args
+ // For these, the first arg is required, second arg is present if it is not a string
+ in_list(commands[index], one_or_two_arg) && len(commands)>index+2 && !is_string(commands[index+2]) ? 3 :
+ is_string(commands[index+1])? 1 : // If 2nd item is a string it's must be a new command
+ 2; // Otherwise we have command and arg
function _turtle(commands, state, full_state, index=0) =
- index < len(commands) ?
- _turtle(commands,
- _turtle_command(commands[index],commands[index+1],commands[index+2],state,index),
- full_state,
- index+_turtle_command_len(commands,index)
- ) :
- ( full_state ? state : state[0] );
+ index < len(commands) ?
+ _turtle(commands,
+ _turtle_command(commands[index],commands[index+1],commands[index+2],state,index),
+ full_state,
+ index+_turtle_command_len(commands,index)
+ ) :
+ ( full_state ? state : state[0] );
// Turtle state: state = [path, step_vector, default angle]
function _turtle_command(command, parm, parm2, state, index) =
- command == "repeat"?
- assert(is_num(parm),str("\"repeat\" command requires a numeric repeat count at index ",index))
- assert(is_list(parm2),str("\"repeat\" command requires a command list parameter at index ",index))
- _turtle_repeat(parm2, state, true, parm) :
- let(
- path = 0,
- step=1,
- angle=2,
- arcsteps=3,
- parm = !is_string(parm) ? parm : undef,
- parm2 = !is_string(parm2) ? parm2 : undef,
- needvec = ["jump", "xymove"],
- neednum = ["untilx","untily","xjump","yjump","angle","length","scale","addlength"],
- needeither = ["setdir"],
- chvec = !in_list(command,needvec) || is_vector(parm,2),
- chnum = !in_list(command,neednum) || is_num(parm),
- vec_or_num = !in_list(command,needeither) || (is_num(parm) || is_vector(parm,2)),
- lastpt = select(state[path],-1)
- )
- assert(chvec,str("\"",command,"\" requires a vector parameter at index ",index))
- assert(chnum,str("\"",command,"\" requires a numeric parameter at index ",index))
- assert(vec_or_num,str("\"",command,"\" requires a vector or numeric parameter at index ",index))
+ command == "repeat"?
+ assert(is_num(parm),str("\"repeat\" command requires a numeric repeat count at index ",index))
+ assert(is_list(parm2),str("\"repeat\" command requires a command list parameter at index ",index))
+ _turtle_repeat(parm2, state, true, parm) :
+ let(
+ path = 0,
+ step=1,
+ angle=2,
+ arcsteps=3,
+ parm = !is_string(parm) ? parm : undef,
+ parm2 = !is_string(parm2) ? parm2 : undef,
+ needvec = ["jump", "xymove"],
+ neednum = ["untilx","untily","xjump","yjump","angle","length","scale","addlength"],
+ needeither = ["setdir"],
+ chvec = !in_list(command,needvec) || is_vector(parm,2),
+ chnum = !in_list(command,neednum) || is_num(parm),
+ vec_or_num = !in_list(command,needeither) || (is_num(parm) || is_vector(parm,2)),
+ lastpt = select(state[path],-1)
+ )
+ assert(chvec,str("\"",command,"\" requires a vector parameter at index ",index))
+ assert(chnum,str("\"",command,"\" requires a numeric parameter at index ",index))
+ assert(vec_or_num,str("\"",command,"\" requires a vector or numeric parameter at index ",index))
- command=="move" ? list_set(state, path, concat(state[path],[default(parm,1)*state[step]+lastpt])) :
- command=="untilx" ? (
- let(
- int = line_intersection([lastpt,lastpt+state[step]], [[parm,0],[parm,1]]),
- xgood = sign(state[step].x) == sign(int.x-lastpt.x)
- )
- assert(xgood,str("\"untilx\" never reaches desired goal at index ",index))
- list_set(state,path,concat(state[path],[int]))
- ) :
- command=="untily" ? (
- let(
- int = line_intersection([lastpt,lastpt+state[step]], [[0,parm],[1,parm]]),
- ygood = is_def(int) && sign(state[step].y) == sign(int.y-lastpt.y)
- )
- assert(ygood,str("\"untily\" never reaches desired goal at index ",index))
- list_set(state,path,concat(state[path],[int]))
- ) :
- command=="xmove" ? list_set(state, path, concat(state[path],[default(parm,1)*norm(state[step])*[1,0]+lastpt])):
- command=="ymove" ? list_set(state, path, concat(state[path],[default(parm,1)*norm(state[step])*[0,1]+lastpt])):
+ command=="move" ? list_set(state, path, concat(state[path],[default(parm,1)*state[step]+lastpt])) :
+ command=="untilx" ? (
+ let(
+ int = line_intersection([lastpt,lastpt+state[step]], [[parm,0],[parm,1]]),
+ xgood = sign(state[step].x) == sign(int.x-lastpt.x)
+ )
+ assert(xgood,str("\"untilx\" never reaches desired goal at index ",index))
+ list_set(state,path,concat(state[path],[int]))
+ ) :
+ command=="untily" ? (
+ let(
+ int = line_intersection([lastpt,lastpt+state[step]], [[0,parm],[1,parm]]),
+ ygood = is_def(int) && sign(state[step].y) == sign(int.y-lastpt.y)
+ )
+ assert(ygood,str("\"untily\" never reaches desired goal at index ",index))
+ list_set(state,path,concat(state[path],[int]))
+ ) :
+ command=="xmove" ? list_set(state, path, concat(state[path],[default(parm,1)*norm(state[step])*[1,0]+lastpt])):
+ command=="ymove" ? list_set(state, path, concat(state[path],[default(parm,1)*norm(state[step])*[0,1]+lastpt])):
command=="xymove" ? list_set(state, path, concat(state[path], [lastpt+parm])):
- command=="jump" ? list_set(state, path, concat(state[path],[parm])):
- command=="xjump" ? list_set(state, path, concat(state[path],[[parm,lastpt.y]])):
- command=="yjump" ? list_set(state, path, concat(state[path],[[lastpt.x,parm]])):
- command=="turn" || command=="left" ? list_set(state, step, rot(default(parm,state[angle]),p=state[step],planar=true)) :
- command=="right" ? list_set(state, step, rot(-default(parm,state[angle]),p=state[step],planar=true)) :
- command=="angle" ? list_set(state, angle, parm) :
- command=="setdir" ? (
- is_vector(parm) ?
- list_set(state, step, norm(state[step]) * unit(parm)) :
- list_set(state, step, norm(state[step]) * [cos(parm),sin(parm)])
- ) :
- command=="length" ? list_set(state, step, parm*unit(state[step])) :
- command=="scale" ? list_set(state, step, parm*state[step]) :
- command=="addlength" ? list_set(state, step, state[step]+unit(state[step])*parm) :
- command=="arcsteps" ? list_set(state, arcsteps, parm) :
- command=="arcleft" || command=="arcright" ?
- assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
- let(
- myangle = default(parm2,state[angle]),
- lrsign = command=="arcleft" ? 1 : -1,
- radius = parm*sign(myangle),
- center = lastpt + lrsign*radius*line_normal([0,0],state[step]),
- steps = state[arcsteps]==0 ? segs(abs(radius)) : state[arcsteps],
- arcpath = myangle == 0 || radius == 0 ? [] : arc(
- steps,
- points = [
- lastpt,
- rot(cp=center, p=lastpt, a=sign(parm)*lrsign*myangle/2),
- rot(cp=center, p=lastpt, a=sign(parm)*lrsign*myangle)
- ]
- )
- )
- list_set(
- state, [path,step], [
- concat(state[path], slice(arcpath,1,-1)),
- rot(lrsign * myangle,p=state[step],planar=true)
- ]
- ) :
- command=="arcleftto" || command=="arcrightto" ?
- assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
- assert(is_num(parm2),str("\"",command,"\" command requires a numeric angle value at index ",index))
- let(
- radius = parm,
- lrsign = command=="arcleftto" ? 1 : -1,
- center = lastpt + lrsign*radius*line_normal([0,0],state[step]),
- steps = state[arcsteps]==0 ? segs(abs(radius)) : state[arcsteps],
- start_angle = posmod(atan2(state[step].y, state[step].x),360),
- end_angle = posmod(parm2,360),
- delta_angle = -start_angle + (lrsign * end_angle < lrsign*start_angle ? end_angle+lrsign*360 : end_angle),
- arcpath = delta_angle == 0 || radius==0 ? [] : arc(
- steps,
- points = [
- lastpt,
- rot(cp=center, p=lastpt, a=sign(radius)*delta_angle/2),
- rot(cp=center, p=lastpt, a=sign(radius)*delta_angle)
- ]
- )
- )
- list_set(
- state, [path,step], [
- concat(state[path], slice(arcpath,1,-1)),
- rot(delta_angle,p=state[step],planar=true)
- ]
- ) :
- assert(false,str("Unknown turtle command \"",command,"\" at index",index))
- [];
+ command=="jump" ? list_set(state, path, concat(state[path],[parm])):
+ command=="xjump" ? list_set(state, path, concat(state[path],[[parm,lastpt.y]])):
+ command=="yjump" ? list_set(state, path, concat(state[path],[[lastpt.x,parm]])):
+ command=="turn" || command=="left" ? list_set(state, step, rot(default(parm,state[angle]),p=state[step],planar=true)) :
+ command=="right" ? list_set(state, step, rot(-default(parm,state[angle]),p=state[step],planar=true)) :
+ command=="angle" ? list_set(state, angle, parm) :
+ command=="setdir" ? (
+ is_vector(parm) ?
+ list_set(state, step, norm(state[step]) * unit(parm)) :
+ list_set(state, step, norm(state[step]) * [cos(parm),sin(parm)])
+ ) :
+ command=="length" ? list_set(state, step, parm*unit(state[step])) :
+ command=="scale" ? list_set(state, step, parm*state[step]) :
+ command=="addlength" ? list_set(state, step, state[step]+unit(state[step])*parm) :
+ command=="arcsteps" ? list_set(state, arcsteps, parm) :
+ command=="arcleft" || command=="arcright" ?
+ assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
+ let(
+ myangle = default(parm2,state[angle]),
+ lrsign = command=="arcleft" ? 1 : -1,
+ radius = parm*sign(myangle),
+ center = lastpt + lrsign*radius*line_normal([0,0],state[step]),
+ steps = state[arcsteps]==0 ? segs(abs(radius)) : state[arcsteps],
+ arcpath = myangle == 0 || radius == 0 ? [] : arc(
+ steps,
+ points = [
+ lastpt,
+ rot(cp=center, p=lastpt, a=sign(parm)*lrsign*myangle/2),
+ rot(cp=center, p=lastpt, a=sign(parm)*lrsign*myangle)
+ ]
+ )
+ )
+ list_set(
+ state, [path,step], [
+ concat(state[path], slice(arcpath,1,-1)),
+ rot(lrsign * myangle,p=state[step],planar=true)
+ ]
+ ) :
+ command=="arcleftto" || command=="arcrightto" ?
+ assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
+ assert(is_num(parm2),str("\"",command,"\" command requires a numeric angle value at index ",index))
+ let(
+ radius = parm,
+ lrsign = command=="arcleftto" ? 1 : -1,
+ center = lastpt + lrsign*radius*line_normal([0,0],state[step]),
+ steps = state[arcsteps]==0 ? segs(abs(radius)) : state[arcsteps],
+ start_angle = posmod(atan2(state[step].y, state[step].x),360),
+ end_angle = posmod(parm2,360),
+ delta_angle = -start_angle + (lrsign * end_angle < lrsign*start_angle ? end_angle+lrsign*360 : end_angle),
+ arcpath = delta_angle == 0 || radius==0 ? [] : arc(
+ steps,
+ points = [
+ lastpt,
+ rot(cp=center, p=lastpt, a=sign(radius)*delta_angle/2),
+ rot(cp=center, p=lastpt, a=sign(radius)*delta_angle)
+ ]
+ )
+ )
+ list_set(
+ state, [path,step], [
+ concat(state[path], slice(arcpath,1,-1)),
+ rot(delta_angle,p=state[step],planar=true)
+ ]
+ ) :
+ assert(false,str("Unknown turtle command \"",command,"\" at index",index))
+ [];
@@ -750,70 +750,70 @@ function _turtle_command(command, parm, parm2, state, index) =
// stroke(path, closed=true);
// move_copies(path) color("blue") circle(d=2,$fn=8);
module rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) {
- size = is_num(size)? [size,size] : point2d(size);
- anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT);
- if (rounding==0 && chamfer==0) {
- attachable(anchor,spin, two_d=true, size=size) {
- square(size, center=true);
- children();
- }
- } else {
- pts = rect(size=size, rounding=rounding, chamfer=chamfer, center=true);
- attachable(anchor,spin, two_d=true, path=pts) {
- polygon(pts);
- children();
- }
- }
+ size = is_num(size)? [size,size] : point2d(size);
+ anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT);
+ if (rounding==0 && chamfer==0) {
+ attachable(anchor,spin, two_d=true, size=size) {
+ square(size, center=true);
+ children();
+ }
+ } else {
+ pts = rect(size=size, rounding=rounding, chamfer=chamfer, center=true);
+ attachable(anchor,spin, two_d=true, path=pts) {
+ polygon(pts);
+ children();
+ }
+ }
}
function rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
- assert(is_num(size) || is_vector(size))
- assert(is_num(chamfer) || len(chamfer)==4)
- assert(is_num(rounding) || len(rounding)==4)
- let(
- size = is_num(size)? [size,size] : point2d(size),
- anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT),
- complex = rounding!=0 || chamfer!=0
- )
- (rounding==0 && chamfer==0)? let(
- path = [
- [ size.x/2, -size.y/2],
- [-size.x/2, -size.y/2],
- [-size.x/2, size.y/2],
- [ size.x/2, size.y/2]
- ]
- ) rot(spin, p=move(-vmul(anchor,size/2), p=path)) :
- let(
- chamfer = is_list(chamfer)? chamfer : [for (i=[0:3]) chamfer],
- rounding = is_list(rounding)? rounding : [for (i=[0:3]) rounding],
- quadorder = [3,2,1,0],
- quadpos = [[1,1],[-1,1],[-1,-1],[1,-1]],
- insets = [for (i=[0:3]) chamfer[i]>0? chamfer[i] : rounding[i]>0? rounding[i] : 0],
- insets_x = max(insets[0]+insets[1],insets[2]+insets[3]),
- insets_y = max(insets[0]+insets[3],insets[1]+insets[2])
- )
- assert(insets_x <= size.x, "Requested roundings and/or chamfers exceed the rect width.")
- assert(insets_y <= size.y, "Requested roundings and/or chamfers exceed the rect height.")
- let(
- path = [
- for(i = [0:3])
- let(
- quad = quadorder[i],
- inset = insets[quad],
- cverts = quant(segs(inset),4)/4,
- cp = vmul(size/2-[inset,inset], quadpos[quad]),
- step = 90/cverts,
- angs =
- chamfer[quad] > 0? [0,-90]-90*[i,i] :
- rounding[quad] > 0? [for (j=[0:1:cverts]) 360-j*step-i*90] :
- [0]
- )
- each [for (a = angs) cp + inset*[cos(a),sin(a)]]
- ]
- ) complex?
- reorient(anchor,spin, two_d=true, path=path, p=path) :
- reorient(anchor,spin, two_d=true, size=size, p=path);
+ assert(is_num(size) || is_vector(size))
+ assert(is_num(chamfer) || len(chamfer)==4)
+ assert(is_num(rounding) || len(rounding)==4)
+ let(
+ size = is_num(size)? [size,size] : point2d(size),
+ anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT),
+ complex = rounding!=0 || chamfer!=0
+ )
+ (rounding==0 && chamfer==0)? let(
+ path = [
+ [ size.x/2, -size.y/2],
+ [-size.x/2, -size.y/2],
+ [-size.x/2, size.y/2],
+ [ size.x/2, size.y/2]
+ ]
+ ) rot(spin, p=move(-vmul(anchor,size/2), p=path)) :
+ let(
+ chamfer = is_list(chamfer)? chamfer : [for (i=[0:3]) chamfer],
+ rounding = is_list(rounding)? rounding : [for (i=[0:3]) rounding],
+ quadorder = [3,2,1,0],
+ quadpos = [[1,1],[-1,1],[-1,-1],[1,-1]],
+ insets = [for (i=[0:3]) chamfer[i]>0? chamfer[i] : rounding[i]>0? rounding[i] : 0],
+ insets_x = max(insets[0]+insets[1],insets[2]+insets[3]),
+ insets_y = max(insets[0]+insets[3],insets[1]+insets[2])
+ )
+ assert(insets_x <= size.x, "Requested roundings and/or chamfers exceed the rect width.")
+ assert(insets_y <= size.y, "Requested roundings and/or chamfers exceed the rect height.")
+ let(
+ path = [
+ for(i = [0:3])
+ let(
+ quad = quadorder[i],
+ inset = insets[quad],
+ cverts = quant(segs(inset),4)/4,
+ cp = vmul(size/2-[inset,inset], quadpos[quad]),
+ step = 90/cverts,
+ angs =
+ chamfer[quad] > 0? [0,-90]-90*[i,i] :
+ rounding[quad] > 0? [for (j=[0:1:cverts]) 360-j*step-i*90] :
+ [0]
+ )
+ each [for (a = angs) cp + inset*[cos(a),sin(a)]]
+ ]
+ ) complex?
+ reorient(anchor,spin, two_d=true, path=path, p=path) :
+ reorient(anchor,spin, two_d=true, size=size, p=path);
// Function&Module: oval()
@@ -840,40 +840,40 @@ function rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
// Example(NORENDER): Called as Function
// path = oval(d=50, anchor=FRONT, spin=45);
module oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) {
- r = get_radius(r=r, d=d, dflt=1);
- sides = segs(max(r));
- sc = circum? (1 / cos(180/sides)) : 1;
- rx = default(r[0],r) * sc;
- ry = default(r[1],r) * sc;
- attachable(anchor,spin, two_d=true, r=[rx,ry]) {
- if (rx < ry) {
- xscale(rx/ry) {
- zrot(realign? 180/sides : 0) {
- circle(r=ry, $fn=sides);
- }
- }
- } else {
- yscale(ry/rx) {
- zrot(realign? 180/sides : 0) {
- circle(r=rx, $fn=sides);
- }
- }
- }
- children();
- }
+ r = get_radius(r=r, d=d, dflt=1);
+ sides = segs(max(r));
+ sc = circum? (1 / cos(180/sides)) : 1;
+ rx = default(r[0],r) * sc;
+ ry = default(r[1],r) * sc;
+ attachable(anchor,spin, two_d=true, r=[rx,ry]) {
+ if (rx < ry) {
+ xscale(rx/ry) {
+ zrot(realign? 180/sides : 0) {
+ circle(r=ry, $fn=sides);
+ }
+ }
+ } else {
+ yscale(ry/rx) {
+ zrot(realign? 180/sides : 0) {
+ circle(r=rx, $fn=sides);
+ }
+ }
+ }
+ children();
+ }
}
function oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
- let(
- r = get_radius(r=r, d=d, dflt=1),
- sides = segs(max(r)),
- offset = realign? 180/sides : 0,
- sc = circum? (1 / cos(180/sides)) : 1,
- rx = default(r[0],r) * sc,
- ry = default(r[1],r) * sc,
- pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) [rx*cos(a), ry*sin(a)]]
- ) reorient(anchor,spin, two_d=true, r=[rx,ry], p=pts);
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ sides = segs(max(r)),
+ offset = realign? 180/sides : 0,
+ sc = circum? (1 / cos(180/sides)) : 1,
+ rx = default(r[0],r) * sc,
+ ry = default(r[1],r) * sc,
+ pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) [rx*cos(a), ry*sin(a)]]
+ ) reorient(anchor,spin, two_d=true, r=[rx,ry], p=pts);
@@ -918,67 +918,67 @@ function oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
// Example(2D): Called as Function
// stroke(closed=true, regular_ngon(n=6, or=30));
function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) =
- let(
- sc = 1/cos(180/n),
- r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n))
- )
- assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.")
- let(
- inset = opp_ang_to_hyp(rounding, (180-360/n)/2),
- path = rounding==0? oval(r=r, realign=realign, $fn=n) : (
- let(
- steps = floor(segs(r)/n),
- step = 360/n/steps,
- path2 = [
- for (i = [0:1:n-1]) let(
- a = 360 - i*360/n - (realign? 180/n : 0),
- p = polar_to_xy(r-inset, a)
- )
- each arc(N=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n)
- ],
- maxx_idx = max_index(subindex(path2,0)),
- path3 = polygon_shift(path2,maxx_idx)
- ) path3
- ),
- anchors = !is_string(anchor)? [] : [
- for (i = [0:1:n-1]) let(
- a1 = 360 - i*360/n - (realign? 180/n : 0),
- a2 = a1 - 360/n,
- p1 = polar_to_xy(r,a1),
- p2 = polar_to_xy(r,a2),
- 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),
- ]
- ]
- ) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path, anchors=anchors);
+ let(
+ sc = 1/cos(180/n),
+ r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n))
+ )
+ assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.")
+ let(
+ inset = opp_ang_to_hyp(rounding, (180-360/n)/2),
+ path = rounding==0? oval(r=r, realign=realign, $fn=n) : (
+ let(
+ steps = floor(segs(r)/n),
+ step = 360/n/steps,
+ path2 = [
+ for (i = [0:1:n-1]) let(
+ a = 360 - i*360/n - (realign? 180/n : 0),
+ p = polar_to_xy(r-inset, a)
+ )
+ each arc(N=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n)
+ ],
+ maxx_idx = max_index(subindex(path2,0)),
+ path3 = polygon_shift(path2,maxx_idx)
+ ) path3
+ ),
+ anchors = !is_string(anchor)? [] : [
+ for (i = [0:1:n-1]) let(
+ a1 = 360 - i*360/n - (realign? 180/n : 0),
+ a2 = a1 - 360/n,
+ p1 = polar_to_xy(r,a1),
+ p2 = polar_to_xy(r,a2),
+ 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),
+ ]
+ ]
+ ) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path, anchors=anchors);
module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) {
- sc = 1/cos(180/n);
- r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n));
- assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.");
- path = regular_ngon(n=n, r=r, rounding=rounding, realign=realign);
- inset = opp_ang_to_hyp(rounding, (180-360/n)/2);
- anchors = [
- for (i = [0:1:n-1]) let(
- a1 = 360 - i*360/n - (realign? 180/n : 0),
- a2 = a1 - 360/n,
- p1 = polar_to_xy(r,a1),
- p2 = polar_to_xy(r,a2),
- 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),
- ]
- ];
- attachable(anchor,spin, two_d=true, path=path, extent=false, anchors=anchors) {
- polygon(path);
- children();
- }
+ sc = 1/cos(180/n);
+ r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n));
+ assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.");
+ path = regular_ngon(n=n, r=r, rounding=rounding, realign=realign);
+ inset = opp_ang_to_hyp(rounding, (180-360/n)/2);
+ anchors = [
+ for (i = [0:1:n-1]) let(
+ a1 = 360 - i*360/n - (realign? 180/n : 0),
+ a2 = a1 - 360/n,
+ p1 = polar_to_xy(r,a1),
+ p2 = polar_to_xy(r,a2),
+ 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),
+ ]
+ ];
+ attachable(anchor,spin, two_d=true, path=path, extent=false, anchors=anchors) {
+ polygon(path);
+ children();
+ }
}
@@ -1020,11 +1020,11 @@ module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false,
// Example(2D): Called as Function
// stroke(closed=true, pentagon(or=30));
function pentagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) =
- regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
+ regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
module pentagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0)
- regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
+ regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
// Function&Module: hexagon()
@@ -1063,11 +1063,11 @@ module pentagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CE
// Example(2D): Called as Function
// stroke(closed=true, hexagon(or=30));
function hexagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) =
- regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
+ regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
module hexagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0)
- regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
+ regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
// Function&Module: octagon()
@@ -1106,11 +1106,11 @@ module hexagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CEN
// Example(2D): Called as Function
// stroke(closed=true, octagon(or=30));
function octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) =
- regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
+ regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin);
module octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0)
- regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
+ regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, rounding=rounding, realign=realign, anchor=anchor, spin=spin) children();
@@ -1136,18 +1136,18 @@ module octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CEN
// Example(2D): Called as Function
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20));
function trapezoid(h, w1, w2, anchor=CENTER, spin=0) =
- let(
- path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]]
- ) reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, p=path);
+ let(
+ path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]]
+ ) reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, p=path);
module trapezoid(h, w1, w2, anchor=CENTER, spin=0) {
- path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]];
- attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2) {
- polygon(path);
- children();
- }
+ path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]];
+ attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2) {
+ polygon(path);
+ children();
+ }
}
@@ -1175,37 +1175,37 @@ module trapezoid(h, w1, w2, anchor=CENTER, spin=0) {
// teardrop2d(r=30, ang=30, cap_h=20);
module teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0)
{
- path = teardrop2d(r=r, d=d, ang=ang, cap_h=cap_h);
- attachable(anchor,spin, two_d=true, path=path) {
- polygon(path);
- children();
- }
+ path = teardrop2d(r=r, d=d, ang=ang, cap_h=cap_h);
+ attachable(anchor,spin, two_d=true, path=path) {
+ polygon(path);
+ children();
+ }
}
function teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0) =
- let(
- r = get_radius(r=r, d=d, dflt=1),
- cord = 2 * r * cos(ang),
- cord_h = r * sin(ang),
- tip_y = (cord/2)/tan(ang),
- cap_h = min((!is_undef(cap_h)? cap_h : tip_y+cord_h), tip_y+cord_h),
- cap_w = cord * (1 - (cap_h - cord_h)/tip_y),
- ang = min(ang,asin(cap_h/r)),
- sa = 180 - ang,
- ea = 360 + ang,
- steps = segs(r)*(ea-sa)/360,
- step = (ea-sa)/steps,
- path = deduplicate(
- [
- [ cap_w/2,cap_h],
- for (i=[0:1:steps]) let(a=ea-i*step) r*[cos(a),sin(a)],
- [-cap_w/2,cap_h]
- ], closed=true
- ),
- maxx_idx = max_index(subindex(path,0)),
- path2 = polygon_shift(path,maxx_idx)
- ) reorient(anchor,spin, two_d=true, path=path2, p=path2);
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ cord = 2 * r * cos(ang),
+ cord_h = r * sin(ang),
+ tip_y = (cord/2)/tan(ang),
+ cap_h = min((!is_undef(cap_h)? cap_h : tip_y+cord_h), tip_y+cord_h),
+ cap_w = cord * (1 - (cap_h - cord_h)/tip_y),
+ ang = min(ang,asin(cap_h/r)),
+ sa = 180 - ang,
+ ea = 360 + ang,
+ steps = segs(r)*(ea-sa)/360,
+ step = (ea-sa)/steps,
+ path = deduplicate(
+ [
+ [ cap_w/2,cap_h],
+ for (i=[0:1:steps]) let(a=ea-i*step) r*[cos(a),sin(a)],
+ [-cap_w/2,cap_h]
+ ], closed=true
+ ),
+ maxx_idx = max_index(subindex(path,0)),
+ path2 = polygon_shift(path,maxx_idx)
+ ) reorient(anchor,spin, two_d=true, path=path2, p=path2);
@@ -1230,38 +1230,38 @@ function teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0) =
// Example(2D): Called as Function
// stroke(closed=true, glued_circles(r=15, spread=40, tangent=45));
function glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) =
- let(
- r = get_radius(r=r, d=d, dflt=10),
- r2 = (spread/2 / sin(tangent)) - r,
- cp1 = [spread/2, 0],
- cp2 = [0, (r+r2)*cos(tangent)],
- sa1 = 90-tangent,
- ea1 = 270+tangent,
- lobearc = ea1-sa1,
- lobesegs = floor(segs(r)*lobearc/360),
- lobestep = lobearc / lobesegs,
- sa2 = 270-tangent,
- ea2 = 270+tangent,
- subarc = ea2-sa2,
- arcsegs = ceil(segs(r2)*abs(subarc)/360),
- arcstep = subarc / arcsegs,
- path = concat(
- [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1],
- tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2],
- [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1],
- tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2]
- ),
- maxx_idx = max_index(subindex(path,0)),
- path2 = reverse_polygon(polygon_shift(path,maxx_idx))
- ) reorient(anchor,spin, two_d=true, path=path2, extent=true, p=path2);
+ let(
+ r = get_radius(r=r, d=d, dflt=10),
+ r2 = (spread/2 / sin(tangent)) - r,
+ cp1 = [spread/2, 0],
+ cp2 = [0, (r+r2)*cos(tangent)],
+ sa1 = 90-tangent,
+ ea1 = 270+tangent,
+ lobearc = ea1-sa1,
+ lobesegs = floor(segs(r)*lobearc/360),
+ lobestep = lobearc / lobesegs,
+ sa2 = 270-tangent,
+ ea2 = 270+tangent,
+ subarc = ea2-sa2,
+ arcsegs = ceil(segs(r2)*abs(subarc)/360),
+ arcstep = subarc / arcsegs,
+ path = concat(
+ [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1],
+ tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2],
+ [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1],
+ tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2]
+ ),
+ maxx_idx = max_index(subindex(path,0)),
+ path2 = reverse_polygon(polygon_shift(path,maxx_idx))
+ ) reorient(anchor,spin, two_d=true, path=path2, extent=true, p=path2);
module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) {
- path = glued_circles(r=r, d=d, spread=spread, tangent=tangent);
- attachable(anchor,spin, two_d=true, path=path, extent=true) {
- polygon(path);
- children();
- }
+ path = glued_circles(r=r, d=d, spread=spread, tangent=tangent);
+ attachable(anchor,spin, two_d=true, path=path, extent=true) {
+ polygon(path);
+ children();
+ }
}
@@ -1297,66 +1297,66 @@ module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) {
// Example(2D): Called as Function
// stroke(closed=true, star(n=5, r=50, ir=25));
function star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0) =
- let(
- r = get_radius(r1=or, d1=od, r=r, d=d),
- count = num_defined([ir,id,step]),
- stepOK = is_undef(step) || (step>1 && step1 && step0 && angle<90)
- assert(is_num(excess))
- let(
- r = get_radius(r=r, d=d, dflt=1),
- n = ceil(segs(r) * angle/360),
- cp = [r,r],
- tp = cp + polar_to_xy(r,180+angle),
- bp = [tp.x+adj_ang_to_opp(tp.y,angle), 0],
- step = angle/n,
- path = [
- bp, bp-[0,excess], [-excess,-excess], [-excess,r],
- for (i=[0:1:n]) cp+polar_to_xy(r,180+i*step)
- ]
- ) reorient(anchor,spin, two_d=true, path=path, p=path);
+ assert(is_num(angle))
+ assert(angle>0 && angle<90)
+ assert(is_num(excess))
+ let(
+ r = get_radius(r=r, d=d, dflt=1),
+ n = ceil(segs(r) * angle/360),
+ cp = [r,r],
+ tp = cp + polar_to_xy(r,180+angle),
+ bp = [tp.x+adj_ang_to_opp(tp.y,angle), 0],
+ step = angle/n,
+ path = [
+ bp, bp-[0,excess], [-excess,-excess], [-excess,r],
+ for (i=[0:1:n]) cp+polar_to_xy(r,180+i*step)
+ ]
+ ) reorient(anchor,spin, two_d=true, path=path, p=path);
module mask2d_teardrop(r,d,angle=45,excess=0.1,anchor=CENTER,spin=0) {
- path = mask2d_teardrop(r=r, d=d, angle=angle, excess=excess);
- attachable(anchor,spin, two_d=true, path=path) {
- polygon(path);
- children();
- }
+ path = mask2d_teardrop(r=r, d=d, angle=angle, excess=excess);
+ attachable(anchor,spin, two_d=true, path=path) {
+ polygon(path);
+ children();
+ }
}
// Function&Module: mask2d_ogee()
@@ -1773,81 +1773,81 @@ module mask2d_teardrop(r,d,angle=45,excess=0.1,anchor=CENTER,spin=0) {
// "ystep",1, "xstep",1 // Ending shoulder.
// ]);
module mask2d_ogee(pattern, excess, anchor=CENTER,spin=0) {
- path = mask2d_ogee(pattern, excess=excess);
- attachable(anchor,spin, two_d=true, path=path) {
- polygon(path);
- children();
- }
+ path = mask2d_ogee(pattern, excess=excess);
+ attachable(anchor,spin, two_d=true, path=path) {
+ polygon(path);
+ children();
+ }
}
function mask2d_ogee(pattern, excess, anchor=CENTER, spin=0) =
- assert(is_list(pattern))
- assert(len(pattern)>0)
- assert(len(pattern)%2==0,"pattern must be a list of TYPE, VAL pairs.")
- assert(all([for (i = idx(pattern,step=2)) in_list(pattern[i],["step","xstep","ystep","round","fillet"])]))
- let(
- excess = default(excess,$overlap),
- x = concat([0], cumsum([
- for (i=idx(pattern,step=2)) let(
- type = pattern[i],
- val = pattern[i+1]
- ) (
- type=="step"? val.x :
- type=="xstep"? val :
- type=="round"? val :
- type=="fillet"? val :
- 0
- )
- ])),
- y = concat([0], cumsum([
- for (i=idx(pattern,step=2)) let(
- type = pattern[i],
- val = pattern[i+1]
- ) (
- type=="step"? val.y :
- type=="ystep"? val :
- type=="round"? val :
- type=="fillet"? val :
- 0
- )
- ])),
- tot_x = select(x,-1),
- tot_y = select(y,-1),
- data = [
- for (i=idx(pattern,step=2)) let(
- type = pattern[i],
- val = pattern[i+1],
- pt = [x[i/2], tot_y-y[i/2]] + (
- type=="step"? [val.x,-val.y] :
- type=="xstep"? [val,0] :
- type=="ystep"? [0,-val] :
- type=="round"? [val,0] :
- type=="fillet"? [0,-val] :
- [0,0]
- )
- ) [type, val, pt]
- ],
- path = [
- [tot_x,-excess],
- [-excess,-excess],
- [-excess,tot_y],
- for (pat = data) each
- pat[0]=="step"? [pat[2]] :
- pat[0]=="xstep"? [pat[2]] :
- pat[0]=="ystep"? [pat[2]] :
- let(
- r = pat[1],
- steps = segs(abs(r)),
- step = 90/steps
- ) [
- for (i=[0:1:steps]) let(
- a = pat[0]=="round"? (180+i*step) : (90-i*step)
- ) pat[2] + abs(r)*[cos(a),sin(a)]
- ]
- ],
- path2 = deduplicate(path)
- ) reorient(anchor,spin, two_d=true, path=path2, p=path2);
+ assert(is_list(pattern))
+ assert(len(pattern)>0)
+ assert(len(pattern)%2==0,"pattern must be a list of TYPE, VAL pairs.")
+ assert(all([for (i = idx(pattern,step=2)) in_list(pattern[i],["step","xstep","ystep","round","fillet"])]))
+ let(
+ excess = default(excess,$overlap),
+ x = concat([0], cumsum([
+ for (i=idx(pattern,step=2)) let(
+ type = pattern[i],
+ val = pattern[i+1]
+ ) (
+ type=="step"? val.x :
+ type=="xstep"? val :
+ type=="round"? val :
+ type=="fillet"? val :
+ 0
+ )
+ ])),
+ y = concat([0], cumsum([
+ for (i=idx(pattern,step=2)) let(
+ type = pattern[i],
+ val = pattern[i+1]
+ ) (
+ type=="step"? val.y :
+ type=="ystep"? val :
+ type=="round"? val :
+ type=="fillet"? val :
+ 0
+ )
+ ])),
+ tot_x = select(x,-1),
+ tot_y = select(y,-1),
+ data = [
+ for (i=idx(pattern,step=2)) let(
+ type = pattern[i],
+ val = pattern[i+1],
+ pt = [x[i/2], tot_y-y[i/2]] + (
+ type=="step"? [val.x,-val.y] :
+ type=="xstep"? [val,0] :
+ type=="ystep"? [0,-val] :
+ type=="round"? [val,0] :
+ type=="fillet"? [0,-val] :
+ [0,0]
+ )
+ ) [type, val, pt]
+ ],
+ path = [
+ [tot_x,-excess],
+ [-excess,-excess],
+ [-excess,tot_y],
+ for (pat = data) each
+ pat[0]=="step"? [pat[2]] :
+ pat[0]=="xstep"? [pat[2]] :
+ pat[0]=="ystep"? [pat[2]] :
+ let(
+ r = pat[1],
+ steps = segs(abs(r)),
+ step = 90/steps
+ ) [
+ for (i=[0:1:steps]) let(
+ a = pat[0]=="round"? (180+i*step) : (90-i*step)
+ ) pat[2] + abs(r)*[cos(a),sin(a)]
+ ]
+ ],
+ path2 = deduplicate(path)
+ ) reorient(anchor,spin, two_d=true, path=path2, p=path2);
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/skin.scad b/skin.scad
index 8267eb4..648ceab 100644
--- a/skin.scad
+++ b/skin.scad
@@ -163,26 +163,26 @@ include
// Example: Vaccum nozzle example from list-comprehension-demos, using "length" sampling (the default)
// xrot(90)down(1.5)
// difference() {
-// skin(
-// [square([2,.2],center=true),
-// circle($fn=64,r=0.5)], z=[0,3],
-// slices=40,sampling="length",method="reindex");
-// skin(
-// [square([1.9,.1],center=true),
-// circle($fn=64,r=0.45)], z=[-.01,3.01],
-// slices=40,sampling="length",method="reindex");
+// skin(
+// [square([2,.2],center=true),
+// circle($fn=64,r=0.5)], z=[0,3],
+// slices=40,sampling="length",method="reindex");
+// skin(
+// [square([1.9,.1],center=true),
+// circle($fn=64,r=0.45)], z=[-.01,3.01],
+// slices=40,sampling="length",method="reindex");
// }
// Example: Same thing with "segment" sampling
// xrot(90)down(1.5)
// difference() {
-// skin(
-// [square([2,.2],center=true),
-// circle($fn=64,r=0.5)], z=[0,3],
-// slices=40,sampling="segment",method="reindex");
-// skin(
-// [square([1.9,.1],center=true),
-// circle($fn=64,r=0.45)], z=[-.01,3.01],
-// slices=40,sampling="segment",method="reindex");
+// skin(
+// [square([2,.2],center=true),
+// circle($fn=64,r=0.5)], z=[0,3],
+// slices=40,sampling="segment",method="reindex");
+// skin(
+// [square([1.9,.1],center=true),
+// circle($fn=64,r=0.45)], z=[-.01,3.01],
+// slices=40,sampling="segment",method="reindex");
// }
// Example: Forma Candle Holder (from list-comprehension-demos)
// r = 50;
@@ -319,7 +319,7 @@ include
module skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=false, z, convexity=10)
{
- vnf_polyhedron(skin(profiles, slices, refine, method, sampling, caps, closed, z), convexity=convexity);
+ vnf_polyhedron(skin(profiles, slices, refine, method, sampling, caps, closed, z), convexity=convexity);
}
@@ -421,56 +421,56 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
function _skin_core(profiles, caps) =
- let(
+ let(
vertices = [for (prof=profiles) each prof],
- plens = [for (prof=profiles) len(prof)],
- sidefaces = [
- for(pidx=idx(profiles,end=-2))
- let(
- prof1 = profiles[pidx%len(profiles)],
- prof2 = profiles[(pidx+1)%len(profiles)],
- voff = default(sum([for (i=[0:1:pidx-1]) plens[i]]),0),
- faces = [
- for(
- first = true,
- finishing = false,
- finished = false,
- plen1 = len(prof1),
- plen2 = len(prof2),
- i=0, j=0, side=0;
+ plens = [for (prof=profiles) len(prof)],
+ sidefaces = [
+ for(pidx=idx(profiles,end=-2))
+ let(
+ prof1 = profiles[pidx%len(profiles)],
+ prof2 = profiles[(pidx+1)%len(profiles)],
+ voff = default(sum([for (i=[0:1:pidx-1]) plens[i]]),0),
+ faces = [
+ for(
+ first = true,
+ finishing = false,
+ finished = false,
+ plen1 = len(prof1),
+ plen2 = len(prof2),
+ i=0, j=0, side=0;
- !finished;
+ !finished;
- side =
- let(
- p1a = prof1[(i+0)%plen1],
- p1b = prof1[(i+1)%plen1],
- p2a = prof2[(j+0)%plen2],
- p2b = prof2[(j+1)%plen2],
- dist1 = norm(p1a-p2b),
- dist2 = norm(p1b-p2a)
- ) (i==j) ? (dist1>dist2? 1 : 0) : (i=plen1 && j>=plen2
- ) if (!first) face
- ]
- ) each faces
- ],
+ side =
+ let(
+ p1a = prof1[(i+0)%plen1],
+ p1b = prof1[(i+1)%plen1],
+ p2a = prof2[(j+0)%plen2],
+ p2b = prof2[(j+1)%plen2],
+ dist1 = norm(p1a-p2b),
+ dist2 = norm(p1b-p2a)
+ ) (i==j) ? (dist1>dist2? 1 : 0) : (i=plen1 && j>=plen2
+ ) if (!first) face
+ ]
+ ) each faces
+ ],
firstcap = !caps[0] ? [] : let(
prof1 = profiles[0]
) [[for (i=idx(prof1)) plens[0]-1-i]],
secondcap = !caps[1] ? [] : let(
- prof2 = select(profiles,-1),
- eoff = sum(select(plens,0,-2))
- ) [[for (i=idx(prof2)) eoff+i]]
- ) [vertices, concat(sidefaces,firstcap,secondcap)];
+ prof2 = select(profiles,-1),
+ eoff = sum(select(plens,0,-2))
+ ) [[for (i=idx(prof2)) eoff+i]]
+ ) [vertices, concat(sidefaces,firstcap,secondcap)];
@@ -1223,4 +1223,4 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/sliders.scad b/sliders.scad
index 2d5b0e4..466fffb 100644
--- a/sliders.scad
+++ b/sliders.scad
@@ -32,30 +32,30 @@
// slider(l=30, base=10, wall=4, $slop=0.2, spin=90);
module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, anchor=BOTTOM, spin=0, orient=UP)
{
- full_width = w + 2*wall;
- full_height = h + base;
+ full_width = w + 2*wall;
+ full_height = h + base;
- attachable(anchor,spin,orient, size=[full_width, l, h+2*base]) {
- zrot(90)
- down(base+h/2) {
- // Base
- cuboid([full_width, l, base-$slop], chamfer=2, edges=edges([FRONT,BACK], except=BOT), anchor=BOTTOM);
+ attachable(anchor,spin,orient, size=[full_width, l, h+2*base]) {
+ zrot(90)
+ down(base+h/2) {
+ // Base
+ cuboid([full_width, l, base-$slop], chamfer=2, edges=edges([FRONT,BACK], except=BOT), anchor=BOTTOM);
- // Wall
- xflip_copy(offset=w/2+$slop) {
- cuboid([wall, l, full_height], chamfer=2, edges=edges(RIGHT, except=BOT), anchor=BOTTOM+LEFT);
- }
+ // Wall
+ xflip_copy(offset=w/2+$slop) {
+ cuboid([wall, l, full_height], chamfer=2, edges=edges(RIGHT, except=BOT), anchor=BOTTOM+LEFT);
+ }
- // Sliders
- up(base+h/2) {
- xflip_copy(offset=w/2+$slop+0.02) {
- bev_h = h/2*tan(ang);
- prismoid([h, l], [0, l-w], h=bev_h+0.01, orient=LEFT, anchor=BOT);
- }
- }
- }
- children();
- }
+ // Sliders
+ up(base+h/2) {
+ xflip_copy(offset=w/2+$slop+0.02) {
+ bev_h = h/2*tan(ang);
+ prismoid([h, l], [0, l-w], h=bev_h+0.01, orient=LEFT, anchor=BOT);
+ }
+ }
+ }
+ children();
+ }
}
@@ -78,129 +78,129 @@ module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, anchor=BOTTOM, spin=0,
// rail(l=100, w=10, h=10);
module rail(l=30, w=10, h=10, chamfer=1.0, ang=30, anchor=BOTTOM, spin=0, orient=UP)
{
- attack_ang = 30;
- attack_len = 2;
+ attack_ang = 30;
+ attack_len = 2;
- fudge = 1.177;
- chamf = sqrt(2) * chamfer;
- cosa = cos(ang*fudge);
- sina = sin(ang*fudge);
+ fudge = 1.177;
+ chamf = sqrt(2) * chamfer;
+ cosa = cos(ang*fudge);
+ sina = sin(ang*fudge);
- z1 = h/2;
- z2 = z1 - chamf * cosa;
- z3 = z1 - attack_len * sin(attack_ang);
- z4 = 0;
+ z1 = h/2;
+ z2 = z1 - chamf * cosa;
+ z3 = z1 - attack_len * sin(attack_ang);
+ z4 = 0;
- x1 = w/2;
- x2 = x1 - chamf * sina;
- x3 = x1 - chamf;
- x4 = x1 - attack_len * sin(attack_ang);
- x5 = x2 - attack_len * sin(attack_ang);
- x6 = x1 - z1 * sina;
- x7 = x4 - z1 * sina;
+ x1 = w/2;
+ x2 = x1 - chamf * sina;
+ x3 = x1 - chamf;
+ x4 = x1 - attack_len * sin(attack_ang);
+ x5 = x2 - attack_len * sin(attack_ang);
+ x6 = x1 - z1 * sina;
+ x7 = x4 - z1 * sina;
- y1 = l/2;
- y2 = y1 - attack_len * cos(attack_ang);
+ y1 = l/2;
+ y2 = y1 - attack_len * cos(attack_ang);
- attachable(anchor,spin,orient, size=[w, l, h]) {
- polyhedron(
- convexity=4,
- points=[
- [-x5, -y1, z3],
- [ x5, -y1, z3],
- [ x7, -y1, z4],
- [ x4, -y1, -z1-0.05],
- [-x4, -y1, -z1-0.05],
- [-x7, -y1, z4],
+ attachable(anchor,spin,orient, size=[w, l, h]) {
+ polyhedron(
+ convexity=4,
+ points=[
+ [-x5, -y1, z3],
+ [ x5, -y1, z3],
+ [ x7, -y1, z4],
+ [ x4, -y1, -z1-0.05],
+ [-x4, -y1, -z1-0.05],
+ [-x7, -y1, z4],
- [-x3, -y2, z1],
- [ x3, -y2, z1],
- [ x2, -y2, z2],
- [ x6, -y2, z4],
- [ x1, -y2, -z1-0.05],
- [-x1, -y2, -z1-0.05],
- [-x6, -y2, z4],
- [-x2, -y2, z2],
+ [-x3, -y2, z1],
+ [ x3, -y2, z1],
+ [ x2, -y2, z2],
+ [ x6, -y2, z4],
+ [ x1, -y2, -z1-0.05],
+ [-x1, -y2, -z1-0.05],
+ [-x6, -y2, z4],
+ [-x2, -y2, z2],
- [ x5, y1, z3],
- [-x5, y1, z3],
- [-x7, y1, z4],
- [-x4, y1, -z1-0.05],
- [ x4, y1, -z1-0.05],
- [ x7, y1, z4],
+ [ x5, y1, z3],
+ [-x5, y1, z3],
+ [-x7, y1, z4],
+ [-x4, y1, -z1-0.05],
+ [ x4, y1, -z1-0.05],
+ [ x7, y1, z4],
- [ x3, y2, z1],
- [-x3, y2, z1],
- [-x2, y2, z2],
- [-x6, y2, z4],
- [-x1, y2, -z1-0.05],
- [ x1, y2, -z1-0.05],
- [ x6, y2, z4],
- [ x2, y2, z2],
- ],
- faces=[
- [0, 1, 2],
- [0, 2, 5],
- [2, 3, 4],
- [2, 4, 5],
+ [ x3, y2, z1],
+ [-x3, y2, z1],
+ [-x2, y2, z2],
+ [-x6, y2, z4],
+ [-x1, y2, -z1-0.05],
+ [ x1, y2, -z1-0.05],
+ [ x6, y2, z4],
+ [ x2, y2, z2],
+ ],
+ faces=[
+ [0, 1, 2],
+ [0, 2, 5],
+ [2, 3, 4],
+ [2, 4, 5],
- [0, 13, 6],
- [0, 6, 7],
- [0, 7, 1],
- [1, 7, 8],
- [1, 8, 9],
- [1, 9, 2],
- [2, 9, 10],
- [2, 10, 3],
- [3, 10, 11],
- [3, 11, 4],
- [4, 11, 12],
- [4, 12, 5],
- [5, 12, 13],
- [5, 13, 0],
+ [0, 13, 6],
+ [0, 6, 7],
+ [0, 7, 1],
+ [1, 7, 8],
+ [1, 8, 9],
+ [1, 9, 2],
+ [2, 9, 10],
+ [2, 10, 3],
+ [3, 10, 11],
+ [3, 11, 4],
+ [4, 11, 12],
+ [4, 12, 5],
+ [5, 12, 13],
+ [5, 13, 0],
- [14, 15, 16],
- [14, 16, 19],
- [16, 17, 18],
- [16, 18, 19],
+ [14, 15, 16],
+ [14, 16, 19],
+ [16, 17, 18],
+ [16, 18, 19],
- [14, 27, 20],
- [14, 20, 21],
- [14, 21, 15],
- [15, 21, 22],
- [15, 22, 23],
- [15, 23, 16],
- [16, 23, 24],
- [16, 24, 17],
- [17, 24, 25],
- [17, 25, 18],
- [18, 25, 26],
- [18, 26, 19],
- [19, 26, 27],
- [19, 27, 14],
+ [14, 27, 20],
+ [14, 20, 21],
+ [14, 21, 15],
+ [15, 21, 22],
+ [15, 22, 23],
+ [15, 23, 16],
+ [16, 23, 24],
+ [16, 24, 17],
+ [17, 24, 25],
+ [17, 25, 18],
+ [18, 25, 26],
+ [18, 26, 19],
+ [19, 26, 27],
+ [19, 27, 14],
- [6, 21, 20],
- [6, 20, 7],
- [7, 20, 27],
- [7, 27, 8],
- [8, 27, 26],
- [8, 26, 9],
- [9, 26, 25],
- [9, 25, 10],
- [10, 25, 24],
- [10, 24, 11],
- [11, 24, 23],
- [11, 23, 12],
- [12, 23, 22],
- [12, 22, 13],
- [13, 22, 21],
- [13, 21, 6],
- ]
- );
- children();
- }
+ [6, 21, 20],
+ [6, 20, 7],
+ [7, 20, 27],
+ [7, 27, 8],
+ [8, 27, 26],
+ [8, 26, 9],
+ [9, 26, 25],
+ [9, 25, 10],
+ [10, 25, 24],
+ [10, 24, 11],
+ [11, 24, 23],
+ [11, 23, 12],
+ [12, 23, 22],
+ [12, 22, 13],
+ [13, 22, 21],
+ [13, 21, 6],
+ ]
+ );
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/stacks.scad b/stacks.scad
index acf945e..4a452c0 100644
--- a/stacks.scad
+++ b/stacks.scad
@@ -41,8 +41,8 @@ function stack_init() = [];
// stack2 = stack_push(stack, "foo");
// is_empty2 = stack_empty(stack2); // Returns: false
function stack_empty(stack) =
- assert(is_list(stack))
- len(stack)==0;
+ assert(is_list(stack))
+ len(stack)==0;
// Function: stack_depth()
@@ -60,8 +60,8 @@ function stack_empty(stack) =
// stack3 = stack_push(stack2, ["bar","baz","qux"]);
// depth3 = stack_depth(stack3); // Returns: 4
function stack_depth(stack) =
- assert(is_list(stack))
- len(stack);
+ assert(is_list(stack))
+ len(stack);
// Function: stack_top()
@@ -78,16 +78,16 @@ function stack_depth(stack) =
// item = stack_top(stack); // Returns: 7
// list = stack_top(stack,n=3); // Returns: [5,6,7]
function stack_top(stack,n=undef) =
- assert(is_list(stack))
- is_undef(n)? (
- stack[len(stack)-1]
- ) : (
- let(stacksize = len(stack))
- assert(is_num(n))
- assert(n>=0)
- assert(stacksize>=n, "stack underflow")
- [for (i=[0:1:n-1]) stack[stacksize-n+i]]
- );
+ assert(is_list(stack))
+ is_undef(n)? (
+ stack[len(stack)-1]
+ ) : (
+ let(stacksize = len(stack))
+ assert(is_num(n))
+ assert(n>=0)
+ assert(stacksize>=n, "stack underflow")
+ [for (i=[0:1:n-1]) stack[stacksize-n+i]]
+ );
// Function: stack_peek()
@@ -107,19 +107,19 @@ function stack_top(stack,n=undef) =
// item2 = stack_peek(stack, 3); // Returns: 7
// list = stack_peek(stack, 6, 4); // Returns: [4,5,6,7]
function stack_peek(stack,depth=0,n=undef) =
- assert(is_list(stack))
- assert(is_num(depth))
- assert(depth>=0)
- let(stacksize = len(stack))
- assert(stacksize>=depth, "stack underflow")
- is_undef(n)? (
- stack[stacksize-depth-1]
- ) : (
- assert(is_num(n))
- assert(n>=0)
- assert(n<=depth+1)
- [for (i=[0:1:n-1]) stack[stacksize-1-depth+i]]
- );
+ assert(is_list(stack))
+ assert(is_num(depth))
+ assert(depth>=0)
+ let(stacksize = len(stack))
+ assert(stacksize>=depth, "stack underflow")
+ is_undef(n)? (
+ stack[stacksize-depth-1]
+ ) : (
+ assert(is_num(n))
+ assert(n>=0)
+ assert(n<=depth+1)
+ [for (i=[0:1:n-1]) stack[stacksize-1-depth+i]]
+ );
// Function: stack_push()
@@ -137,8 +137,8 @@ function stack_peek(stack,depth=0,n=undef) =
// stack4 = stack_push(stack,[[5,8]]); // Returns: [4,9,2,3,[5,8]]
// stack5 = stack_push(stack,[[5,8],6,7]); // Returns: [4,9,2,3,[5,8],6,7]
function stack_push(stack,items) =
- assert(is_list(stack))
- is_list(items)? concat(stack, items) : concat(stack, [items]);
+ assert(is_list(stack))
+ is_list(items)? concat(stack, items) : concat(stack, [items]);
// Function: stack_pop()
@@ -154,11 +154,11 @@ function stack_push(stack,items) =
// stack2 = stack_pop(stack); // Returns: [4,5,6,7,8]
// stack3 = stack_pop(stack2,n=3); // Returns: [4,5]
function stack_pop(stack,n=1) =
- assert(is_list(stack))
- assert(is_num(n))
- assert(n>=0)
- assert(len(stack)>=n, "stack underflow")
- [for (i = [0:1:len(stack)-1-n]) stack[i]];
+ assert(is_list(stack))
+ assert(is_num(n))
+ assert(n>=0)
+ assert(len(stack)>=n, "stack underflow")
+ [for (i = [0:1:len(stack)-1-n]) stack[i]];
// Function: stack_rotate()
@@ -176,18 +176,18 @@ function stack_pop(stack,n=1) =
// stack2 = stack_rotate(stack,3); // Returns: [4,5,7,8,6]
// stack3 = stack_rotate(stack2,-4); // Returns: [4,6,5,7,8]
function stack_rotate(stack,n=3) =
- assert(is_list(stack))
- let(stacksize = len(stack))
- assert(stacksize>=n, "stack underflow")
- n>=0? concat(
- [for (i=[0:1:stacksize-1-n]) stack[i]],
- [for (i=[0:1:n-2]) stack[stacksize-n+i+1]],
- [stack[stacksize-n]]
- ) : concat(
- [for (i=[0:1:stacksize-1+n]) stack[i]],
- [stack[stacksize-1]],
- [for (i=[0:1:-n-2]) stack[stacksize+n+i]]
- );
+ assert(is_list(stack))
+ let(stacksize = len(stack))
+ assert(stacksize>=n, "stack underflow")
+ n>=0? concat(
+ [for (i=[0:1:stacksize-1-n]) stack[i]],
+ [for (i=[0:1:n-2]) stack[stacksize-n+i+1]],
+ [stack[stacksize-n]]
+ ) : concat(
+ [for (i=[0:1:stacksize-1+n]) stack[i]],
+ [stack[stacksize-1]],
+ [for (i=[0:1:-n-2]) stack[stacksize+n+i]]
+ );
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/std.scad b/std.scad
index ce46f5c..8375fcc 100644
--- a/std.scad
+++ b/std.scad
@@ -39,5 +39,5 @@ include
include
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/strings.scad b/strings.scad
index 94cafeb..7565e17 100644
--- a/strings.scad
+++ b/strings.scad
@@ -27,13 +27,13 @@
// substr("abcdefg",[2,4]); // Returns "cde"
// substr("abcdefg",len=-2); // Returns ""
function substr(str, pos=0, len=undef) =
- is_list(pos) ? _substr(str, pos[0], pos[1]-pos[0]+1) :
- len == undef ? _substr(str, pos, len(str)-pos) :
- _substr(str,pos,len);
+ is_list(pos) ? _substr(str, pos[0], pos[1]-pos[0]+1) :
+ len == undef ? _substr(str, pos, len(str)-pos) :
+ _substr(str,pos,len);
function _substr(str,pos,len,substr="") =
- len <= 0 || pos>=len(str) ? substr :
- _substr(str, pos+1, len-1, str(substr, str[pos]));
+ len <= 0 || pos>=len(str) ? substr :
+ _substr(str, pos+1, len-1, str(substr, str[pos]));
// Function suffix()
@@ -57,8 +57,8 @@ function suffix(str,len) = substr(str, len(str)-len,len);
// str_join(["abc","def","ghi"]); // Returns "abcdefghi"
// str_join(["abc","def","ghi"], " + "); // Returns "abc + def + ghi"
function str_join(list,sep="",_i=0, _result="") =
- _i >= len(list)-1 ? (_i==len(list) ? _result : str(_result,list[_i])) :
- str_join(list,sep,_i+1,str(_result,list[_i],sep));
+ _i >= len(list)-1 ? (_i==len(list) ? _result : str(_result,list[_i])) :
+ str_join(list,sep,_i+1,str(_result,list[_i],sep));
// Function: downcase()
@@ -72,7 +72,7 @@ function str_join(list,sep="",_i=0, _result="") =
// Example:
// downcase("ABCdef"); // Returns "abcdef"
function downcase(str) =
- str_join([for(char=str) let(code=ord(char)) code>=65 && code<=90 ? chr(code+32) : char]);
+ str_join([for(char=str) let(code=ord(char)) code>=65 && code<=90 ? chr(code+32) : char]);
// Function: upcase()
@@ -86,7 +86,7 @@ function downcase(str) =
// Example:
// upcase("ABCdef"); // Returns "ABCDEF"
function upcase(str) =
- str_join([for(char=str) let(code=ord(char)) code>=97 && code<=122 ? chr(code-32) : char]);
+ str_join([for(char=str) let(code=ord(char)) code>=97 && code<=122 ? chr(code-32) : char]);
// Function: str_int()
@@ -110,19 +110,19 @@ function upcase(str) =
// str_int("CEDE", 16); // Returns 52958
// str_int(""); // Returns 0
function str_int(str,base=10) =
- str==undef ? undef :
- len(str)==0 ? 0 :
- let(str=downcase(str))
- str[0] == "-" ? -_str_int_recurse(substr(str,1),base,len(str)-2) :
- str[0] == "+" ? _str_int_recurse(substr(str,1),base,len(str)-2) :
- _str_int_recurse(str,base,len(str)-1);
+ str==undef ? undef :
+ len(str)==0 ? 0 :
+ let(str=downcase(str))
+ str[0] == "-" ? -_str_int_recurse(substr(str,1),base,len(str)-2) :
+ str[0] == "+" ? _str_int_recurse(substr(str,1),base,len(str)-2) :
+ _str_int_recurse(str,base,len(str)-1);
function _str_int_recurse(str,base,i) =
- let(
- digit = search(str[i],"0123456789abcdef"),
- last_digit = digit == [] || digit[0] >= base ? (0/0) : digit[0]
- ) i==0 ? last_digit :
- _str_int_recurse(str,base,i-1)*base + last_digit;
+ let(
+ digit = search(str[i],"0123456789abcdef"),
+ last_digit = digit == [] || digit[0] >= base ? (0/0) : digit[0]
+ ) i==0 ? last_digit :
+ _str_int_recurse(str,base,i-1)*base + last_digit;
// Function: str_float()
@@ -142,15 +142,15 @@ function _str_int_recurse(str,base,i) =
// str_float("7.342e-4"); // Returns 0.0007342
// str_float(""); // Returns 0
function str_float(str) =
- str==undef ? undef :
- len(str) == 0 ? 0 :
- in_list(str[1], ["+","-"]) ? (0/0) : // Don't allow --3, or +-3
- str[0]=="-" ? -str_float(substr(str,1)) :
- str[0]=="+" ? str_float(substr(str,1)) :
- let(esplit = str_split(str,"eE") )
- len(esplit)==2 ? str_float(esplit[0]) * pow(10,str_int(esplit[1])) :
- let( dsplit = str_split(str,["."]))
- str_int(dsplit[0])+str_int(dsplit[1])/pow(10,len(dsplit[1]));
+ str==undef ? undef :
+ len(str) == 0 ? 0 :
+ in_list(str[1], ["+","-"]) ? (0/0) : // Don't allow --3, or +-3
+ str[0]=="-" ? -str_float(substr(str,1)) :
+ str[0]=="+" ? str_float(substr(str,1)) :
+ let(esplit = str_split(str,"eE") )
+ len(esplit)==2 ? str_float(esplit[0]) * pow(10,str_int(esplit[1])) :
+ let( dsplit = str_split(str,["."]))
+ str_int(dsplit[0])+str_int(dsplit[1])/pow(10,len(dsplit[1]));
// Function: str_frac()
@@ -186,24 +186,24 @@ function str_float(str) =
// str_frac("-2 12/4",mixed=false); // Returns nan
// str_frac("2 1/4",mixed=false); // Returns nan
function str_frac(str,mixed=true,improper=true,signed=true) =
- str == undef ? undef :
- len(str)==0 ? 0 :
- signed && str[0]=="-" ? -str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
- signed && str[0]=="+" ? str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
- mixed ? (
- str_find(str," ")>0 || is_undef(str_find(str,"/"))? (
- let(whole = str_split(str,[" "]))
- _str_int_recurse(whole[0],10,len(whole[0])-1) + str_frac(whole[1], mixed=false, improper=improper, signed=false)
- ) : str_frac(str,mixed=false, improper=improper)
- ) : (
- let(split = str_split(str,"/"))
- len(split)!=2 ? (0/0) :
- let(
- numerator = _str_int_recurse(split[0],10,len(split[0])-1),
- denominator = _str_int_recurse(split[1],10,len(split[1])-1)
- ) !improper && numerator>=denominator? (0/0) :
- denominator<0 ? (0/0) : numerator/denominator
- );
+ str == undef ? undef :
+ len(str)==0 ? 0 :
+ signed && str[0]=="-" ? -str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
+ signed && str[0]=="+" ? str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
+ mixed ? (
+ str_find(str," ")>0 || is_undef(str_find(str,"/"))? (
+ let(whole = str_split(str,[" "]))
+ _str_int_recurse(whole[0],10,len(whole[0])-1) + str_frac(whole[1], mixed=false, improper=improper, signed=false)
+ ) : str_frac(str,mixed=false, improper=improper)
+ ) : (
+ let(split = str_split(str,"/"))
+ len(split)!=2 ? (0/0) :
+ let(
+ numerator = _str_int_recurse(split[0],10,len(split[0])-1),
+ denominator = _str_int_recurse(split[1],10,len(split[1])-1)
+ ) !improper && numerator>=denominator? (0/0) :
+ denominator<0 ? (0/0) : numerator/denominator
+ );
// Function: str_num()
@@ -216,10 +216,10 @@ function str_frac(str,mixed=true,improper=true,signed=true) =
// str_num("3/4"); // Returns 0.75
// str_num("3.4e-2"); // Returns 0.034
function str_num(str) =
- str == undef ? undef :
- let( val = str_frac(str) )
- val == val ? val :
- str_float(str);
+ str == undef ? undef :
+ let( val = str_frac(str) )
+ val == val ? val :
+ str_float(str);
// Function: str_split()
@@ -247,25 +247,25 @@ function str_num(str) =
// str_split("abc+def-qrs*iop",["+","-","*"]); // Returns ["abc", "def", "qrs", "iop"]
// str_split("abc+def-qrs*iop",["-","+","*"]); // Returns ["abc+def", "qrs*iop", "", ""]
function str_split(str,sep,keep_nulls=true) =
- !keep_nulls ? _remove_empty_strs(str_split(str,sep,keep_nulls=true)) :
- is_list(sep) ? _str_split_recurse(str,sep,i=0,result=[]) :
- let( cutpts = concat([-1],sort(flatten(search(sep, str,0))),[len(str)]))
- [for(i=[0:len(cutpts)-2]) substr(str,cutpts[i]+1,cutpts[i+1]-cutpts[i]-1)];
+ !keep_nulls ? _remove_empty_strs(str_split(str,sep,keep_nulls=true)) :
+ is_list(sep) ? _str_split_recurse(str,sep,i=0,result=[]) :
+ let( cutpts = concat([-1],sort(flatten(search(sep, str,0))),[len(str)]))
+ [for(i=[0:len(cutpts)-2]) substr(str,cutpts[i]+1,cutpts[i+1]-cutpts[i]-1)];
function _str_split_recurse(str,sep,i,result) =
- i == len(sep) ? concat(result,[str]) :
- let(
- pos = search(sep[i], str),
- end = pos==[] ? len(str) : pos[0]
- )
- _str_split_recurse(
- substr(str,end+1),
- sep, i+1,
- concat(result, [substr(str,0,end)])
- );
+ i == len(sep) ? concat(result,[str]) :
+ let(
+ pos = search(sep[i], str),
+ end = pos==[] ? len(str) : pos[0]
+ )
+ _str_split_recurse(
+ substr(str,end+1),
+ sep, i+1,
+ concat(result, [substr(str,0,end)])
+ );
function _remove_empty_strs(list) =
- list_remove(list, search([""], list,0)[0]);
+ list_remove(list, search([""], list,0)[0]);
// _str_cmp(str,sindex,pattern)
@@ -276,11 +276,11 @@ function _remove_empty_strs(list) =
// cuts run time in half when the string is long. Two other string
// comparison methods were slower.
function _str_cmp(str,sindex,pattern) =
- len(str)-sindex =0 && !_str_cmp(str,sindex, pattern)?
- _str_find_last(str,pattern,sindex-1) :
- (sindex >=0 ? sindex : undef);
+ sindex>=0 && !_str_cmp(str,sindex, pattern)?
+ _str_find_last(str,pattern,sindex-1) :
+ (sindex >=0 ? sindex : undef);
function _str_find_all(str,pattern) =
- pattern == "" ? list_range(len(str)) :
- [for(i=[0:1:len(str)-len(pattern)]) if (_str_cmp(str,i,pattern)) i];
+ pattern == "" ? list_range(len(str)) :
+ [for(i=[0:1:len(str)-len(pattern)]) if (_str_cmp(str,i,pattern)) i];
// Function: starts_with()
@@ -369,12 +369,12 @@ function ends_with(str,pattern) = _str_cmp(str,len(str)-len(pattern),pattern);
function _str_count_leading(s,c,_i=0) =
- (_i>=len(s)||!in_list(s[_i],[each c]))? _i :
- _str_count_leading(s,c,_i=_i+1);
+ (_i>=len(s)||!in_list(s[_i],[each c]))? _i :
+ _str_count_leading(s,c,_i=_i+1);
function _str_count_trailing(s,c,_i=0) =
- (_i>=len(s)||!in_list(s[len(s)-1-_i],[each c]))? _i :
- _str_count_trailing(s,c,_i=_i+1);
+ (_i>=len(s)||!in_list(s[len(s)-1-_i],[each c]))? _i :
+ _str_count_trailing(s,c,_i=_i+1);
// Function: str_strip_leading()
@@ -435,15 +435,15 @@ function str_strip(s,c) = str_strip_trailing(str_strip_leading(s,c),c);
// fmt_int(123456789012345); // Returns "123456789012345"
// fmt_int(-123456789012345); // Returns "-123456789012345"
function fmt_int(i,mindigits=1) =
- i<0? str("-", fmt_int(-i)) :
- let(i=floor(i), e=floor(log(i)))
- i==0? "0" :
- str_join(
- concat(
- [for (j=[0:1:mindigits-e-2]) "0"],
- [for (j=[e:-1:0]) str(floor(i/pow(10,j)%10))]
- )
- );
+ i<0? str("-", fmt_int(-i)) :
+ let(i=floor(i), e=floor(log(i)))
+ i==0? "0" :
+ str_join(
+ concat(
+ [for (j=[0:1:mindigits-e-2]) "0"],
+ [for (j=[e:-1:0]) str(floor(i/pow(10,j)%10))]
+ )
+ );
// Function: fmt_fixed()
@@ -455,19 +455,19 @@ function fmt_int(i,mindigits=1) =
// f = The floating point number to format.
// digits = The number of digits after the decimal to show. Default: 6
function fmt_fixed(f,digits=6) =
- assert(is_int(digits))
- assert(digits>0)
- is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_fixed(g,digits=digits)]),"]") :
- str(f)=="nan"? "nan" :
- str(f)=="inf"? "inf" :
- f<0? str("-",fmt_fixed(-f,digits=digits)) :
- assert(is_num(f))
- let(
- sc = pow(10,digits),
- scaled = floor(f * sc + 0.5),
- whole = floor(scaled/sc),
- part = floor(scaled-(whole*sc))
- ) str(fmt_int(whole),".",fmt_int(part,digits));
+ assert(is_int(digits))
+ assert(digits>0)
+ is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_fixed(g,digits=digits)]),"]") :
+ str(f)=="nan"? "nan" :
+ str(f)=="inf"? "inf" :
+ f<0? str("-",fmt_fixed(-f,digits=digits)) :
+ assert(is_num(f))
+ let(
+ sc = pow(10,digits),
+ scaled = floor(f * sc + 0.5),
+ whole = floor(scaled/sc),
+ part = floor(scaled-(whole*sc))
+ ) str(fmt_int(whole),".",fmt_int(part,digits));
// Function: fmt_float()
@@ -485,34 +485,34 @@ function fmt_fixed(f,digits=6) =
// fmt_float(PI,12); // Returns: "3.14159265359"
// fmt_float([PI,-16.75],12); // Returns: "[3.14159265359, -16.75]"
function fmt_float(f,sig=12) =
- assert(is_int(sig))
- assert(sig>0)
- is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_float(g,sig=sig)]),"]") :
- f==0? "0" :
- str(f)=="nan"? "nan" :
- str(f)=="inf"? "inf" :
- f<0? str("-",fmt_float(-f,sig=sig)) :
- assert(is_num(f))
- let(
- e = floor(log(f)),
- mv = sig - e - 1
- ) mv == 0? fmt_int(floor(f + 0.5)) :
- (e<-sig/2||mv<0)? str(fmt_float(f*pow(10,-e),sig=sig),"e",e) :
- let(
- ff = f + pow(10,-mv)*0.5,
- whole = floor(ff),
- part = floor((ff-whole) * pow(10,mv))
- )
- str_join([
- str(whole),
- str_strip_trailing(
- str_join([
- ".",
- fmt_int(part, mindigits=mv)
- ]),
- "0."
- )
- ]);
+ assert(is_int(sig))
+ assert(sig>0)
+ is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_float(g,sig=sig)]),"]") :
+ f==0? "0" :
+ str(f)=="nan"? "nan" :
+ str(f)=="inf"? "inf" :
+ f<0? str("-",fmt_float(-f,sig=sig)) :
+ assert(is_num(f))
+ let(
+ e = floor(log(f)),
+ mv = sig - e - 1
+ ) mv == 0? fmt_int(floor(f + 0.5)) :
+ (e<-sig/2||mv<0)? str(fmt_float(f*pow(10,-e),sig=sig),"e",e) :
+ let(
+ ff = f + pow(10,-mv)*0.5,
+ whole = floor(ff),
+ part = floor((ff-whole) * pow(10,mv))
+ )
+ str_join([
+ str(whole),
+ str_strip_trailing(
+ str_join([
+ ".",
+ fmt_int(part, mindigits=mv)
+ ]),
+ "0."
+ )
+ ]);
// Function: escape_html()
@@ -521,14 +521,14 @@ function fmt_float(f,sig=12) =
// Description:
// Converts "<", ">", "&", and double-quote chars to their entity encoding so that echoing the strong will show it verbatim.
function escape_html(s) =
- str_join([
- for (c=s)
- c=="<"? "<" :
- c==">"? ">" :
- c=="&"? "&" :
- c=="\""? """ :
- c
- ]);
+ str_join([
+ for (c=s)
+ c=="<"? "<" :
+ c==">"? ">" :
+ c=="&"? "&" :
+ c=="\""? """ :
+ c
+ ]);
// Function: is_lower()
@@ -537,10 +537,10 @@ function escape_html(s) =
// Description:
// Returns true if all the characters in the given string are lowercase letters. (a-z)
function is_lower(s) =
- assert(is_string(s))
- s==""? false :
- len(s)>1? all([for (v=s) is_lower(v)]) :
- let(v = ord(s[0])) (v>=ord("a") && v<=ord("z"));
+ assert(is_string(s))
+ s==""? false :
+ len(s)>1? all([for (v=s) is_lower(v)]) :
+ let(v = ord(s[0])) (v>=ord("a") && v<=ord("z"));
// Function: is_upper()
@@ -549,10 +549,10 @@ function is_lower(s) =
// Description:
// Returns true if all the characters in the given string are uppercase letters. (A-Z)
function is_upper(s) =
- assert(is_string(s))
- s==""? false :
- len(s)>1? all([for (v=s) is_upper(v)]) :
- let(v = ord(s[0])) (v>=ord("A") && v<=ord("Z"));
+ assert(is_string(s))
+ s==""? false :
+ len(s)>1? all([for (v=s) is_upper(v)]) :
+ let(v = ord(s[0])) (v>=ord("A") && v<=ord("Z"));
// Function: is_digit()
@@ -561,10 +561,10 @@ function is_upper(s) =
// Description:
// Returns true if all the characters in the given string are digits. (0-9)
function is_digit(s) =
- assert(is_string(s))
- s==""? false :
- len(s)>1? all([for (v=s) is_digit(v)]) :
- let(v = ord(s[0])) (v>=ord("0") && v<=ord("9"));
+ assert(is_string(s))
+ s==""? false :
+ len(s)>1? all([for (v=s) is_digit(v)]) :
+ let(v = ord(s[0])) (v>=ord("0") && v<=ord("9"));
// Function: is_hexdigit()
@@ -573,13 +573,13 @@ function is_digit(s) =
// Description:
// Returns true if all the characters in the given string are valid hexadecimal digits. (0-9 or a-f or A-F))
function is_hexdigit(s) =
- assert(is_string(s))
- s==""? false :
- len(s)>1? all([for (v=s) is_hexdigit(v)]) :
- let(v = ord(s[0]))
- (v>=ord("0") && v<=ord("9")) ||
- (v>=ord("A") && v<=ord("F")) ||
- (v>=ord("a") && v<=ord("f"));
+ assert(is_string(s))
+ s==""? false :
+ len(s)>1? all([for (v=s) is_hexdigit(v)]) :
+ let(v = ord(s[0]))
+ (v>=ord("0") && v<=ord("9")) ||
+ (v>=ord("A") && v<=ord("F")) ||
+ (v>=ord("a") && v<=ord("f"));
// Function: is_letter()
@@ -588,9 +588,9 @@ function is_hexdigit(s) =
// Description:
// Returns true if all the characters in the given string are standard ASCII letters. (A-Z or a-z)
function is_letter(s) =
- assert(is_string(s))
- s==""? false :
- all([for (v=s) is_lower(v) || is_upper(v)]);
+ assert(is_string(s))
+ s==""? false :
+ all([for (v=s) is_lower(v) || is_upper(v)]);
// Function: str_format()
@@ -630,54 +630,54 @@ function is_letter(s) =
// str_format("{:-10s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostamus27.440"
// str_format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostam 27.440"
function str_format(fmt, vals, use_nbsp=false) =
- let(
- parts = str_split(fmt,"{")
- ) str_join([
- for(i = idx(parts))
- let(
- found_brace = i==0 || [for (c=parts[i]) if(c=="}") c] != [],
- err = assert(found_brace, "Unbalanced { in format string."),
- p = i==0? [undef,parts[i]] : str_split(parts[i],"}"),
- fmta = p[0],
- raw = p[1]
- ) each [
- assert(i<99)
- is_undef(fmta)? "" : let(
- fmtb = str_split(fmta,":"),
- num = is_digit(fmtb[0])? str_int(fmtb[0]) : (i-1),
- left = fmtb[1][0] == "-",
- fmtb1 = default(fmtb[1],""),
- fmtc = left? substr(fmtb1,1) : fmtb1,
- zero = fmtc[0] == "0",
- lch = fmtc==""? "" : fmtc[len(fmtc)-1],
- hastyp = is_letter(lch),
- typ = hastyp? lch : "s",
- fmtd = hastyp? substr(fmtc,0,len(fmtc)-1) : fmtc,
- fmte = str_split((zero? substr(fmtd,1) : fmtd), "."),
- wid = str_int(fmte[0]),
- prec = str_int(fmte[1]),
- val = assert(num>=0&&num=0&&num
testpoints_on_sphere = [ for(p =
- [
- [1,PHI,0], [-1,PHI,0], [1,-PHI,0], [-1,-PHI,0],
- [0,1,PHI], [0,-1,PHI], [0,1,-PHI], [0,-1,-PHI],
- [PHI,0,1], [-PHI,0,1], [PHI,0,-1], [-PHI,0,-1]
- ])
- unit(p)
+ [
+ [1,PHI,0], [-1,PHI,0], [1,-PHI,0], [-1,-PHI,0],
+ [0,1,PHI], [0,-1,PHI], [0,1,-PHI], [0,-1,-PHI],
+ [PHI,0,1], [-PHI,0,1], [PHI,0,-1], [-PHI,0,-1]
+ ])
+ unit(p)
];
testpoints_circular = [ for(a = [0:15:360-EPSILON]) [cos(a),sin(a)] ];
@@ -44,30 +44,30 @@ visualize_hull(testpoints3d);
module visualize_hull(points) {
- hull = hull(points);
-
- %if (len(hull) > 0 && is_list(hull[0]) && len(hull[0]) > 0)
- polyhedron(points=points, faces = hull);
- else
- polyhedron(points=points, faces = [hull]);
-
- for (i = [0:len(points)-1]) {
- p = points[i];
- $fn = 16;
- translate(p) {
- if (hull_contains_index(hull,i)) {
- color("blue") sphere(1);
- } else {
- color("red") sphere(1);
- }
- }
- }
-
- function hull_contains_index(hull, index) =
- search(index,hull,1,0) ||
- search(index,hull,1,1) ||
- search(index,hull,1,2);
+ hull = hull(points);
+
+ %if (len(hull) > 0 && is_list(hull[0]) && len(hull[0]) > 0)
+ polyhedron(points=points, faces = hull);
+ else
+ polyhedron(points=points, faces = [hull]);
+
+ for (i = [0:len(points)-1]) {
+ p = points[i];
+ $fn = 16;
+ translate(p) {
+ if (hull_contains_index(hull,i)) {
+ color("blue") sphere(1);
+ } else {
+ color("red") sphere(1);
+ }
+ }
+ }
+
+ function hull_contains_index(hull, index) =
+ search(index,hull,1,0) ||
+ search(index,hull,1,1) ||
+ search(index,hull,1,2);
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad
index b066049..71fa750 100644
--- a/tests/test_arrays.scad
+++ b/tests/test_arrays.scad
@@ -4,259 +4,259 @@ include
// List/Array Ops
module test_repeat() {
- assert(repeat(1, 4) == [1,1,1,1]);
- assert(repeat(8, [2,3]) == [[8,8,8], [8,8,8]]);
- assert(repeat(0, [2,2,3]) == [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]]);
- assert(repeat([1,2,3],3) == [[1,2,3], [1,2,3], [1,2,3]]);
+ assert(repeat(1, 4) == [1,1,1,1]);
+ assert(repeat(8, [2,3]) == [[8,8,8], [8,8,8]]);
+ assert(repeat(0, [2,2,3]) == [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]]);
+ assert(repeat([1,2,3],3) == [[1,2,3], [1,2,3], [1,2,3]]);
}
test_repeat();
module test_in_list() {
- assert(in_list("bar", ["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", ["foo", "bar", "baz"]));
+ assert(!in_list("bee", ["foo", "bar", "baz"]));
+ assert(in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1));
}
test_in_list();
module test_slice() {
- assert(slice([3,4,5,6,7,8,9], 3, 5) == [6,7]);
- assert(slice([3,4,5,6,7,8,9], 2, -1) == [5,6,7,8,9]);
- assert(slice([3,4,5,6,7,8,9], 1, 1) == []);
- assert(slice([3,4,5,6,7,8,9], 6, -1) == [9]);
- assert(slice([3,4,5,6,7,8,9], 2, -2) == [5,6,7,8]);
+ assert(slice([3,4,5,6,7,8,9], 3, 5) == [6,7]);
+ assert(slice([3,4,5,6,7,8,9], 2, -1) == [5,6,7,8,9]);
+ assert(slice([3,4,5,6,7,8,9], 1, 1) == []);
+ assert(slice([3,4,5,6,7,8,9], 6, -1) == [9]);
+ assert(slice([3,4,5,6,7,8,9], 2, -2) == [5,6,7,8]);
}
test_slice();
module test_select() {
- l = [3,4,5,6,7,8,9];
- assert(select(l, 5, 6) == [8,9]);
- assert(select(l, 5, 8) == [8,9,3,4]);
- assert(select(l, 5, 2) == [8,9,3,4,5]);
- assert(select(l, -3, -1) == [7,8,9]);
- assert(select(l, 3, 3) == [6]);
- assert(select(l, 4) == 7);
- assert(select(l, -2) == 8);
- assert(select(l, [1:3]) == [4,5,6]);
- assert(select(l, [1,3]) == [4,6]);
+ l = [3,4,5,6,7,8,9];
+ assert(select(l, 5, 6) == [8,9]);
+ assert(select(l, 5, 8) == [8,9,3,4]);
+ assert(select(l, 5, 2) == [8,9,3,4,5]);
+ assert(select(l, -3, -1) == [7,8,9]);
+ assert(select(l, 3, 3) == [6]);
+ assert(select(l, 4) == 7);
+ assert(select(l, -2) == 8);
+ assert(select(l, [1:3]) == [4,5,6]);
+ assert(select(l, [1,3]) == [4,6]);
}
test_select();
module test_list_range() {
- assert(list_range(4) == [0,1,2,3]);
- assert(list_range(n=4, step=2) == [0,2,4,6]);
- assert(list_range(n=4, s=3, step=3) == [3,6,9,12]);
- assert(list_range(e=3) == [0,1,2,3]);
- assert(list_range(e=6, step=2) == [0,2,4,6]);
- assert(list_range(s=3, e=5) == [3,4,5]);
- assert(list_range(s=3, e=8, step=2) == [3,5,7]);
- assert(list_range(s=4, e=8, step=2) == [4,6,8]);
- assert(list_range(e=4, n=3) == [0,2,4]);
- assert(list_range(n=4, s=[3,4], step=[2,3]) == [[3,4], [5,7], [7,10], [9,13]]);
+ assert(list_range(4) == [0,1,2,3]);
+ assert(list_range(n=4, step=2) == [0,2,4,6]);
+ assert(list_range(n=4, s=3, step=3) == [3,6,9,12]);
+ assert(list_range(e=3) == [0,1,2,3]);
+ assert(list_range(e=6, step=2) == [0,2,4,6]);
+ assert(list_range(s=3, e=5) == [3,4,5]);
+ assert(list_range(s=3, e=8, step=2) == [3,5,7]);
+ assert(list_range(s=4, e=8, step=2) == [4,6,8]);
+ assert(list_range(e=4, n=3) == [0,2,4]);
+ assert(list_range(n=4, s=[3,4], step=[2,3]) == [[3,4], [5,7], [7,10], [9,13]]);
}
test_list_range();
module test_reverse() {
- assert(reverse([3,4,5,6]) == [6,5,4,3]);
+ assert(reverse([3,4,5,6]) == [6,5,4,3]);
}
test_reverse();
module test_list_rotate() {
- assert(list_rotate([1,2,3,4,5],-2) == [4,5,1,2,3]);
- assert(list_rotate([1,2,3,4,5],-1) == [5,1,2,3,4]);
- assert(list_rotate([1,2,3,4,5],0) == [1,2,3,4,5]);
- assert(list_rotate([1,2,3,4,5],1) == [2,3,4,5,1]);
- assert(list_rotate([1,2,3,4,5],2) == [3,4,5,1,2]);
- assert(list_rotate([1,2,3,4,5],3) == [4,5,1,2,3]);
- assert(list_rotate([1,2,3,4,5],4) == [5,1,2,3,4]);
- assert(list_rotate([1,2,3,4,5],5) == [1,2,3,4,5]);
- assert(list_rotate([1,2,3,4,5],6) == [2,3,4,5,1]);
- assert(list_rotate([],3) == []);
+ assert(list_rotate([1,2,3,4,5],-2) == [4,5,1,2,3]);
+ assert(list_rotate([1,2,3,4,5],-1) == [5,1,2,3,4]);
+ assert(list_rotate([1,2,3,4,5],0) == [1,2,3,4,5]);
+ assert(list_rotate([1,2,3,4,5],1) == [2,3,4,5,1]);
+ assert(list_rotate([1,2,3,4,5],2) == [3,4,5,1,2]);
+ assert(list_rotate([1,2,3,4,5],3) == [4,5,1,2,3]);
+ assert(list_rotate([1,2,3,4,5],4) == [5,1,2,3,4]);
+ assert(list_rotate([1,2,3,4,5],5) == [1,2,3,4,5]);
+ assert(list_rotate([1,2,3,4,5],6) == [2,3,4,5,1]);
+ assert(list_rotate([],3) == []);
}
test_list_rotate();
module test_deduplicate() {
- assert(deduplicate([8,3,4,4,4,8,2,3,3,8,8]) == [8,3,4,8,2,3,8]);
- assert(deduplicate(closed=true, [8,3,4,4,4,8,2,3,3,8,8]) == [8,3,4,8,2,3]);
- assert(deduplicate("Hello") == ["H","e","l","o"]);
- assert(deduplicate([[3,4],[7,1.99],[7,2],[1,4]],eps=0.1) == [[3,4],[7,2],[1,4]]);
+ assert(deduplicate([8,3,4,4,4,8,2,3,3,8,8]) == [8,3,4,8,2,3,8]);
+ assert(deduplicate(closed=true, [8,3,4,4,4,8,2,3,3,8,8]) == [8,3,4,8,2,3]);
+ assert(deduplicate("Hello") == ["H","e","l","o"]);
+ assert(deduplicate([[3,4],[7,1.99],[7,2],[1,4]],eps=0.1) == [[3,4],[7,2],[1,4]]);
}
test_deduplicate();
module test_deduplicate_indexed() {
- assert(deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1]) == [1,4,1,2,0,1]);
- assert(deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1], closed=true) == [1,4,1,2,0]);
+ assert(deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1]) == [1,4,1,2,0,1]);
+ assert(deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1], closed=true) == [1,4,1,2,0]);
}
test_deduplicate_indexed();
module test_list_set() {
- assert(list_set([2,3,4,5], 2, 21) == [2,3,21,5]);
- assert(list_set([2,3,4,5], [1,3], [81,47]) == [2,81,4,47]);
+ assert(list_set([2,3,4,5], 2, 21) == [2,3,21,5]);
+ assert(list_set([2,3,4,5], [1,3], [81,47]) == [2,81,4,47]);
}
test_list_set();
module test_list_remove() {
- assert(list_remove([3,6,9,12],1) == [3,9,12]);
- assert(list_remove([3,6,9,12],[1,3]) == [3,9]);
+ assert(list_remove([3,6,9,12],1) == [3,9,12]);
+ assert(list_remove([3,6,9,12],[1,3]) == [3,9]);
}
test_list_remove();
module test_list_remove_values() {
- animals = ["bat", "cat", "rat", "dog", "bat", "rat"];
- assert(list_remove_values(animals, "rat") == ["bat","cat","dog","bat","rat"]);
- assert(list_remove_values(animals, "bat", all=true) == ["cat","rat","dog","rat"]);
- assert(list_remove_values(animals, ["bat","rat"]) == ["cat","dog","bat","rat"]);
- assert(list_remove_values(animals, ["bat","rat"], all=true) == ["cat","dog"]);
- assert(list_remove_values(animals, ["tucan","rat"], all=true) == ["bat","cat","dog","bat"]);
+ animals = ["bat", "cat", "rat", "dog", "bat", "rat"];
+ assert(list_remove_values(animals, "rat") == ["bat","cat","dog","bat","rat"]);
+ assert(list_remove_values(animals, "bat", all=true) == ["cat","rat","dog","rat"]);
+ assert(list_remove_values(animals, ["bat","rat"]) == ["cat","dog","bat","rat"]);
+ assert(list_remove_values(animals, ["bat","rat"], all=true) == ["cat","dog"]);
+ assert(list_remove_values(animals, ["tucan","rat"], all=true) == ["bat","cat","dog","bat"]);
}
test_list_remove_values();
module test_list_insert() {
- assert(list_insert([3,6,9,12],1,5) == [3,5,6,9,12]);
- assert(list_insert([3,6,9,12],[1,3],[5,11]) == [3,5,6,9,11,12]);
+ assert(list_insert([3,6,9,12],1,5) == [3,5,6,9,12]);
+ assert(list_insert([3,6,9,12],[1,3],[5,11]) == [3,5,6,9,11,12]);
}
test_list_insert();
module test_bselect() {
- assert(bselect([3,4,5,6,7], [false,false,false,false,false]) == []);
- assert(bselect([3,4,5,6,7], [false,true,true,false,true]) == [4,5,7]);
- assert(bselect([3,4,5,6,7], [true,true,true,true,true]) == [3,4,5,6,7]);
+ assert(bselect([3,4,5,6,7], [false,false,false,false,false]) == []);
+ assert(bselect([3,4,5,6,7], [false,true,true,false,true]) == [4,5,7]);
+ assert(bselect([3,4,5,6,7], [true,true,true,true,true]) == [3,4,5,6,7]);
}
test_bselect();
module test_list_bset() {
- assert(list_bset([false,true,false,true,false], [3,4]) == [0,3,0,4,0]);
- assert(list_bset([false,true,false,true,false], [3,4], dflt=1) == [1,3,1,4,1]);
+ assert(list_bset([false,true,false,true,false], [3,4]) == [0,3,0,4,0]);
+ assert(list_bset([false,true,false,true,false], [3,4], dflt=1) == [1,3,1,4,1]);
}
test_list_bset();
module test_list_increasing() {
- assert(list_increasing([1,2,3,4]) == true);
- assert(list_increasing([1,3,2,4]) == false);
- assert(list_increasing([4,3,2,1]) == false);
+ assert(list_increasing([1,2,3,4]) == true);
+ assert(list_increasing([1,3,2,4]) == false);
+ assert(list_increasing([4,3,2,1]) == false);
}
test_list_increasing();
module test_list_decreasing() {
- assert(list_decreasing([1,2,3,4]) == false);
- assert(list_decreasing([4,2,3,1]) == false);
- assert(list_decreasing([4,3,2,1]) == true);
+ assert(list_decreasing([1,2,3,4]) == false);
+ assert(list_decreasing([4,2,3,1]) == false);
+ assert(list_decreasing([4,3,2,1]) == true);
}
test_list_decreasing();
module test_list_shortest() {
- assert(list_shortest(["foobar", "bazquxx", "abcd"]) == 4);
+ assert(list_shortest(["foobar", "bazquxx", "abcd"]) == 4);
}
test_list_shortest();
module test_list_longest() {
- assert(list_longest(["foobar", "bazquxx", "abcd"]) == 7);
+ assert(list_longest(["foobar", "bazquxx", "abcd"]) == 7);
}
test_list_longest();
module test_list_pad() {
- assert(list_pad([4,5,6], 5, 8) == [4,5,6,8,8]);
- assert(list_pad([4,5,6,7,8], 5, 8) == [4,5,6,7,8]);
- assert(list_pad([4,5,6,7,8,9], 5, 8) == [4,5,6,7,8,9]);
+ assert(list_pad([4,5,6], 5, 8) == [4,5,6,8,8]);
+ assert(list_pad([4,5,6,7,8], 5, 8) == [4,5,6,7,8]);
+ assert(list_pad([4,5,6,7,8,9], 5, 8) == [4,5,6,7,8,9]);
}
test_list_pad();
module test_list_trim() {
- assert(list_trim([4,5,6], 5) == [4,5,6]);
- assert(list_trim([4,5,6,7,8], 5) == [4,5,6,7,8]);
- assert(list_trim([3,4,5,6,7,8,9], 5) == [3,4,5,6,7]);
+ assert(list_trim([4,5,6], 5) == [4,5,6]);
+ assert(list_trim([4,5,6,7,8], 5) == [4,5,6,7,8]);
+ assert(list_trim([3,4,5,6,7,8,9], 5) == [3,4,5,6,7]);
}
test_list_trim();
module test_list_fit() {
- assert(list_fit([4,5,6], 5, 8) == [4,5,6,8,8]);
- assert(list_fit([4,5,6,7,8], 5, 8) == [4,5,6,7,8]);
- assert(list_fit([3,4,5,6,7,8,9], 5, 8) == [3,4,5,6,7]);
+ assert(list_fit([4,5,6], 5, 8) == [4,5,6,8,8]);
+ assert(list_fit([4,5,6,7,8], 5, 8) == [4,5,6,7,8]);
+ assert(list_fit([3,4,5,6,7,8,9], 5, 8) == [3,4,5,6,7]);
}
test_list_fit();
module test_idx() {
- colors = ["red", "green", "blue", "cyan"];
- assert([for (i=idx(colors)) i] == [0,1,2,3]);
- assert([for (i=idx(colors,end=-2)) i] == [0,1,2]);
- assert([for (i=idx(colors,start=1)) i] == [1,2,3]);
- assert([for (i=idx(colors,start=1,end=-2)) i] == [1,2]);
+ colors = ["red", "green", "blue", "cyan"];
+ assert([for (i=idx(colors)) i] == [0,1,2,3]);
+ assert([for (i=idx(colors,end=-2)) i] == [0,1,2]);
+ assert([for (i=idx(colors,start=1)) i] == [1,2,3]);
+ assert([for (i=idx(colors,start=1,end=-2)) i] == [1,2]);
}
test_idx();
module test_enumerate() {
- assert(enumerate(["a","b","c"]) == [[0,"a"], [1,"b"], [2,"c"]]);
- assert(enumerate([[88,"a"],[76,"b"],[21,"c"]], idx=1) == [[0,"a"], [1,"b"], [2,"c"]]);
- assert(enumerate([["cat","a",12],["dog","b",10],["log","c",14]], idx=[1:2]) == [[0,"a",12], [1,"b",10], [2,"c",14]]);
+ assert(enumerate(["a","b","c"]) == [[0,"a"], [1,"b"], [2,"c"]]);
+ assert(enumerate([[88,"a"],[76,"b"],[21,"c"]], idx=1) == [[0,"a"], [1,"b"], [2,"c"]]);
+ assert(enumerate([["cat","a",12],["dog","b",10],["log","c",14]], idx=[1:2]) == [[0,"a",12], [1,"b",10], [2,"c",14]]);
}
test_enumerate();
module test_shuffle() {
- nums1 = [for (i=list_range(100)) i];
- nums2 = shuffle(nums1);
- nums3 = shuffle(nums2);
- assert(len(nums2)==len(nums1));
- assert(len(nums3)==len(nums2));
- assert(nums1!=nums2);
- assert(nums2!=nums3);
- assert(nums1!=nums3);
+ nums1 = [for (i=list_range(100)) i];
+ nums2 = shuffle(nums1);
+ nums3 = shuffle(nums2);
+ assert(len(nums2)==len(nums1));
+ assert(len(nums3)==len(nums2));
+ assert(nums1!=nums2);
+ assert(nums2!=nums3);
+ assert(nums1!=nums3);
}
test_shuffle();
module test_sort() {
- assert(sort([7,3,9,4,3,1,8]) == [1,3,3,4,7,8,9]);
- assert(sort(["cat", "oat", "sat", "bat", "vat", "rat", "pat", "mat", "fat", "hat", "eat"]) == ["bat", "cat", "eat", "fat", "hat", "mat", "oat", "pat", "rat", "sat", "vat"]);
- assert(sort(enumerate([[2,3,4],[1,2,3],[2,4,3]]),idx=1)==[[1,[1,2,3]], [0,[2,3,4]], [2,[2,4,3]]]);
+ assert(sort([7,3,9,4,3,1,8]) == [1,3,3,4,7,8,9]);
+ assert(sort(["cat", "oat", "sat", "bat", "vat", "rat", "pat", "mat", "fat", "hat", "eat"]) == ["bat", "cat", "eat", "fat", "hat", "mat", "oat", "pat", "rat", "sat", "vat"]);
+ assert(sort(enumerate([[2,3,4],[1,2,3],[2,4,3]]),idx=1)==[[1,[1,2,3]], [0,[2,3,4]], [2,[2,4,3]]]);
}
test_sort();
module test_sortidx() {
- lst1 = ["d","b","e","c"];
- assert(sortidx(lst1) == [1,3,0,2]);
- lst2 = [
- ["foo", 88, [0,0,1], false],
- ["bar", 90, [0,1,0], true],
- ["baz", 89, [1,0,0], false],
- ["qux", 23, [1,1,1], true]
- ];
- assert(sortidx(lst2, idx=1) == [3,0,2,1]);
- assert(sortidx(lst2, idx=0) == [1,2,0,3]);
- assert(sortidx(lst2, idx=[1,3]) == [3,0,2,1]);
- lst3 = [[-4, 0, 0], [0, 0, -4], [0, -4, 0], [-4, 0, 0], [0, -4, 0], [0, 0, 4], [0, 0, -4], [0, 4, 0], [4, 0, 0], [0, 0, 4], [0, 4, 0], [4, 0, 0]];
- assert(sortidx(lst3)==[0,3,2,4,1,6,5,9,7,10,8,11]);
+ lst1 = ["d","b","e","c"];
+ assert(sortidx(lst1) == [1,3,0,2]);
+ lst2 = [
+ ["foo", 88, [0,0,1], false],
+ ["bar", 90, [0,1,0], true],
+ ["baz", 89, [1,0,0], false],
+ ["qux", 23, [1,1,1], true]
+ ];
+ assert(sortidx(lst2, idx=1) == [3,0,2,1]);
+ assert(sortidx(lst2, idx=0) == [1,2,0,3]);
+ assert(sortidx(lst2, idx=[1,3]) == [3,0,2,1]);
+ lst3 = [[-4, 0, 0], [0, 0, -4], [0, -4, 0], [-4, 0, 0], [0, -4, 0], [0, 0, 4], [0, 0, -4], [0, 4, 0], [4, 0, 0], [0, 0, 4], [0, 4, 0], [4, 0, 0]];
+ assert(sortidx(lst3)==[0,3,2,4,1,6,5,9,7,10,8,11]);
}
test_sortidx();
module test_unique() {
- assert(unique([]) == []);
- assert(unique([8]) == [8]);
- assert(unique([7,3,9,4,3,1,8]) == [1,3,4,7,8,9]);
+ assert(unique([]) == []);
+ assert(unique([8]) == [8]);
+ assert(unique([7,3,9,4,3,1,8]) == [1,3,4,7,8,9]);
}
test_unique();
@@ -265,100 +265,100 @@ test_unique();
module test_subindex() {
- v = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
- assert(subindex(v,2) == [3, 7, 11, 15]);
- assert(subindex(v,[2,1]) == [[3, 2], [7, 6], [11, 10], [15, 14]]);
- assert(subindex(v,[1:3]) == [[2, 3, 4], [6, 7, 8], [10, 11, 12], [14, 15, 16]]);
+ v = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
+ assert(subindex(v,2) == [3, 7, 11, 15]);
+ assert(subindex(v,[2,1]) == [[3, 2], [7, 6], [11, 10], [15, 14]]);
+ assert(subindex(v,[1:3]) == [[2, 3, 4], [6, 7, 8], [10, 11, 12], [14, 15, 16]]);
}
test_subindex();
module test_pair() {
- assert(pair([3,4,5,6]) == [[3,4], [4,5], [5,6]]);
- assert(pair("ABCD") == [["A","B"], ["B","C"], ["C","D"]]);
+ assert(pair([3,4,5,6]) == [[3,4], [4,5], [5,6]]);
+ assert(pair("ABCD") == [["A","B"], ["B","C"], ["C","D"]]);
}
test_pair();
module test_pair_wrap() {
- assert(pair_wrap([3,4,5,6]) == [[3,4], [4,5], [5,6], [6,3]]);
- assert(pair_wrap("ABCD") == [["A","B"], ["B","C"], ["C","D"], ["D","A"]]);
+ assert(pair_wrap([3,4,5,6]) == [[3,4], [4,5], [5,6], [6,3]]);
+ assert(pair_wrap("ABCD") == [["A","B"], ["B","C"], ["C","D"], ["D","A"]]);
}
test_pair_wrap();
module test_triplet() {
- assert(triplet([3,4,5,6,7]) == [[3,4,5], [4,5,6], [5,6,7]]);
- assert(triplet("ABCDE") == [["A","B","C"], ["B","C","D"], ["C","D","E"]]);
+ assert(triplet([3,4,5,6,7]) == [[3,4,5], [4,5,6], [5,6,7]]);
+ assert(triplet("ABCDE") == [["A","B","C"], ["B","C","D"], ["C","D","E"]]);
}
test_triplet();
module test_triplet_wrap() {
- assert(triplet_wrap([3,4,5,6]) == [[3,4,5], [4,5,6], [5,6,3], [6,3,4]]);
- assert(triplet_wrap("ABCD") == [["A","B","C"], ["B","C","D"], ["C","D","A"], ["D","A","B"]]);
+ assert(triplet_wrap([3,4,5,6]) == [[3,4,5], [4,5,6], [5,6,3], [6,3,4]]);
+ assert(triplet_wrap("ABCD") == [["A","B","C"], ["B","C","D"], ["C","D","A"], ["D","A","B"]]);
}
test_triplet_wrap();
module test_permute() {
- assert(permute([3,4,5,6]) == [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]);
- assert(permute([3,4,5,6],n=3) == [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]);
+ assert(permute([3,4,5,6]) == [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]);
+ assert(permute([3,4,5,6],n=3) == [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]);
}
test_permute();
module test_repeat_entries() {
- list = [0,1,2,3];
- assert(repeat_entries(list, 6) == [0,0,1,2,2,3]);
- assert(repeat_entries(list, 6, exact=false) == [0,0,1,1,2,2,3,3]);
- assert(repeat_entries(list, [1,1,2,1], exact=false) == [0,1,2,2,3]);
+ list = [0,1,2,3];
+ assert(repeat_entries(list, 6) == [0,0,1,2,2,3]);
+ assert(repeat_entries(list, 6, exact=false) == [0,0,1,1,2,2,3,3]);
+ assert(repeat_entries(list, [1,1,2,1], exact=false) == [0,1,2,2,3]);
}
test_repeat_entries();
module test_zip() {
- v1 = [1,2,3,4];
- v2 = [5,6,7];
- v3 = [8,9,10,11];
- assert(zip(v1,v3) == [[1,8],[2,9],[3,10],[4,11]]);
- assert(zip([v1,v3]) == [[1,8],[2,9],[3,10],[4,11]]);
- assert(zip([v1,v2],fit="short") == [[1,5],[2,6],[3,7]]);
- assert(zip([v1,v2],fit="long") == [[1,5],[2,6],[3,7],[4,undef]]);
- assert(zip([v1,v2],fit="long", fill=0) == [[1,5],[2,6],[3,7],[4,0]]);
- assert(zip([v1,v2,v3],fit="long") == [[1,5,8],[2,6,9],[3,7,10],[4,undef,11]]);
+ v1 = [1,2,3,4];
+ v2 = [5,6,7];
+ v3 = [8,9,10,11];
+ assert(zip(v1,v3) == [[1,8],[2,9],[3,10],[4,11]]);
+ assert(zip([v1,v3]) == [[1,8],[2,9],[3,10],[4,11]]);
+ assert(zip([v1,v2],fit="short") == [[1,5],[2,6],[3,7]]);
+ assert(zip([v1,v2],fit="long") == [[1,5],[2,6],[3,7],[4,undef]]);
+ assert(zip([v1,v2],fit="long", fill=0) == [[1,5],[2,6],[3,7],[4,0]]);
+ assert(zip([v1,v2,v3],fit="long") == [[1,5,8],[2,6,9],[3,7,10],[4,undef,11]]);
}
test_zip();
module test_array_group() {
- v = [1,2,3,4,5,6];
- assert(array_group(v,2) == [[1,2], [3,4], [5,6]]);
- assert(array_group(v,3) == [[1,2,3], [4,5,6]]);
- assert(array_group(v,4,0) == [[1,2,3,4], [5,6,0,0]]);
+ v = [1,2,3,4,5,6];
+ assert(array_group(v,2) == [[1,2], [3,4], [5,6]]);
+ assert(array_group(v,3) == [[1,2,3], [4,5,6]]);
+ assert(array_group(v,4,0) == [[1,2,3,4], [5,6,0,0]]);
}
test_array_group();
module test_flatten() {
- assert(flatten([[1,2,3], [4,5,[6,7,8]]]) == [1,2,3,4,5,[6,7,8]]);
+ assert(flatten([[1,2,3], [4,5,[6,7,8]]]) == [1,2,3,4,5,[6,7,8]]);
}
test_flatten();
module test_array_dim() {
- assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) == [2,2,3]);
- assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 0) == 2);
- assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 2) == 3);
- assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9]]]) == [2,undef,3]);
+ assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) == [2,2,3]);
+ assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 0) == 2);
+ assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 2) == 3);
+ assert(array_dim([[[1,2,3],[4,5,6]],[[7,8,9]]]) == [2,undef,3]);
}
test_array_dim();
module test_transpose() {
- assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]);
- assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]);
- assert(transpose([3,4,5]) == [3,4,5]);
+ assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]);
+ assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]);
+ assert(transpose([3,4,5]) == [3,4,5]);
}
test_transpose();
@@ -366,4 +366,4 @@ test_transpose();
cube();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_common.scad b/tests/test_common.scad
index 4710965..d6756b0 100644
--- a/tests/test_common.scad
+++ b/tests/test_common.scad
@@ -2,254 +2,254 @@ include
module test_typeof() {
- assert(typeof(undef) == "undef");
- assert(typeof(true) == "boolean");
- assert(typeof(false) == "boolean");
- assert(typeof(-123) == "number");
- assert(typeof(0) == "number");
- assert(typeof(123) == "number");
- assert(typeof("") == "string");
- assert(typeof("foo") == "string");
- assert(typeof([]) == "list");
- assert(typeof(["foo","bar"]) == "list");
- assert(typeof([123,849,32]) == "list");
- assert(typeof([0:5]) == "range");
- assert(typeof([-3:0]) == "range");
- assert(typeof([0:1:5]) == "range");
- assert(typeof([-3:2:5]) == "range");
- assert(typeof([10:-2:-10]) == "range");
+ assert(typeof(undef) == "undef");
+ assert(typeof(true) == "boolean");
+ assert(typeof(false) == "boolean");
+ assert(typeof(-123) == "number");
+ assert(typeof(0) == "number");
+ assert(typeof(123) == "number");
+ assert(typeof("") == "string");
+ assert(typeof("foo") == "string");
+ assert(typeof([]) == "list");
+ assert(typeof(["foo","bar"]) == "list");
+ assert(typeof([123,849,32]) == "list");
+ assert(typeof([0:5]) == "range");
+ assert(typeof([-3:0]) == "range");
+ assert(typeof([0:1:5]) == "range");
+ assert(typeof([-3:2:5]) == "range");
+ assert(typeof([10:-2:-10]) == "range");
}
test_typeof();
module test_is_type() {
- assert(is_type(undef,"undef"));
- assert(is_type(true,"boolean"));
- assert(is_type(false,"boolean"));
- assert(is_type(-123,"number"));
- assert(is_type(0,"number"));
- assert(is_type(123,"number"));
- assert(is_type("","string"));
- assert(is_type("foo","string"));
- assert(is_type([],"list"));
- assert(is_type([1,2,3],"list"));
- assert(is_type(["foo","bar"],"list"));
- assert(is_type([0:5],"range"));
+ assert(is_type(undef,"undef"));
+ assert(is_type(true,"boolean"));
+ assert(is_type(false,"boolean"));
+ assert(is_type(-123,"number"));
+ assert(is_type(0,"number"));
+ assert(is_type(123,"number"));
+ assert(is_type("","string"));
+ assert(is_type("foo","string"));
+ assert(is_type([],"list"));
+ assert(is_type([1,2,3],"list"));
+ assert(is_type(["foo","bar"],"list"));
+ assert(is_type([0:5],"range"));
- assert(is_type(undef,["undef"]));
- assert(is_type(true,["boolean"]));
- assert(is_type(false,["boolean"]));
- assert(is_type(-123,["number"]));
- assert(is_type(0,["number"]));
- assert(is_type(123,["number"]));
- assert(is_type("",["string"]));
- assert(is_type("foo",["string"]));
- assert(is_type([],["list"]));
- assert(is_type([1,2,3],["list"]));
- assert(is_type(["foo","bar"],["list"]));
- assert(is_type([0:5],["range"]));
+ assert(is_type(undef,["undef"]));
+ assert(is_type(true,["boolean"]));
+ assert(is_type(false,["boolean"]));
+ assert(is_type(-123,["number"]));
+ assert(is_type(0,["number"]));
+ assert(is_type(123,["number"]));
+ assert(is_type("",["string"]));
+ assert(is_type("foo",["string"]));
+ assert(is_type([],["list"]));
+ assert(is_type([1,2,3],["list"]));
+ assert(is_type(["foo","bar"],["list"]));
+ assert(is_type([0:5],["range"]));
- assert(is_type(123,["number","string"]));
- assert(is_type("foo",["number","string"]));
+ assert(is_type(123,["number","string"]));
+ assert(is_type("foo",["number","string"]));
}
test_is_type();
module test_is_def() {
- assert(!is_def(undef));
- assert(is_def(true));
- assert(is_def(false));
- assert(is_def(-123));
- assert(is_def(0));
- assert(is_def(123));
- assert(is_def(""));
- assert(is_def("foo"));
- assert(is_def([]));
- assert(is_def([3,4,5]));
- assert(is_def(["foo","bar","baz"]));
- assert(is_def([0:5]));
+ assert(!is_def(undef));
+ assert(is_def(true));
+ assert(is_def(false));
+ assert(is_def(-123));
+ assert(is_def(0));
+ assert(is_def(123));
+ assert(is_def(""));
+ assert(is_def("foo"));
+ assert(is_def([]));
+ assert(is_def([3,4,5]));
+ assert(is_def(["foo","bar","baz"]));
+ assert(is_def([0:5]));
}
test_is_def();
module test_is_str() {
- assert(!is_str(undef));
- assert(!is_str(true));
- assert(!is_str(false));
- assert(!is_str(-123));
- assert(!is_str(0));
- assert(!is_str(123));
- assert(is_str(""));
- assert(is_str("foo"));
- assert(!is_str([]));
- assert(!is_str([3,4,5]));
- assert(!is_str(["foo","bar","baz"]));
- assert(!is_str([0:5]));
+ assert(!is_str(undef));
+ assert(!is_str(true));
+ assert(!is_str(false));
+ assert(!is_str(-123));
+ assert(!is_str(0));
+ assert(!is_str(123));
+ assert(is_str(""));
+ assert(is_str("foo"));
+ assert(!is_str([]));
+ assert(!is_str([3,4,5]));
+ assert(!is_str(["foo","bar","baz"]));
+ assert(!is_str([0:5]));
}
test_is_str();
module test_is_int() {
- assert(is_int(-999));
- assert(is_int(-1));
- assert(is_int(0));
- assert(is_int(1));
- assert(is_int(999));
- assert(!is_int(-1.1));
- assert(!is_int(1.1));
- assert(!is_int(-0.1));
- assert(!is_int(0.1));
- assert(!is_int(-99.1));
- assert(!is_int(99.1));
- assert(!is_int(undef));
- assert(!is_int(false));
- assert(!is_int(true));
- assert(!is_int("foo"));
- assert(!is_int([0,1,2]));
- assert(!is_int([0:1:2]));
+ assert(is_int(-999));
+ assert(is_int(-1));
+ assert(is_int(0));
+ assert(is_int(1));
+ assert(is_int(999));
+ assert(!is_int(-1.1));
+ assert(!is_int(1.1));
+ assert(!is_int(-0.1));
+ assert(!is_int(0.1));
+ assert(!is_int(-99.1));
+ assert(!is_int(99.1));
+ assert(!is_int(undef));
+ assert(!is_int(false));
+ assert(!is_int(true));
+ assert(!is_int("foo"));
+ assert(!is_int([0,1,2]));
+ assert(!is_int([0:1:2]));
}
test_is_int();
module test_is_integer() {
- assert(is_integer(-999));
- assert(is_integer(-1));
- assert(is_integer(0));
- assert(is_integer(1));
- assert(is_integer(999));
- assert(!is_integer(-1.1));
- assert(!is_integer(1.1));
- assert(!is_integer(-0.1));
- assert(!is_integer(0.1));
- assert(!is_integer(-99.1));
- assert(!is_integer(99.1));
- assert(!is_integer(undef));
- assert(!is_integer(false));
- assert(!is_integer(true));
- assert(!is_integer("foo"));
- assert(!is_integer([0,1,2]));
- assert(!is_integer([0:1:2]));
+ assert(is_integer(-999));
+ assert(is_integer(-1));
+ assert(is_integer(0));
+ assert(is_integer(1));
+ assert(is_integer(999));
+ assert(!is_integer(-1.1));
+ assert(!is_integer(1.1));
+ assert(!is_integer(-0.1));
+ assert(!is_integer(0.1));
+ assert(!is_integer(-99.1));
+ assert(!is_integer(99.1));
+ assert(!is_integer(undef));
+ assert(!is_integer(false));
+ assert(!is_integer(true));
+ assert(!is_integer("foo"));
+ assert(!is_integer([0,1,2]));
+ assert(!is_integer([0:1:2]));
}
test_is_integer();
module test_default() {
- assert(default(undef,23) == 23);
- assert(default(true,23) == true);
- assert(default(false,23) == false);
- assert(default(-123,23) == -123);
- assert(default(0,23) == 0);
- assert(default(123,23) == 123);
- assert(default("",23) == "");
- assert(default("foo",23) == "foo");
+ assert(default(undef,23) == 23);
+ assert(default(true,23) == true);
+ assert(default(false,23) == false);
+ assert(default(-123,23) == -123);
+ assert(default(0,23) == 0);
+ assert(default(123,23) == 123);
+ assert(default("",23) == "");
+ assert(default("foo",23) == "foo");
}
test_default();
module test_first_defined() {
- assert(first_defined([undef,undef,true,false,undef]) == true);
- assert(first_defined([undef,undef,false,true,undef]) == false);
- assert(first_defined([undef,undef,0,1,undef]) == 0);
- assert(first_defined([undef,undef,43,44,undef]) == 43);
- assert(first_defined([undef,undef,"foo","bar",undef]) == "foo");
- assert(first_defined([0,1,2,3,4]) == 0);
- assert(first_defined([2,3,4]) == 2);
- assert(first_defined([[undef,undef],[undef,true],[false,undef]],recursive=true) == [undef, true]);
+ assert(first_defined([undef,undef,true,false,undef]) == true);
+ assert(first_defined([undef,undef,false,true,undef]) == false);
+ assert(first_defined([undef,undef,0,1,undef]) == 0);
+ assert(first_defined([undef,undef,43,44,undef]) == 43);
+ assert(first_defined([undef,undef,"foo","bar",undef]) == "foo");
+ assert(first_defined([0,1,2,3,4]) == 0);
+ assert(first_defined([2,3,4]) == 2);
+ assert(first_defined([[undef,undef],[undef,true],[false,undef]],recursive=true) == [undef, true]);
}
test_first_defined();
module test_num_defined() {
- assert(num_defined([undef,undef,true,false,undef]) == 2);
- assert(num_defined([9,undef,true,false,undef]) == 3);
- assert(num_defined([undef,9,true,false,undef]) == 3);
- assert(num_defined(["foo",9,true,false,undef]) == 4);
+ assert(num_defined([undef,undef,true,false,undef]) == 2);
+ assert(num_defined([9,undef,true,false,undef]) == 3);
+ assert(num_defined([undef,9,true,false,undef]) == 3);
+ assert(num_defined(["foo",9,true,false,undef]) == 4);
}
test_num_defined();
module test_any_defined() {
- assert(!any_defined([undef,undef,undef,undef,undef]));
- assert(any_defined([3,undef,undef,undef,undef]));
- assert(any_defined([undef,3,undef,undef,undef]));
- assert(any_defined([undef,undef,3,undef,undef]));
- assert(any_defined([undef,undef,undef,3,undef]));
- assert(any_defined([undef,undef,undef,undef,3]));
- assert(any_defined([3,undef,undef,undef,3]));
- assert(any_defined([3,3,3,3,3]));
- assert(any_defined(["foo",undef,undef,undef,undef]));
- assert(any_defined([undef,"foo",undef,undef,undef]));
- assert(any_defined([undef,undef,"foo",undef,undef]));
- assert(any_defined([undef,undef,undef,"foo",undef]));
- assert(any_defined([undef,undef,undef,undef,"foo"]));
- assert(any_defined(["foo",undef,undef,undef,"foo"]));
- assert(any_defined(["foo","foo","foo","foo","foo"]));
- assert(any_defined([undef,undef,true,false,undef]));
+ assert(!any_defined([undef,undef,undef,undef,undef]));
+ assert(any_defined([3,undef,undef,undef,undef]));
+ assert(any_defined([undef,3,undef,undef,undef]));
+ assert(any_defined([undef,undef,3,undef,undef]));
+ assert(any_defined([undef,undef,undef,3,undef]));
+ assert(any_defined([undef,undef,undef,undef,3]));
+ assert(any_defined([3,undef,undef,undef,3]));
+ assert(any_defined([3,3,3,3,3]));
+ assert(any_defined(["foo",undef,undef,undef,undef]));
+ assert(any_defined([undef,"foo",undef,undef,undef]));
+ assert(any_defined([undef,undef,"foo",undef,undef]));
+ assert(any_defined([undef,undef,undef,"foo",undef]));
+ assert(any_defined([undef,undef,undef,undef,"foo"]));
+ assert(any_defined(["foo",undef,undef,undef,"foo"]));
+ assert(any_defined(["foo","foo","foo","foo","foo"]));
+ assert(any_defined([undef,undef,true,false,undef]));
}
test_any_defined();
module test_all_defined() {
- assert(!all_defined([undef,undef,undef,undef,undef]));
- assert(!all_defined([3,undef,undef,undef,undef]));
- assert(!all_defined([undef,3,undef,undef,undef]));
- assert(!all_defined([undef,undef,3,undef,undef]));
- assert(!all_defined([undef,undef,undef,3,undef]));
- assert(!all_defined([undef,undef,undef,undef,3]));
- assert(!all_defined([3,undef,undef,undef,3]));
- assert(all_defined([3,3,3,3,3]));
- assert(!all_defined(["foo",undef,undef,undef,undef]));
- assert(!all_defined([undef,"foo",undef,undef,undef]));
- assert(!all_defined([undef,undef,"foo",undef,undef]));
- assert(!all_defined([undef,undef,undef,"foo",undef]));
- assert(!all_defined([undef,undef,undef,undef,"foo"]));
- assert(!all_defined(["foo",undef,undef,undef,"foo"]));
- assert(all_defined(["foo","foo","foo","foo","foo"]));
- assert(!all_defined([undef,undef,true,false,undef]));
+ assert(!all_defined([undef,undef,undef,undef,undef]));
+ assert(!all_defined([3,undef,undef,undef,undef]));
+ assert(!all_defined([undef,3,undef,undef,undef]));
+ assert(!all_defined([undef,undef,3,undef,undef]));
+ assert(!all_defined([undef,undef,undef,3,undef]));
+ assert(!all_defined([undef,undef,undef,undef,3]));
+ assert(!all_defined([3,undef,undef,undef,3]));
+ assert(all_defined([3,3,3,3,3]));
+ assert(!all_defined(["foo",undef,undef,undef,undef]));
+ assert(!all_defined([undef,"foo",undef,undef,undef]));
+ assert(!all_defined([undef,undef,"foo",undef,undef]));
+ assert(!all_defined([undef,undef,undef,"foo",undef]));
+ assert(!all_defined([undef,undef,undef,undef,"foo"]));
+ assert(!all_defined(["foo",undef,undef,undef,"foo"]));
+ assert(all_defined(["foo","foo","foo","foo","foo"]));
+ assert(!all_defined([undef,undef,true,false,undef]));
}
test_all_defined();
module test_get_radius() {
- assert(get_radius(r1=100,d1=undef,r=undef,d=undef,dflt=23) == 100);
- assert(get_radius(r1=undef,d1=200,r=undef,d=undef,dflt=23) == 100);
- assert(get_radius(r1=undef,d1=undef,r=100,d=undef,dflt=23) == 100);
- assert(get_radius(r1=undef,d1=undef,r=undef,d=200,dflt=23) == 100);
- assert(get_radius(r1=50,d1=undef,r=undef,d=undef,dflt=23) == 50);
- assert(get_radius(r1=undef,d1=100,r=undef,d=undef,dflt=23) == 50);
- assert(get_radius(r1=undef,d1=undef,r=50,d=undef,dflt=23) == 50);
- assert(get_radius(r1=undef,d1=undef,r=undef,d=100,dflt=23) == 50);
- assert(get_radius(r1=undef,d1=undef,r=undef,d=undef,dflt=23) == 23);
- assert(get_radius(r1=undef,d1=undef,r=undef,d=undef,dflt=undef) == undef);
+ assert(get_radius(r1=100,d1=undef,r=undef,d=undef,dflt=23) == 100);
+ assert(get_radius(r1=undef,d1=200,r=undef,d=undef,dflt=23) == 100);
+ assert(get_radius(r1=undef,d1=undef,r=100,d=undef,dflt=23) == 100);
+ assert(get_radius(r1=undef,d1=undef,r=undef,d=200,dflt=23) == 100);
+ assert(get_radius(r1=50,d1=undef,r=undef,d=undef,dflt=23) == 50);
+ assert(get_radius(r1=undef,d1=100,r=undef,d=undef,dflt=23) == 50);
+ assert(get_radius(r1=undef,d1=undef,r=50,d=undef,dflt=23) == 50);
+ assert(get_radius(r1=undef,d1=undef,r=undef,d=100,dflt=23) == 50);
+ assert(get_radius(r1=undef,d1=undef,r=undef,d=undef,dflt=23) == 23);
+ assert(get_radius(r1=undef,d1=undef,r=undef,d=undef,dflt=undef) == undef);
}
test_get_radius();
module test_get_height() {
- assert(get_height(h=undef, l=undef, height=undef, dflt=undef) == undef);
- assert(get_height(h=undef, l=undef, height=undef, dflt=23) == 23);
- assert(get_height(h=undef, l=undef, height=50, dflt=23) == 50);
- assert(get_height(h=undef, l=50, height=undef, dflt=23) == 50);
- assert(get_height(h=50, l=undef, height=undef, dflt=23) == 50);
- assert(get_height(h=undef, l=undef, height=75, dflt=23) == 75);
- assert(get_height(h=undef, l=75, height=undef, dflt=23) == 75);
- assert(get_height(h=75, l=undef, height=undef, dflt=23) == 75);
+ assert(get_height(h=undef, l=undef, height=undef, dflt=undef) == undef);
+ assert(get_height(h=undef, l=undef, height=undef, dflt=23) == 23);
+ assert(get_height(h=undef, l=undef, height=50, dflt=23) == 50);
+ assert(get_height(h=undef, l=50, height=undef, dflt=23) == 50);
+ assert(get_height(h=50, l=undef, height=undef, dflt=23) == 50);
+ assert(get_height(h=undef, l=undef, height=75, dflt=23) == 75);
+ assert(get_height(h=undef, l=75, height=undef, dflt=23) == 75);
+ assert(get_height(h=75, l=undef, height=undef, dflt=23) == 75);
}
test_get_height();
module test_scalar_vec3() {
- assert(scalar_vec3(undef) == undef);
- assert(scalar_vec3(3) == [3,3,3]);
- assert(scalar_vec3(3,dflt=1) == [3,1,1]);
- assert(scalar_vec3([3]) == [3,0,0]);
- assert(scalar_vec3([3,4]) == [3,4,0]);
- assert(scalar_vec3([3,4],dflt=1) == [3,4,1]);
- assert(scalar_vec3([3],dflt=1) == [3,1,1]);
- assert(scalar_vec3([3,4,5]) == [3,4,5]);
- assert(scalar_vec3([3,4,5,6]) == [3,4,5]);
+ assert(scalar_vec3(undef) == undef);
+ assert(scalar_vec3(3) == [3,3,3]);
+ assert(scalar_vec3(3,dflt=1) == [3,1,1]);
+ assert(scalar_vec3([3]) == [3,0,0]);
+ assert(scalar_vec3([3,4]) == [3,4,0]);
+ assert(scalar_vec3([3,4],dflt=1) == [3,4,1]);
+ assert(scalar_vec3([3],dflt=1) == [3,1,1]);
+ assert(scalar_vec3([3,4,5]) == [3,4,5]);
+ assert(scalar_vec3([3,4,5,6]) == [3,4,5]);
}
test_scalar_vec3();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_coords.scad b/tests/test_coords.scad
index 0b321d5..702a351 100644
--- a/tests/test_coords.scad
+++ b/tests/test_coords.scad
@@ -2,208 +2,208 @@ include
module test_point2d() {
- assert(point2d([1,2,3])==[1,2]);
- assert(point2d([2,3])==[2,3]);
- assert(point2d([1])==[1,0]);
+ assert(point2d([1,2,3])==[1,2]);
+ assert(point2d([2,3])==[2,3]);
+ assert(point2d([1])==[1,0]);
}
test_point2d();
module test_path2d() {
- assert(path2d([[1,2], [3,4], [5,6], [7,8]])==[[1,2],[3,4],[5,6],[7,8]]);
- assert(path2d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2],[2,3],[3,4],[4,5]]);
- assert(path2d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2],[2,3],[3,4],[4,5]]);
+ assert(path2d([[1,2], [3,4], [5,6], [7,8]])==[[1,2],[3,4],[5,6],[7,8]]);
+ assert(path2d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2],[2,3],[3,4],[4,5]]);
+ assert(path2d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2],[2,3],[3,4],[4,5]]);
}
test_path2d();
module test_point3d() {
- assert(point3d([1,2,3,4,5])==[1,2,3]);
- assert(point3d([1,2,3,4])==[1,2,3]);
- assert(point3d([1,2,3])==[1,2,3]);
- assert(point3d([2,3])==[2,3,0]);
- assert(point3d([1])==[1,0,0]);
+ assert(point3d([1,2,3,4,5])==[1,2,3]);
+ assert(point3d([1,2,3,4])==[1,2,3]);
+ assert(point3d([1,2,3])==[1,2,3]);
+ assert(point3d([2,3])==[2,3,0]);
+ assert(point3d([1])==[1,0,0]);
}
test_point3d();
module test_path3d() {
- assert(path3d([[1,2], [3,4], [5,6], [7,8]])==[[1,2,0],[3,4,0],[5,6,0],[7,8,0]]);
- assert(path3d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2,3],[2,3,4],[3,4,5],[4,5,6]]);
- assert(path3d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2,3],[2,3,4],[3,4,5],[4,5,6]]);
+ assert(path3d([[1,2], [3,4], [5,6], [7,8]])==[[1,2,0],[3,4,0],[5,6,0],[7,8,0]]);
+ assert(path3d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2,3],[2,3,4],[3,4,5],[4,5,6]]);
+ assert(path3d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2,3],[2,3,4],[3,4,5],[4,5,6]]);
}
test_path3d();
module test_point4d() {
- assert(point4d([1,2,3,4,5])==[1,2,3,4]);
- assert(point4d([1,2,3,4])==[1,2,3,4]);
- assert(point4d([1,2,3])==[1,2,3,0]);
- assert(point4d([2,3])==[2,3,0,0]);
- assert(point4d([1])==[1,0,0,0]);
+ assert(point4d([1,2,3,4,5])==[1,2,3,4]);
+ assert(point4d([1,2,3,4])==[1,2,3,4]);
+ assert(point4d([1,2,3])==[1,2,3,0]);
+ assert(point4d([2,3])==[2,3,0,0]);
+ assert(point4d([1])==[1,0,0,0]);
}
test_point4d();
module test_path4d() {
- assert(path4d([[1,2], [3,4], [5,6], [7,8]])==[[1,2,0,0],[3,4,0,0],[5,6,0,0],[7,8,0,0]]);
- assert(path4d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2,3,0],[2,3,4,0],[3,4,5,0],[4,5,6,0]]);
- assert(path4d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]);
- assert(path4d([[1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7], [4,5,6,7,8]])==[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]);
+ assert(path4d([[1,2], [3,4], [5,6], [7,8]])==[[1,2,0,0],[3,4,0,0],[5,6,0,0],[7,8,0,0]]);
+ assert(path4d([[1,2,3], [2,3,4], [3,4,5], [4,5,6]])==[[1,2,3,0],[2,3,4,0],[3,4,5,0],[4,5,6,0]]);
+ assert(path4d([[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]])==[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]);
+ assert(path4d([[1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7], [4,5,6,7,8]])==[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]);
}
test_path4d();
module test_polar_to_xy() {
- assert(approx(polar_to_xy(20,45), [20/sqrt(2), 20/sqrt(2)]));
- assert(approx(polar_to_xy(20,135), [-20/sqrt(2), 20/sqrt(2)]));
- assert(approx(polar_to_xy(20,-135), [-20/sqrt(2), -20/sqrt(2)]));
- assert(approx(polar_to_xy(20,-45), [20/sqrt(2), -20/sqrt(2)]));
- assert(approx(polar_to_xy(40,30), [40*sqrt(3)/2, 40/2]));
- assert(approx(polar_to_xy([40,30]), [40*sqrt(3)/2, 40/2]));
+ assert(approx(polar_to_xy(20,45), [20/sqrt(2), 20/sqrt(2)]));
+ assert(approx(polar_to_xy(20,135), [-20/sqrt(2), 20/sqrt(2)]));
+ assert(approx(polar_to_xy(20,-135), [-20/sqrt(2), -20/sqrt(2)]));
+ assert(approx(polar_to_xy(20,-45), [20/sqrt(2), -20/sqrt(2)]));
+ assert(approx(polar_to_xy(40,30), [40*sqrt(3)/2, 40/2]));
+ assert(approx(polar_to_xy([40,30]), [40*sqrt(3)/2, 40/2]));
}
test_polar_to_xy();
module test_xy_to_polar() {
- assert(approx(xy_to_polar([20/sqrt(2), 20/sqrt(2)]),[20,45]));
- assert(approx(xy_to_polar([-20/sqrt(2), 20/sqrt(2)]),[20,135]));
- assert(approx(xy_to_polar([-20/sqrt(2), -20/sqrt(2)]),[20,-135]));
- assert(approx(xy_to_polar([20/sqrt(2), -20/sqrt(2)]),[20,-45]));
- assert(approx(xy_to_polar([40*sqrt(3)/2, 40/2]),[40,30]));
- assert(approx(xy_to_polar([-40*sqrt(3)/2, 40/2]),[40,150]));
- assert(approx(xy_to_polar([-40*sqrt(3)/2, -40/2]),[40,-150]));
- assert(approx(xy_to_polar([40*sqrt(3)/2, -40/2]),[40,-30]));
+ assert(approx(xy_to_polar([20/sqrt(2), 20/sqrt(2)]),[20,45]));
+ assert(approx(xy_to_polar([-20/sqrt(2), 20/sqrt(2)]),[20,135]));
+ assert(approx(xy_to_polar([-20/sqrt(2), -20/sqrt(2)]),[20,-135]));
+ assert(approx(xy_to_polar([20/sqrt(2), -20/sqrt(2)]),[20,-45]));
+ assert(approx(xy_to_polar([40*sqrt(3)/2, 40/2]),[40,30]));
+ assert(approx(xy_to_polar([-40*sqrt(3)/2, 40/2]),[40,150]));
+ assert(approx(xy_to_polar([-40*sqrt(3)/2, -40/2]),[40,-150]));
+ assert(approx(xy_to_polar([40*sqrt(3)/2, -40/2]),[40,-30]));
}
test_xy_to_polar();
module test_project_plane() {
- assert(approx(project_plane([-5,0,-5], [-10,0,-10], [0,0,0], [0,-10,-10]),[0,10*sqrt(2)/2]));
- assert(approx(project_plane([0,-5,-5], [-10,0,-10], [0,0,0], [0,-10,-10]),[6.12372, 10.6066],eps=1e-5));
+ assert(approx(project_plane([-5,0,-5], [-10,0,-10], [0,0,0], [0,-10,-10]),[0,10*sqrt(2)/2]));
+ assert(approx(project_plane([0,-5,-5], [-10,0,-10], [0,0,0], [0,-10,-10]),[6.12372, 10.6066],eps=1e-5));
}
test_project_plane();
module test_lift_plane() {
- assert(approx(lift_plane([0,10*sqrt(2)/2], [-10,0,-10], [0,0,0], [0,-10,-10]),[-5,0,-5]));
- assert(approx(lift_plane([6.12372, 10.6066], [-10,0,-10], [0,0,0], [0,-10,-10]),[0,-5,-5],eps=1e-5));
+ assert(approx(lift_plane([0,10*sqrt(2)/2], [-10,0,-10], [0,0,0], [0,-10,-10]),[-5,0,-5]));
+ assert(approx(lift_plane([6.12372, 10.6066], [-10,0,-10], [0,0,0], [0,-10,-10]),[0,-5,-5],eps=1e-5));
}
test_lift_plane();
module test_cylindrical_to_xyz() {
- assert(approx(cylindrical_to_xyz(100,90,10),[0,100,10]));
- assert(approx(cylindrical_to_xyz(100,270,-10),[0,-100,-10]));
- assert(approx(cylindrical_to_xyz(100,-90,-10),[0,-100,-10]));
- assert(approx(cylindrical_to_xyz(100,180,0),[-100,0,0]));
- assert(approx(cylindrical_to_xyz(100,0,0),[100,0,0]));
- assert(approx(cylindrical_to_xyz(100,45,10),[100*sqrt(2)/2,100*sqrt(2)/2,10]));
- assert(approx(cylindrical_to_xyz([100,90,10]),[0,100,10]));
- assert(approx(cylindrical_to_xyz([100,270,-10]),[0,-100,-10]));
- assert(approx(cylindrical_to_xyz([100,-90,-10]),[0,-100,-10]));
- assert(approx(cylindrical_to_xyz([100,180,0]),[-100,0,0]));
- assert(approx(cylindrical_to_xyz([100,0,0]),[100,0,0]));
- assert(approx(cylindrical_to_xyz([100,45,10]),[100*sqrt(2)/2,100*sqrt(2)/2,10]));
+ assert(approx(cylindrical_to_xyz(100,90,10),[0,100,10]));
+ assert(approx(cylindrical_to_xyz(100,270,-10),[0,-100,-10]));
+ assert(approx(cylindrical_to_xyz(100,-90,-10),[0,-100,-10]));
+ assert(approx(cylindrical_to_xyz(100,180,0),[-100,0,0]));
+ assert(approx(cylindrical_to_xyz(100,0,0),[100,0,0]));
+ assert(approx(cylindrical_to_xyz(100,45,10),[100*sqrt(2)/2,100*sqrt(2)/2,10]));
+ assert(approx(cylindrical_to_xyz([100,90,10]),[0,100,10]));
+ assert(approx(cylindrical_to_xyz([100,270,-10]),[0,-100,-10]));
+ assert(approx(cylindrical_to_xyz([100,-90,-10]),[0,-100,-10]));
+ assert(approx(cylindrical_to_xyz([100,180,0]),[-100,0,0]));
+ assert(approx(cylindrical_to_xyz([100,0,0]),[100,0,0]));
+ assert(approx(cylindrical_to_xyz([100,45,10]),[100*sqrt(2)/2,100*sqrt(2)/2,10]));
}
test_cylindrical_to_xyz();
module test_xyz_to_cylindrical() {
- assert(approx(xyz_to_cylindrical(0,100,10),[100,90,10]));
- assert(approx(xyz_to_cylindrical(0,-100,-10),[100,-90,-10]));
- assert(approx(xyz_to_cylindrical(-100,0,0),[100,180,0]));
- assert(approx(xyz_to_cylindrical(100,0,0),[100,0,0]));
- assert(approx(xyz_to_cylindrical(100*sqrt(2)/2,100*sqrt(2)/2,10),[100,45,10]));
- assert(approx(xyz_to_cylindrical([0,100,10]),[100,90,10]));
- assert(approx(xyz_to_cylindrical([0,-100,-10]),[100,-90,-10]));
- assert(approx(xyz_to_cylindrical([-100,0,0]),[100,180,0]));
- assert(approx(xyz_to_cylindrical([100,0,0]),[100,0,0]));
- assert(approx(xyz_to_cylindrical([100*sqrt(2)/2,100*sqrt(2)/2,10]),[100,45,10]));
+ assert(approx(xyz_to_cylindrical(0,100,10),[100,90,10]));
+ assert(approx(xyz_to_cylindrical(0,-100,-10),[100,-90,-10]));
+ assert(approx(xyz_to_cylindrical(-100,0,0),[100,180,0]));
+ assert(approx(xyz_to_cylindrical(100,0,0),[100,0,0]));
+ assert(approx(xyz_to_cylindrical(100*sqrt(2)/2,100*sqrt(2)/2,10),[100,45,10]));
+ assert(approx(xyz_to_cylindrical([0,100,10]),[100,90,10]));
+ assert(approx(xyz_to_cylindrical([0,-100,-10]),[100,-90,-10]));
+ assert(approx(xyz_to_cylindrical([-100,0,0]),[100,180,0]));
+ assert(approx(xyz_to_cylindrical([100,0,0]),[100,0,0]));
+ assert(approx(xyz_to_cylindrical([100*sqrt(2)/2,100*sqrt(2)/2,10]),[100,45,10]));
}
test_xyz_to_cylindrical();
module test_spherical_to_xyz() {
- assert(approx(spherical_to_xyz(100,90,45),100*[0,sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz(100,270,45),100*[0,-sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz(100,-90,45),100*[0,-sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz(100,90,90),100*[0,1,0]));
- assert(approx(spherical_to_xyz(100,-90,90),100*[0,-1,0]));
- assert(approx(spherical_to_xyz(100,180,90),100*[-1,0,0]));
- assert(approx(spherical_to_xyz(100,0,90),100*[1,0,0]));
- assert(approx(spherical_to_xyz(100,0,0),100*[0,0,1]));
- assert(approx(spherical_to_xyz(100,0,180),100*[0,0,-1]));
- assert(approx(spherical_to_xyz([100,90,45]),100*[0,sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz([100,270,45]),100*[0,-sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz([100,-90,45]),100*[0,-sqrt(2)/2,sqrt(2)/2]));
- assert(approx(spherical_to_xyz([100,90,90]),100*[0,1,0]));
- assert(approx(spherical_to_xyz([100,-90,90]),100*[0,-1,0]));
- assert(approx(spherical_to_xyz([100,180,90]),100*[-1,0,0]));
- assert(approx(spherical_to_xyz([100,0,90]),100*[1,0,0]));
- assert(approx(spherical_to_xyz([100,0,0]),100*[0,0,1]));
- assert(approx(spherical_to_xyz([100,0,180]),100*[0,0,-1]));
+ assert(approx(spherical_to_xyz(100,90,45),100*[0,sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz(100,270,45),100*[0,-sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz(100,-90,45),100*[0,-sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz(100,90,90),100*[0,1,0]));
+ assert(approx(spherical_to_xyz(100,-90,90),100*[0,-1,0]));
+ assert(approx(spherical_to_xyz(100,180,90),100*[-1,0,0]));
+ assert(approx(spherical_to_xyz(100,0,90),100*[1,0,0]));
+ assert(approx(spherical_to_xyz(100,0,0),100*[0,0,1]));
+ assert(approx(spherical_to_xyz(100,0,180),100*[0,0,-1]));
+ assert(approx(spherical_to_xyz([100,90,45]),100*[0,sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz([100,270,45]),100*[0,-sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz([100,-90,45]),100*[0,-sqrt(2)/2,sqrt(2)/2]));
+ assert(approx(spherical_to_xyz([100,90,90]),100*[0,1,0]));
+ assert(approx(spherical_to_xyz([100,-90,90]),100*[0,-1,0]));
+ assert(approx(spherical_to_xyz([100,180,90]),100*[-1,0,0]));
+ assert(approx(spherical_to_xyz([100,0,90]),100*[1,0,0]));
+ assert(approx(spherical_to_xyz([100,0,0]),100*[0,0,1]));
+ assert(approx(spherical_to_xyz([100,0,180]),100*[0,0,-1]));
}
test_spherical_to_xyz();
module test_xyz_to_spherical() {
- assert(approx(xyz_to_spherical(0, 100*sqrt(2)/2,100*sqrt(2)/2),[100, 90,45]));
- assert(approx(xyz_to_spherical(0,-100*sqrt(2)/2,100*sqrt(2)/2),[100,-90,45]));
- assert(approx(xyz_to_spherical( 0, 100, 0),[100, 90, 90]));
- assert(approx(xyz_to_spherical( 0,-100, 0),[100,-90, 90]));
- assert(approx(xyz_to_spherical(-100, 0, 0),[100,180, 90]));
- assert(approx(xyz_to_spherical( 100, 0, 0),[100, 0, 90]));
- assert(approx(xyz_to_spherical( 0, 0, 100),[100, 0, 0]));
- assert(approx(xyz_to_spherical( 0, 0,-100),[100, 0,180]));
- assert(approx(xyz_to_spherical([0, 100*sqrt(2)/2,100*sqrt(2)/2]),[100, 90,45]));
- assert(approx(xyz_to_spherical([0,-100*sqrt(2)/2,100*sqrt(2)/2]),[100,-90,45]));
- assert(approx(xyz_to_spherical([ 0, 100, 0]),[100, 90, 90]));
- assert(approx(xyz_to_spherical([ 0,-100, 0]),[100,-90, 90]));
- assert(approx(xyz_to_spherical([-100, 0, 0]),[100,180, 90]));
- assert(approx(xyz_to_spherical([ 100, 0, 0]),[100, 0, 90]));
- assert(approx(xyz_to_spherical([ 0, 0, 100]),[100, 0, 0]));
- assert(approx(xyz_to_spherical([ 0, 0,-100]),[100, 0,180]));
+ assert(approx(xyz_to_spherical(0, 100*sqrt(2)/2,100*sqrt(2)/2),[100, 90,45]));
+ assert(approx(xyz_to_spherical(0,-100*sqrt(2)/2,100*sqrt(2)/2),[100,-90,45]));
+ assert(approx(xyz_to_spherical( 0, 100, 0),[100, 90, 90]));
+ assert(approx(xyz_to_spherical( 0,-100, 0),[100,-90, 90]));
+ assert(approx(xyz_to_spherical(-100, 0, 0),[100,180, 90]));
+ assert(approx(xyz_to_spherical( 100, 0, 0),[100, 0, 90]));
+ assert(approx(xyz_to_spherical( 0, 0, 100),[100, 0, 0]));
+ assert(approx(xyz_to_spherical( 0, 0,-100),[100, 0,180]));
+ assert(approx(xyz_to_spherical([0, 100*sqrt(2)/2,100*sqrt(2)/2]),[100, 90,45]));
+ assert(approx(xyz_to_spherical([0,-100*sqrt(2)/2,100*sqrt(2)/2]),[100,-90,45]));
+ assert(approx(xyz_to_spherical([ 0, 100, 0]),[100, 90, 90]));
+ assert(approx(xyz_to_spherical([ 0,-100, 0]),[100,-90, 90]));
+ assert(approx(xyz_to_spherical([-100, 0, 0]),[100,180, 90]));
+ assert(approx(xyz_to_spherical([ 100, 0, 0]),[100, 0, 90]));
+ assert(approx(xyz_to_spherical([ 0, 0, 100]),[100, 0, 0]));
+ assert(approx(xyz_to_spherical([ 0, 0,-100]),[100, 0,180]));
}
test_xyz_to_spherical();
module test_altaz_to_xyz() {
- assert(approx(altaz_to_xyz( 0, 0,100),[ 0,100, 0]));
- assert(approx(altaz_to_xyz( 90, 0,100),[ 0, 0, 100]));
- assert(approx(altaz_to_xyz(-90, 0,100),[ 0, 0,-100]));
- assert(approx(altaz_to_xyz( 0, 90,100),[ 100, 0, 0]));
- assert(approx(altaz_to_xyz( 0,-90,100),[-100, 0, 0]));
- assert(approx(altaz_to_xyz( 45, 90,100),[100*sqrt(2)/2,0,100*sqrt(2)/2]));
- assert(approx(altaz_to_xyz(-45, 90,100),[100*sqrt(2)/2,0,-100*sqrt(2)/2]));
- assert(approx(altaz_to_xyz([ 0, 0,100]),[ 0,100, 0]));
- assert(approx(altaz_to_xyz([ 90, 0,100]),[ 0, 0, 100]));
- assert(approx(altaz_to_xyz([-90, 0,100]),[ 0, 0,-100]));
- assert(approx(altaz_to_xyz([ 0, 90,100]),[ 100, 0, 0]));
- assert(approx(altaz_to_xyz([ 0,-90,100]),[-100, 0, 0]));
- assert(approx(altaz_to_xyz([ 45, 90,100]),[100*sqrt(2)/2,0,100*sqrt(2)/2]));
- assert(approx(altaz_to_xyz([-45, 90,100]),[100*sqrt(2)/2,0,-100*sqrt(2)/2]));
+ assert(approx(altaz_to_xyz( 0, 0,100),[ 0,100, 0]));
+ assert(approx(altaz_to_xyz( 90, 0,100),[ 0, 0, 100]));
+ assert(approx(altaz_to_xyz(-90, 0,100),[ 0, 0,-100]));
+ assert(approx(altaz_to_xyz( 0, 90,100),[ 100, 0, 0]));
+ assert(approx(altaz_to_xyz( 0,-90,100),[-100, 0, 0]));
+ assert(approx(altaz_to_xyz( 45, 90,100),[100*sqrt(2)/2,0,100*sqrt(2)/2]));
+ assert(approx(altaz_to_xyz(-45, 90,100),[100*sqrt(2)/2,0,-100*sqrt(2)/2]));
+ assert(approx(altaz_to_xyz([ 0, 0,100]),[ 0,100, 0]));
+ assert(approx(altaz_to_xyz([ 90, 0,100]),[ 0, 0, 100]));
+ assert(approx(altaz_to_xyz([-90, 0,100]),[ 0, 0,-100]));
+ assert(approx(altaz_to_xyz([ 0, 90,100]),[ 100, 0, 0]));
+ assert(approx(altaz_to_xyz([ 0,-90,100]),[-100, 0, 0]));
+ assert(approx(altaz_to_xyz([ 45, 90,100]),[100*sqrt(2)/2,0,100*sqrt(2)/2]));
+ assert(approx(altaz_to_xyz([-45, 90,100]),[100*sqrt(2)/2,0,-100*sqrt(2)/2]));
}
test_altaz_to_xyz();
module test_xyz_to_altaz() {
- assert(approx(xyz_to_altaz( 0,100, 0),[ 0, 0,100]));
- assert(approx(xyz_to_altaz( 0, 0, 100),[ 90, 0,100]));
- assert(approx(xyz_to_altaz( 0, 0,-100),[-90, 0,100]));
- assert(approx(xyz_to_altaz( 100, 0, 0),[ 0, 90,100]));
- assert(approx(xyz_to_altaz(-100, 0, 0),[ 0,-90,100]));
- assert(approx(xyz_to_altaz(100*sqrt(2)/2,0,100*sqrt(2)/2),[ 45, 90,100]));
- assert(approx(xyz_to_altaz(100*sqrt(2)/2,0,-100*sqrt(2)/2),[-45, 90,100]));
- assert(approx(xyz_to_altaz([ 0,100, 0]),[ 0, 0,100]));
- assert(approx(xyz_to_altaz([ 0, 0, 100]),[ 90, 0,100]));
- assert(approx(xyz_to_altaz([ 0, 0,-100]),[-90, 0,100]));
- assert(approx(xyz_to_altaz([ 100, 0, 0]),[ 0, 90,100]));
- assert(approx(xyz_to_altaz([-100, 0, 0]),[ 0,-90,100]));
- assert(approx(xyz_to_altaz([100*sqrt(2)/2,0,100*sqrt(2)/2]),[ 45, 90,100]));
- assert(approx(xyz_to_altaz([100*sqrt(2)/2,0,-100*sqrt(2)/2]),[-45, 90,100]));
+ assert(approx(xyz_to_altaz( 0,100, 0),[ 0, 0,100]));
+ assert(approx(xyz_to_altaz( 0, 0, 100),[ 90, 0,100]));
+ assert(approx(xyz_to_altaz( 0, 0,-100),[-90, 0,100]));
+ assert(approx(xyz_to_altaz( 100, 0, 0),[ 0, 90,100]));
+ assert(approx(xyz_to_altaz(-100, 0, 0),[ 0,-90,100]));
+ assert(approx(xyz_to_altaz(100*sqrt(2)/2,0,100*sqrt(2)/2),[ 45, 90,100]));
+ assert(approx(xyz_to_altaz(100*sqrt(2)/2,0,-100*sqrt(2)/2),[-45, 90,100]));
+ assert(approx(xyz_to_altaz([ 0,100, 0]),[ 0, 0,100]));
+ assert(approx(xyz_to_altaz([ 0, 0, 100]),[ 90, 0,100]));
+ assert(approx(xyz_to_altaz([ 0, 0,-100]),[-90, 0,100]));
+ assert(approx(xyz_to_altaz([ 100, 0, 0]),[ 0, 90,100]));
+ assert(approx(xyz_to_altaz([-100, 0, 0]),[ 0,-90,100]));
+ assert(approx(xyz_to_altaz([100*sqrt(2)/2,0,100*sqrt(2)/2]),[ 45, 90,100]));
+ assert(approx(xyz_to_altaz([100*sqrt(2)/2,0,-100*sqrt(2)/2]),[-45, 90,100]));
}
test_xyz_to_altaz();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_cubetruss.scad b/tests/test_cubetruss.scad
index fe5095b..9b71f0e 100644
--- a/tests/test_cubetruss.scad
+++ b/tests/test_cubetruss.scad
@@ -3,12 +3,12 @@ include
module test_cubetruss_dist() {
- assert(cubetruss_dist(5,1,size=30,strut=3) == 138);
- assert(cubetruss_dist(3,2,size=30,strut=3) == 87);
- assert(cubetruss_dist(5,1,size=20,strut=2) == 92);
- assert(cubetruss_dist(3,2,size=20,strut=2) == 58);
+ assert(cubetruss_dist(5,1,size=30,strut=3) == 138);
+ assert(cubetruss_dist(3,2,size=30,strut=3) == 87);
+ assert(cubetruss_dist(5,1,size=20,strut=2) == 92);
+ assert(cubetruss_dist(3,2,size=20,strut=2) == 58);
}
test_cubetruss_dist();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_edges.scad b/tests/test_edges.scad
index ba35b27..047c1f9 100644
--- a/tests/test_edges.scad
+++ b/tests/test_edges.scad
@@ -2,103 +2,103 @@ include
module test_is_edge_array() {
- assert(is_edge_array([[0,0,0,0],[0,0,0,0],[0,0,0,0]]));
- assert(is_edge_array([[1,1,1,1],[1,1,1,1],[1,1,1,1]]));
- assert(!is_edge_array([[1,1,1],[1,1,1],[1,1,1]]));
- assert(!is_edge_array([[1,1,1,1,1],[1,1,1,1,1],[1,1,1,1,1]]));
- assert(!is_edge_array([[1,1,1,1],[1,1,1,1]]));
- assert(!is_edge_array([1,1,1,1]));
- assert(!is_edge_array("foo"));
- assert(!is_edge_array(42));
- assert(!is_edge_array(true));
- assert(is_edge_array(edges(["X","Y"])));
+ assert(is_edge_array([[0,0,0,0],[0,0,0,0],[0,0,0,0]]));
+ assert(is_edge_array([[1,1,1,1],[1,1,1,1],[1,1,1,1]]));
+ assert(!is_edge_array([[1,1,1],[1,1,1],[1,1,1]]));
+ assert(!is_edge_array([[1,1,1,1,1],[1,1,1,1,1],[1,1,1,1,1]]));
+ assert(!is_edge_array([[1,1,1,1],[1,1,1,1]]));
+ assert(!is_edge_array([1,1,1,1]));
+ assert(!is_edge_array("foo"));
+ assert(!is_edge_array(42));
+ assert(!is_edge_array(true));
+ assert(is_edge_array(edges(["X","Y"])));
}
test_is_edge_array();
module test__edge_set() {
- // Edge set pass through
- assert(_edge_set([[1,1,1,1],[0,1,0,1],[0,0,0,0]]) == [[1,1,1,1],[0,1,0,1],[0,0,0,0]]);
+ // Edge set pass through
+ assert(_edge_set([[1,1,1,1],[0,1,0,1],[0,0,0,0]]) == [[1,1,1,1],[0,1,0,1],[0,0,0,0]]);
- // Vectors towards corners
- assert(_edge_set([-1,-1,-1]) == [[1,0,0,0],[1,0,0,0],[1,0,0,0]]);
- assert(_edge_set([-1,-1, 1]) == [[0,0,1,0],[0,0,1,0],[1,0,0,0]]);
- assert(_edge_set([-1, 1,-1]) == [[0,1,0,0],[1,0,0,0],[0,0,1,0]]);
- assert(_edge_set([-1, 1, 1]) == [[0,0,0,1],[0,0,1,0],[0,0,1,0]]);
- assert(_edge_set([ 1,-1,-1]) == [[1,0,0,0],[0,1,0,0],[0,1,0,0]]);
- assert(_edge_set([ 1,-1, 1]) == [[0,0,1,0],[0,0,0,1],[0,1,0,0]]);
- assert(_edge_set([ 1, 1,-1]) == [[0,1,0,0],[0,1,0,0],[0,0,0,1]]);
- assert(_edge_set([ 1, 1, 1]) == [[0,0,0,1],[0,0,0,1],[0,0,0,1]]);
+ // Vectors towards corners
+ assert(_edge_set([-1,-1,-1]) == [[1,0,0,0],[1,0,0,0],[1,0,0,0]]);
+ assert(_edge_set([-1,-1, 1]) == [[0,0,1,0],[0,0,1,0],[1,0,0,0]]);
+ assert(_edge_set([-1, 1,-1]) == [[0,1,0,0],[1,0,0,0],[0,0,1,0]]);
+ assert(_edge_set([-1, 1, 1]) == [[0,0,0,1],[0,0,1,0],[0,0,1,0]]);
+ assert(_edge_set([ 1,-1,-1]) == [[1,0,0,0],[0,1,0,0],[0,1,0,0]]);
+ assert(_edge_set([ 1,-1, 1]) == [[0,0,1,0],[0,0,0,1],[0,1,0,0]]);
+ assert(_edge_set([ 1, 1,-1]) == [[0,1,0,0],[0,1,0,0],[0,0,0,1]]);
+ assert(_edge_set([ 1, 1, 1]) == [[0,0,0,1],[0,0,0,1],[0,0,0,1]]);
- // Vectors towards edges
- assert(_edge_set([ 0,-1,-1]) == [[1,0,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set([ 0, 1,-1]) == [[0,1,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set([ 0,-1, 1]) == [[0,0,1,0],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set([ 0, 1, 1]) == [[0,0,0,1],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set([-1, 0,-1]) == [[0,0,0,0],[1,0,0,0],[0,0,0,0]]);
- assert(_edge_set([ 1, 0,-1]) == [[0,0,0,0],[0,1,0,0],[0,0,0,0]]);
- assert(_edge_set([-1, 0, 1]) == [[0,0,0,0],[0,0,1,0],[0,0,0,0]]);
- assert(_edge_set([ 1, 0, 1]) == [[0,0,0,0],[0,0,0,1],[0,0,0,0]]);
- assert(_edge_set([-1,-1, 0]) == [[0,0,0,0],[0,0,0,0],[1,0,0,0]]);
- assert(_edge_set([ 1,-1, 0]) == [[0,0,0,0],[0,0,0,0],[0,1,0,0]]);
- assert(_edge_set([-1, 1, 0]) == [[0,0,0,0],[0,0,0,0],[0,0,1,0]]);
- assert(_edge_set([ 1, 1, 0]) == [[0,0,0,0],[0,0,0,0],[0,0,0,1]]);
+ // Vectors towards edges
+ assert(_edge_set([ 0,-1,-1]) == [[1,0,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set([ 0, 1,-1]) == [[0,1,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set([ 0,-1, 1]) == [[0,0,1,0],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set([ 0, 1, 1]) == [[0,0,0,1],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set([-1, 0,-1]) == [[0,0,0,0],[1,0,0,0],[0,0,0,0]]);
+ assert(_edge_set([ 1, 0,-1]) == [[0,0,0,0],[0,1,0,0],[0,0,0,0]]);
+ assert(_edge_set([-1, 0, 1]) == [[0,0,0,0],[0,0,1,0],[0,0,0,0]]);
+ assert(_edge_set([ 1, 0, 1]) == [[0,0,0,0],[0,0,0,1],[0,0,0,0]]);
+ assert(_edge_set([-1,-1, 0]) == [[0,0,0,0],[0,0,0,0],[1,0,0,0]]);
+ assert(_edge_set([ 1,-1, 0]) == [[0,0,0,0],[0,0,0,0],[0,1,0,0]]);
+ assert(_edge_set([-1, 1, 0]) == [[0,0,0,0],[0,0,0,0],[0,0,1,0]]);
+ assert(_edge_set([ 1, 1, 0]) == [[0,0,0,0],[0,0,0,0],[0,0,0,1]]);
- // Vectors towards faces
- assert(_edge_set([ 0, 0,-1]) == [[1,1,0,0],[1,1,0,0],[0,0,0,0]]);
- assert(_edge_set([ 0, 0, 1]) == [[0,0,1,1],[0,0,1,1],[0,0,0,0]]);
- assert(_edge_set([ 0,-1, 0]) == [[1,0,1,0],[0,0,0,0],[1,1,0,0]]);
- assert(_edge_set([ 0, 1, 0]) == [[0,1,0,1],[0,0,0,0],[0,0,1,1]]);
- assert(_edge_set([-1, 0, 0]) == [[0,0,0,0],[1,0,1,0],[1,0,1,0]]);
- assert(_edge_set([ 1, 0, 0]) == [[0,0,0,0],[0,1,0,1],[0,1,0,1]]);
+ // Vectors towards faces
+ assert(_edge_set([ 0, 0,-1]) == [[1,1,0,0],[1,1,0,0],[0,0,0,0]]);
+ assert(_edge_set([ 0, 0, 1]) == [[0,0,1,1],[0,0,1,1],[0,0,0,0]]);
+ assert(_edge_set([ 0,-1, 0]) == [[1,0,1,0],[0,0,0,0],[1,1,0,0]]);
+ assert(_edge_set([ 0, 1, 0]) == [[0,1,0,1],[0,0,0,0],[0,0,1,1]]);
+ assert(_edge_set([-1, 0, 0]) == [[0,0,0,0],[1,0,1,0],[1,0,1,0]]);
+ assert(_edge_set([ 1, 0, 0]) == [[0,0,0,0],[0,1,0,1],[0,1,0,1]]);
- // Named edge sets
- assert(_edge_set("X") == [[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set("Y") == [[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
- assert(_edge_set("Z") == [[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
- assert(_edge_set("NONE") == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(_edge_set("ALL") == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
+ // Named edge sets
+ assert(_edge_set("X") == [[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set("Y") == [[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
+ assert(_edge_set("Z") == [[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
+ assert(_edge_set("NONE") == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(_edge_set("ALL") == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
}
test__edge_set();
module test_normalize_edges() {
- assert(normalize_edges([[-2,-2,-2,-2],[-2,-2,-2,-2],[-2,-2,-2,-2]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(normalize_edges([[-1,-1,-1,-1],[-1,-1,-1,-1],[-1,-1,-1,-1]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(normalize_edges([[0,0,0,0],[0,0,0,0],[0,0,0,0]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
- assert(normalize_edges([[1,1,1,1],[1,1,1,1],[1,1,1,1]]) == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
- assert(normalize_edges([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
+ assert(normalize_edges([[-2,-2,-2,-2],[-2,-2,-2,-2],[-2,-2,-2,-2]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(normalize_edges([[-1,-1,-1,-1],[-1,-1,-1,-1],[-1,-1,-1,-1]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(normalize_edges([[0,0,0,0],[0,0,0,0],[0,0,0,0]]) == [[0,0,0,0],[0,0,0,0],[0,0,0,0]]);
+ assert(normalize_edges([[1,1,1,1],[1,1,1,1],[1,1,1,1]]) == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
+ assert(normalize_edges([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) == [[1,1,1,1],[1,1,1,1],[1,1,1,1]]);
}
test_normalize_edges();
module test_edges() {
- assert(edges("X")==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
- assert(edges("Y")==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
- assert(edges("Z")==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
- assert(edges(["X"])==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
- assert(edges(["Y"])==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
- assert(edges(["Z"])==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
- assert(edges(["X","Y"])==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
- assert(edges(["X","Z"])==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
- assert(edges(["Y","Z"])==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
- assert(edges("ALL",except="X")==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
- assert(edges("ALL",except="Y")==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
- assert(edges("ALL",except="Z")==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
- assert(edges(["Y","Z"],except=[FRONT+RIGHT,FRONT+LEFT])==[[0,0,0,0],[1,1,1,1],[0,0,1,1]]);
+ assert(edges("X")==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
+ assert(edges("Y")==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
+ assert(edges("Z")==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
+ assert(edges(["X"])==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
+ assert(edges(["Y"])==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
+ assert(edges(["Z"])==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
+ assert(edges(["X","Y"])==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
+ assert(edges(["X","Z"])==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
+ assert(edges(["Y","Z"])==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
+ assert(edges("ALL",except="X")==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
+ assert(edges("ALL",except="Y")==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
+ assert(edges("ALL",except="Z")==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
+ assert(edges(["Y","Z"],except=[FRONT+RIGHT,FRONT+LEFT])==[[0,0,0,0],[1,1,1,1],[0,0,1,1]]);
}
test_edges();
module test_corner_edge_count() {
- edges = edges([TOP,FRONT+RIGHT]);
- assert(corner_edge_count(edges,TOP+FRONT+RIGHT) == 3);
- assert(corner_edge_count(edges,TOP+FRONT+LEFT) == 2);
- assert(corner_edge_count(edges,BOTTOM+FRONT+RIGHT) == 1);
- assert(corner_edge_count(edges,BOTTOM+FRONT+LEFT) == 0);
+ edges = edges([TOP,FRONT+RIGHT]);
+ assert(corner_edge_count(edges,TOP+FRONT+RIGHT) == 3);
+ assert(corner_edge_count(edges,TOP+FRONT+LEFT) == 2);
+ assert(corner_edge_count(edges,BOTTOM+FRONT+RIGHT) == 1);
+ assert(corner_edge_count(edges,BOTTOM+FRONT+LEFT) == 0);
}
test_corner_edge_count();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_errors.scad b/tests/test_errors.scad
index aa52225..ba82755 100644
--- a/tests/test_errors.scad
+++ b/tests/test_errors.scad
@@ -8,4 +8,4 @@ module test_deprecate() {}
module test_deprecate_argument() {}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad
index ce69361..e5d1f5b 100644
--- a/tests/test_geometry.scad
+++ b/tests/test_geometry.scad
@@ -2,330 +2,330 @@ include
module test_point_on_segment2d() {
- assert(point_on_segment2d([-15,0], [[-10,0], [10,0]]) == false);
- assert(point_on_segment2d([-10,0], [[-10,0], [10,0]]) == true);
- assert(point_on_segment2d([-5,0], [[-10,0], [10,0]]) == true);
- assert(point_on_segment2d([0,0], [[-10,0], [10,0]]) == true);
- assert(point_on_segment2d([3,3], [[-10,0], [10,0]]) == false);
- assert(point_on_segment2d([5,0], [[-10,0], [10,0]]) == true);
- assert(point_on_segment2d([10,0], [[-10,0], [10,0]]) == true);
- assert(point_on_segment2d([15,0], [[-10,0], [10,0]]) == false);
+ assert(point_on_segment2d([-15,0], [[-10,0], [10,0]]) == false);
+ assert(point_on_segment2d([-10,0], [[-10,0], [10,0]]) == true);
+ assert(point_on_segment2d([-5,0], [[-10,0], [10,0]]) == true);
+ assert(point_on_segment2d([0,0], [[-10,0], [10,0]]) == true);
+ assert(point_on_segment2d([3,3], [[-10,0], [10,0]]) == false);
+ assert(point_on_segment2d([5,0], [[-10,0], [10,0]]) == true);
+ assert(point_on_segment2d([10,0], [[-10,0], [10,0]]) == true);
+ assert(point_on_segment2d([15,0], [[-10,0], [10,0]]) == false);
- assert(point_on_segment2d([0,-15], [[0,-10], [0,10]]) == false);
- assert(point_on_segment2d([0,-10], [[0,-10], [0,10]]) == true);
- assert(point_on_segment2d([0, -5], [[0,-10], [0,10]]) == true);
- assert(point_on_segment2d([0, 0], [[0,-10], [0,10]]) == true);
- assert(point_on_segment2d([3, 3], [[0,-10], [0,10]]) == false);
- assert(point_on_segment2d([0, 5], [[0,-10], [0,10]]) == true);
- assert(point_on_segment2d([0, 10], [[0,-10], [0,10]]) == true);
- assert(point_on_segment2d([0, 15], [[0,-10], [0,10]]) == false);
+ assert(point_on_segment2d([0,-15], [[0,-10], [0,10]]) == false);
+ assert(point_on_segment2d([0,-10], [[0,-10], [0,10]]) == true);
+ assert(point_on_segment2d([0, -5], [[0,-10], [0,10]]) == true);
+ assert(point_on_segment2d([0, 0], [[0,-10], [0,10]]) == true);
+ assert(point_on_segment2d([3, 3], [[0,-10], [0,10]]) == false);
+ assert(point_on_segment2d([0, 5], [[0,-10], [0,10]]) == true);
+ assert(point_on_segment2d([0, 10], [[0,-10], [0,10]]) == true);
+ assert(point_on_segment2d([0, 15], [[0,-10], [0,10]]) == false);
- assert(point_on_segment2d([-15,-15], [[-10,-10], [10,10]]) == false);
- assert(point_on_segment2d([-10,-10], [[-10,-10], [10,10]]) == true);
- assert(point_on_segment2d([ -5, -5], [[-10,-10], [10,10]]) == true);
- assert(point_on_segment2d([ 0, 0], [[-10,-10], [10,10]]) == true);
- assert(point_on_segment2d([ 0, 3], [[-10,-10], [10,10]]) == false);
- assert(point_on_segment2d([ 5, 5], [[-10,-10], [10,10]]) == true);
- assert(point_on_segment2d([ 10, 10], [[-10,-10], [10,10]]) == true);
- assert(point_on_segment2d([ 15, 15], [[-10,-10], [10,10]]) == false);
+ assert(point_on_segment2d([-15,-15], [[-10,-10], [10,10]]) == false);
+ assert(point_on_segment2d([-10,-10], [[-10,-10], [10,10]]) == true);
+ assert(point_on_segment2d([ -5, -5], [[-10,-10], [10,10]]) == true);
+ assert(point_on_segment2d([ 0, 0], [[-10,-10], [10,10]]) == true);
+ assert(point_on_segment2d([ 0, 3], [[-10,-10], [10,10]]) == false);
+ assert(point_on_segment2d([ 5, 5], [[-10,-10], [10,10]]) == true);
+ assert(point_on_segment2d([ 10, 10], [[-10,-10], [10,10]]) == true);
+ assert(point_on_segment2d([ 15, 15], [[-10,-10], [10,10]]) == false);
}
test_point_on_segment2d();
module test_point_left_of_segment() {
- assert(point_left_of_segment2d([ -3, 0], [[-10,-10], [10,10]]) > 0);
- assert(point_left_of_segment2d([ 0, 0], [[-10,-10], [10,10]]) == 0);
- assert(point_left_of_segment2d([ 3, 0], [[-10,-10], [10,10]]) < 0);
+ assert(point_left_of_segment2d([ -3, 0], [[-10,-10], [10,10]]) > 0);
+ assert(point_left_of_segment2d([ 0, 0], [[-10,-10], [10,10]]) == 0);
+ assert(point_left_of_segment2d([ 3, 0], [[-10,-10], [10,10]]) < 0);
}
test_point_left_of_segment();
module test_collinear() {
- assert(collinear([-10,-10], [-15, -16], [10,10]) == false);
- assert(collinear([-10,-10], [-15, -15], [10,10]) == true);
- assert(collinear([-10,-10], [ -3, 0], [10,10]) == false);
- assert(collinear([-10,-10], [ 0, 0], [10,10]) == true);
- assert(collinear([-10,-10], [ 3, 0], [10,10]) == false);
- assert(collinear([-10,-10], [ 15, 15], [10,10]) == true);
- assert(collinear([-10,-10], [ 15, 16], [10,10]) == false);
+ assert(collinear([-10,-10], [-15, -16], [10,10]) == false);
+ assert(collinear([-10,-10], [-15, -15], [10,10]) == true);
+ assert(collinear([-10,-10], [ -3, 0], [10,10]) == false);
+ assert(collinear([-10,-10], [ 0, 0], [10,10]) == true);
+ assert(collinear([-10,-10], [ 3, 0], [10,10]) == false);
+ assert(collinear([-10,-10], [ 15, 15], [10,10]) == true);
+ assert(collinear([-10,-10], [ 15, 16], [10,10]) == false);
}
test_collinear();
module test_collinear_indexed() {
- pts = [
- [-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]
- ];
- assert(collinear_indexed(pts, 0,1,2) == false);
- assert(collinear_indexed(pts, 1,2,3) == true);
- assert(collinear_indexed(pts, 2,3,4) == true);
- assert(collinear_indexed(pts, 3,4,5) == false);
- assert(collinear_indexed(pts, 4,5,6) == false);
- assert(collinear_indexed(pts, 4,3,2) == true);
- assert(collinear_indexed(pts, 0,5,6) == false);
+ pts = [
+ [-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]
+ ];
+ assert(collinear_indexed(pts, 0,1,2) == false);
+ assert(collinear_indexed(pts, 1,2,3) == true);
+ assert(collinear_indexed(pts, 2,3,4) == true);
+ assert(collinear_indexed(pts, 3,4,5) == false);
+ assert(collinear_indexed(pts, 4,5,6) == false);
+ assert(collinear_indexed(pts, 4,3,2) == true);
+ assert(collinear_indexed(pts, 0,5,6) == false);
}
test_collinear_indexed();
module test_distance_from_line() {
- assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,1,1])) < EPSILON);
- assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [-1,-1,-1])) < EPSILON);
- assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,-1,0]) - sqrt(2)) < EPSILON);
- assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [8,-8,0]) - 8*sqrt(2)) < EPSILON);
+ assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,1,1])) < EPSILON);
+ assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [-1,-1,-1])) < EPSILON);
+ assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,-1,0]) - sqrt(2)) < EPSILON);
+ assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [8,-8,0]) - 8*sqrt(2)) < EPSILON);
}
test_distance_from_line();
module test_line_normal() {
- assert(line_normal([0,0],[10,0]) == [0,1]);
- assert(line_normal([0,0],[0,10]) == [-1,0]);
- 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]));
- assert(line_normal([[0,0],[10,0]]) == [0,1]);
- assert(line_normal([[0,0],[0,10]]) == [-1,0]);
- 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)];
- for (p = pair_wrap(pts)) {
- p1 = p.x;
- p2 = p.y;
- n = unit(p2-p1);
- n1 = [-n.y, n.x];
- n2 = line_normal(p1,p2);
- assert(approx(n2, n1));
- }
+ assert(line_normal([0,0],[10,0]) == [0,1]);
+ assert(line_normal([0,0],[0,10]) == [-1,0]);
+ 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]));
+ assert(line_normal([[0,0],[10,0]]) == [0,1]);
+ assert(line_normal([[0,0],[0,10]]) == [-1,0]);
+ 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)];
+ for (p = pair_wrap(pts)) {
+ p1 = p.x;
+ p2 = p.y;
+ n = unit(p2-p1);
+ n1 = [-n.y, n.x];
+ n2 = line_normal(p1,p2);
+ assert(approx(n2, n1));
+ }
}
test_line_normal();
module test_line_intersection() {
- assert(line_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
- assert(line_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
- assert(line_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
- assert(line_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
- assert(line_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
- assert(line_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == [0,0]);
- assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
- assert(line_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
+ assert(line_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
+ assert(line_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
+ assert(line_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
+ assert(line_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
+ assert(line_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
+ assert(line_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == [0,0]);
+ assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
+ assert(line_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
}
test_line_intersection();
module test_segment_intersection() {
- assert(segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
- assert(segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
- assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
- assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
- assert(segment_intersection([[-10, 10], [ -1, 1]], [[ 10, 10], [ 1, 1]]) == undef);
- assert(segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
- assert(segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
- assert(segment_intersection([[-10, 0], [ 0, 10]], [[ 0, 10], [ 10, 0]]) == [0,10]);
- assert(segment_intersection([[-10, 0], [ 0, 10]], [[-10, 20], [ 10, 0]]) == [0,10]);
- assert(segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
- assert(segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
+ assert(segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
+ assert(segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
+ assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
+ assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
+ assert(segment_intersection([[-10, 10], [ -1, 1]], [[ 10, 10], [ 1, 1]]) == undef);
+ assert(segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
+ assert(segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
+ assert(segment_intersection([[-10, 0], [ 0, 10]], [[ 0, 10], [ 10, 0]]) == [0,10]);
+ assert(segment_intersection([[-10, 0], [ 0, 10]], [[-10, 20], [ 10, 0]]) == [0,10]);
+ assert(segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
+ assert(segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
}
test_segment_intersection();
module test_line_segment_intersection() {
- assert(line_segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
- assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
- assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
- assert(line_segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
- assert(line_segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
- assert(line_segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
- assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
- assert(line_segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
- assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ 1, -1]]) == undef);
- assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ -1, 1]]) == [0,0]);
+ assert(line_segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
+ assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
+ assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
+ assert(line_segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
+ assert(line_segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
+ assert(line_segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
+ assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
+ assert(line_segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
+ assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ 1, -1]]) == undef);
+ assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ -1, 1]]) == [0,0]);
}
test_line_segment_intersection();
module test_line_closest_point() {
- assert(approx(line_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
- assert(approx(line_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
- assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
- assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
- assert(approx(line_closest_point([[-10,-20], [10,20]], [13,31]), [15,30]));
+ assert(approx(line_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
+ assert(approx(line_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
+ assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
+ assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
+ assert(approx(line_closest_point([[-10,-20], [10,20]], [13,31]), [15,30]));
}
test_line_closest_point();
module test_segment_closest_point() {
- assert(approx(segment_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
- assert(approx(segment_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
- assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
- assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
- assert(approx(segment_closest_point([[-10,-20], [10,20]], [13,31]), [10,20]));
- assert(approx(segment_closest_point([[-10,-20], [10,20]], [15,25]), [10,20]));
+ assert(approx(segment_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
+ assert(approx(segment_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
+ assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
+ assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
+ assert(approx(segment_closest_point([[-10,-20], [10,20]], [13,31]), [10,20]));
+ assert(approx(segment_closest_point([[-10,-20], [10,20]], [15,25]), [10,20]));
}
test_segment_closest_point();
module test_find_circle_2tangents() {
- assert(approx(find_circle_2tangents([10,10],[0,0],[10,-10],r=10/sqrt(2))[0],[10,0]));
- assert(approx(find_circle_2tangents([-10,10],[0,0],[-10,-10],r=10/sqrt(2))[0],[-10,0]));
- assert(approx(find_circle_2tangents([-10,10],[0,0],[10,10],r=10/sqrt(2))[0],[0,10]));
- assert(approx(find_circle_2tangents([-10,-10],[0,0],[10,-10],r=10/sqrt(2))[0],[0,-10]));
- assert(approx(find_circle_2tangents([0,10],[0,0],[10,0],r=10)[0],[10,10]));
- assert(approx(find_circle_2tangents([10,0],[0,0],[0,-10],r=10)[0],[10,-10]));
- assert(approx(find_circle_2tangents([0,-10],[0,0],[-10,0],r=10)[0],[-10,-10]));
- assert(approx(find_circle_2tangents([-10,0],[0,0],[0,10],r=10)[0],[-10,10]));
- assert(approx(find_circle_2tangents(polar_to_xy(10,60),[0,0],[10,0],r=10)[0],polar_to_xy(20,30)));
+ assert(approx(find_circle_2tangents([10,10],[0,0],[10,-10],r=10/sqrt(2))[0],[10,0]));
+ assert(approx(find_circle_2tangents([-10,10],[0,0],[-10,-10],r=10/sqrt(2))[0],[-10,0]));
+ assert(approx(find_circle_2tangents([-10,10],[0,0],[10,10],r=10/sqrt(2))[0],[0,10]));
+ assert(approx(find_circle_2tangents([-10,-10],[0,0],[10,-10],r=10/sqrt(2))[0],[0,-10]));
+ assert(approx(find_circle_2tangents([0,10],[0,0],[10,0],r=10)[0],[10,10]));
+ assert(approx(find_circle_2tangents([10,0],[0,0],[0,-10],r=10)[0],[10,-10]));
+ assert(approx(find_circle_2tangents([0,-10],[0,0],[-10,0],r=10)[0],[-10,-10]));
+ assert(approx(find_circle_2tangents([-10,0],[0,0],[0,10],r=10)[0],[-10,10]));
+ assert(approx(find_circle_2tangents(polar_to_xy(10,60),[0,0],[10,0],r=10)[0],polar_to_xy(20,30)));
}
test_find_circle_2tangents();
module test_find_circle_3points() {
- count = 200;
- coords = rands(-100,100,count,seed_value=888);
- radii = rands(10,100,count,seed_value=390);
- angles = rands(0,360,count,seed_value=699);
- // 2D tests.
- for(i = list_range(count)) {
- cp = select(coords,i,i+1);
- r = radii[i];
- angs = sort(select(angles,i,i+2));
- pts = [for (a=angs) cp+polar_to_xy(r,a)];
- res = find_circle_3points(pts);
- if (!approx(res[0], cp)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[0], expected=cp, delta=res[0]-cp);
- assert(approx(res[0], cp));
- }
- if (!approx(res[1], r)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[1], expected=r, delta=res[1]-r);
- assert(approx(res[1], r));
- }
- if (!approx(res[2], UP)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[2], expected=UP, delta=res[2]-UP);
- assert(approx(res[2], UP));
- }
- }
- for(i = list_range(count)) {
- cp = select(coords,i,i+1);
- r = radii[i];
- angs = sort(select(angles,i,i+2));
- pts = [for (a=angs) cp+polar_to_xy(r,a)];
- res = find_circle_3points(pts[0], pts[1], pts[2]);
- if (!approx(res[0], cp)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[0], expected=cp, delta=res[0]-cp);
- assert(approx(res[0], cp));
- }
- if (!approx(res[1], r)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[1], expected=r, delta=res[1]-r);
- assert(approx(res[1], r));
- }
- if (!approx(res[2], UP)) {
- echo(cp=cp, r=r, angs=angs);
- echo(pts=pts);
- echo(got=res[2], expected=UP, delta=res[2]-UP);
- assert(approx(res[2], UP));
- }
- }
- // 3D tests.
- for(i = list_range(count)) {
- cp = select(coords,i,i+2);
- r = radii[i];
- nrm = unit(select(coords,i+10,i+12));
- n = nrm.z<0? -nrm : nrm;
- angs = sort(select(angles,i,i+2));
- pts = translate(cp,p=rot(from=UP,to=n,p=[for (a=angs) point3d(polar_to_xy(r,a))]));
- res = find_circle_3points(pts);
- if (!approx(res[0], cp)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("CP:", got=res[0], expected=cp, delta=res[0]-cp);
- assert(approx(res[0], cp));
- }
- if (!approx(res[1], r)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("R:", got=res[1], expected=r, delta=res[1]-r);
- assert(approx(res[1], r));
- }
- if (!approx(res[2], n)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("NORMAL:", got=res[2], expected=n, delta=res[2]-n);
- assert(approx(res[2], n));
- }
- }
- for(i = list_range(count)) {
- cp = select(coords,i,i+2);
- r = radii[i];
- nrm = unit(select(coords,i+10,i+12));
- n = nrm.z<0? -nrm : nrm;
- angs = sort(select(angles,i,i+2));
- pts = translate(cp,p=rot(from=UP,to=n,p=[for (a=angs) point3d(polar_to_xy(r,a))]));
- res = find_circle_3points(pts[0], pts[1], pts[2]);
- if (!approx(res[0], cp)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("CENTER:", got=res[0], expected=cp, delta=res[0]-cp);
- assert(approx(res[0], cp));
- }
- if (!approx(res[1], r)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("RADIUS:", got=res[1], expected=r, delta=res[1]-r);
- assert(approx(res[1], r));
- }
- if (!approx(res[2], n)) {
- echo(cp=cp, r=r, angs=angs, n=n);
- echo(pts=pts);
- echo("NORMAL:", got=res[2], expected=n, delta=res[2]-n);
- assert(approx(res[2], n));
- }
- }
+ count = 200;
+ coords = rands(-100,100,count,seed_value=888);
+ radii = rands(10,100,count,seed_value=390);
+ angles = rands(0,360,count,seed_value=699);
+ // 2D tests.
+ for(i = list_range(count)) {
+ cp = select(coords,i,i+1);
+ r = radii[i];
+ angs = sort(select(angles,i,i+2));
+ pts = [for (a=angs) cp+polar_to_xy(r,a)];
+ res = find_circle_3points(pts);
+ if (!approx(res[0], cp)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[0], expected=cp, delta=res[0]-cp);
+ assert(approx(res[0], cp));
+ }
+ if (!approx(res[1], r)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[1], expected=r, delta=res[1]-r);
+ assert(approx(res[1], r));
+ }
+ if (!approx(res[2], UP)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[2], expected=UP, delta=res[2]-UP);
+ assert(approx(res[2], UP));
+ }
+ }
+ for(i = list_range(count)) {
+ cp = select(coords,i,i+1);
+ r = radii[i];
+ angs = sort(select(angles,i,i+2));
+ pts = [for (a=angs) cp+polar_to_xy(r,a)];
+ res = find_circle_3points(pts[0], pts[1], pts[2]);
+ if (!approx(res[0], cp)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[0], expected=cp, delta=res[0]-cp);
+ assert(approx(res[0], cp));
+ }
+ if (!approx(res[1], r)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[1], expected=r, delta=res[1]-r);
+ assert(approx(res[1], r));
+ }
+ if (!approx(res[2], UP)) {
+ echo(cp=cp, r=r, angs=angs);
+ echo(pts=pts);
+ echo(got=res[2], expected=UP, delta=res[2]-UP);
+ assert(approx(res[2], UP));
+ }
+ }
+ // 3D tests.
+ for(i = list_range(count)) {
+ cp = select(coords,i,i+2);
+ r = radii[i];
+ nrm = unit(select(coords,i+10,i+12));
+ n = nrm.z<0? -nrm : nrm;
+ angs = sort(select(angles,i,i+2));
+ pts = translate(cp,p=rot(from=UP,to=n,p=[for (a=angs) point3d(polar_to_xy(r,a))]));
+ res = find_circle_3points(pts);
+ if (!approx(res[0], cp)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("CP:", got=res[0], expected=cp, delta=res[0]-cp);
+ assert(approx(res[0], cp));
+ }
+ if (!approx(res[1], r)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("R:", got=res[1], expected=r, delta=res[1]-r);
+ assert(approx(res[1], r));
+ }
+ if (!approx(res[2], n)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("NORMAL:", got=res[2], expected=n, delta=res[2]-n);
+ assert(approx(res[2], n));
+ }
+ }
+ for(i = list_range(count)) {
+ cp = select(coords,i,i+2);
+ r = radii[i];
+ nrm = unit(select(coords,i+10,i+12));
+ n = nrm.z<0? -nrm : nrm;
+ angs = sort(select(angles,i,i+2));
+ pts = translate(cp,p=rot(from=UP,to=n,p=[for (a=angs) point3d(polar_to_xy(r,a))]));
+ res = find_circle_3points(pts[0], pts[1], pts[2]);
+ if (!approx(res[0], cp)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("CENTER:", got=res[0], expected=cp, delta=res[0]-cp);
+ assert(approx(res[0], cp));
+ }
+ if (!approx(res[1], r)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("RADIUS:", got=res[1], expected=r, delta=res[1]-r);
+ assert(approx(res[1], r));
+ }
+ if (!approx(res[2], n)) {
+ echo(cp=cp, r=r, angs=angs, n=n);
+ echo(pts=pts);
+ echo("NORMAL:", got=res[2], expected=n, delta=res[2]-n);
+ assert(approx(res[2], n));
+ }
+ }
}
test_find_circle_3points();
module test_circle_point_tangents() {
- tangs = circle_point_tangents(r=50,cp=[0,0],pt=[50*sqrt(2),0]);
- assert(approx(subindex(tangs,0), [45,-45]));
- expected = [for (ang=subindex(tangs,0)) polar_to_xy(50,ang)];
- got = subindex(tangs,1);
- if (!approx(flatten(got), flatten(expected))) {
- echo("TAN_PTS:", got=got, expected=expected, delta=got-expected);
- assert(approx(flatten(got), flatten(expected)));
- }
+ tangs = circle_point_tangents(r=50,cp=[0,0],pt=[50*sqrt(2),0]);
+ assert(approx(subindex(tangs,0), [45,-45]));
+ expected = [for (ang=subindex(tangs,0)) polar_to_xy(50,ang)];
+ got = subindex(tangs,1);
+ if (!approx(flatten(got), flatten(expected))) {
+ echo("TAN_PTS:", got=got, expected=expected, delta=got-expected);
+ assert(approx(flatten(got), flatten(expected)));
+ }
}
test_circle_point_tangents();
module test_tri_calc() {
- sides = rands(1,100,100,seed_value=8888);
- for (p=pair_wrap(sides)) {
- opp = p[0];
- adj = p[1];
- hyp = norm([opp,adj]);
- ang = acos(adj/hyp);
- ang2 = 90-ang;
- expected = [adj, opp, hyp, ang, ang2];
- assert(approx(tri_calc(adj=adj, hyp=hyp), expected));
- assert(approx(tri_calc(opp=opp, hyp=hyp), expected));
- assert(approx(tri_calc(adj=adj, opp=opp), expected));
- assert(approx(tri_calc(adj=adj, ang=ang), expected));
- assert(approx(tri_calc(opp=opp, ang=ang), expected, eps=1e-8));
- assert(approx(tri_calc(hyp=hyp, ang=ang), expected));
- assert(approx(tri_calc(adj=adj, ang2=ang2), expected));
- assert(approx(tri_calc(opp=opp, ang2=ang2), expected, eps=1e-8));
- assert(approx(tri_calc(hyp=hyp, ang2=ang2), expected));
- }
+ sides = rands(1,100,100,seed_value=8888);
+ for (p=pair_wrap(sides)) {
+ opp = p[0];
+ adj = p[1];
+ hyp = norm([opp,adj]);
+ ang = acos(adj/hyp);
+ ang2 = 90-ang;
+ expected = [adj, opp, hyp, ang, ang2];
+ assert(approx(tri_calc(adj=adj, hyp=hyp), expected));
+ assert(approx(tri_calc(opp=opp, hyp=hyp), expected));
+ assert(approx(tri_calc(adj=adj, opp=opp), expected));
+ assert(approx(tri_calc(adj=adj, ang=ang), expected));
+ assert(approx(tri_calc(opp=opp, ang=ang), expected, eps=1e-8));
+ assert(approx(tri_calc(hyp=hyp, ang=ang), expected));
+ assert(approx(tri_calc(adj=adj, ang2=ang2), expected));
+ assert(approx(tri_calc(opp=opp, ang2=ang2), expected, eps=1e-8));
+ assert(approx(tri_calc(hyp=hyp, ang2=ang2), expected));
+ }
}
test_tri_calc();
@@ -345,151 +345,151 @@ module test_hyp_opp_to_ang();
module test_adj_opp_to_ang();
module test_tri_functions() {
- sides = rands(1,100,100,seed_value=8181);
- for (p = pair_wrap(sides)) {
- adj = p.x;
- 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));
- }
+ sides = rands(1,100,100,seed_value=8181);
+ for (p = pair_wrap(sides)) {
+ adj = p.x;
+ 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));
+ }
}
test_tri_functions();
module test_triangle_area() {
- assert(abs(triangle_area([0,0], [0,10], [10,0]) + 50) < EPSILON);
- assert(abs(triangle_area([0,0], [0,10], [0,15])) < EPSILON);
- assert(abs(triangle_area([0,0], [10,0], [0,10]) - 50) < EPSILON);
+ assert(abs(triangle_area([0,0], [0,10], [10,0]) + 50) < EPSILON);
+ assert(abs(triangle_area([0,0], [0,10], [0,15])) < EPSILON);
+ assert(abs(triangle_area([0,0], [10,0], [0,10]) - 50) < EPSILON);
}
test_triangle_area();
module test_plane3pt() {
- assert(plane3pt([0,0,20], [0,10,10], [0,0,0]) == [1,0,0,0]);
- assert(plane3pt([2,0,20], [2,10,10], [2,0,0]) == [1,0,0,2]);
- assert(plane3pt([0,0,0], [10,0,10], [0,0,20]) == [0,1,0,0]);
- assert(plane3pt([0,2,0], [10,2,10], [0,2,20]) == [0,1,0,2]);
- assert(plane3pt([0,0,0], [10,10,0], [20,0,0]) == [0,0,1,0]);
- assert(plane3pt([0,0,2], [10,10,2], [20,0,2]) == [0,0,1,2]);
+ assert(plane3pt([0,0,20], [0,10,10], [0,0,0]) == [1,0,0,0]);
+ assert(plane3pt([2,0,20], [2,10,10], [2,0,0]) == [1,0,0,2]);
+ assert(plane3pt([0,0,0], [10,0,10], [0,0,20]) == [0,1,0,0]);
+ assert(plane3pt([0,2,0], [10,2,10], [0,2,20]) == [0,1,0,2]);
+ assert(plane3pt([0,0,0], [10,10,0], [20,0,0]) == [0,0,1,0]);
+ assert(plane3pt([0,0,2], [10,10,2], [20,0,2]) == [0,0,1,2]);
}
test_plane3pt();
module test_plane3pt_indexed() {
- pts = [ [0,0,0], [10,0,0], [0,10,0], [0,0,10] ];
- s13 = sqrt(1/3);
- assert(plane3pt_indexed(pts, 0,3,2) == [1,0,0,0]);
- assert(plane3pt_indexed(pts, 0,2,3) == [-1,0,0,0]);
- assert(plane3pt_indexed(pts, 0,1,3) == [0,1,0,0]);
- assert(plane3pt_indexed(pts, 0,3,1) == [0,-1,0,0]);
- assert(plane3pt_indexed(pts, 0,2,1) == [0,0,1,0]);
- assert(plane3pt_indexed(pts, 0,1,2) == [0,0,-1,0]);
- assert(plane3pt_indexed(pts, 3,2,1) == [s13,s13,s13,10*s13]);
- assert(plane3pt_indexed(pts, 1,2,3) == [-s13,-s13,-s13,-10*s13]);
+ pts = [ [0,0,0], [10,0,0], [0,10,0], [0,0,10] ];
+ s13 = sqrt(1/3);
+ assert(plane3pt_indexed(pts, 0,3,2) == [1,0,0,0]);
+ assert(plane3pt_indexed(pts, 0,2,3) == [-1,0,0,0]);
+ assert(plane3pt_indexed(pts, 0,1,3) == [0,1,0,0]);
+ assert(plane3pt_indexed(pts, 0,3,1) == [0,-1,0,0]);
+ assert(plane3pt_indexed(pts, 0,2,1) == [0,0,1,0]);
+ assert(plane3pt_indexed(pts, 0,1,2) == [0,0,-1,0]);
+ assert(plane3pt_indexed(pts, 3,2,1) == [s13,s13,s13,10*s13]);
+ assert(plane3pt_indexed(pts, 1,2,3) == [-s13,-s13,-s13,-10*s13]);
}
test_plane3pt_indexed();
module test_plane_from_points() {
- assert(plane_from_points([[0,0,20], [0,10,10], [0,0,0], [0,5,3]]) == [1,0,0,0]);
- assert(plane_from_points([[2,0,20], [2,10,10], [2,0,0], [2,3,4]]) == [1,0,0,2]);
- assert(plane_from_points([[0,0,0], [10,0,10], [0,0,20], [5,0,7]]) == [0,1,0,0]);
- assert(plane_from_points([[0,2,0], [10,2,10], [0,2,20], [4,2,3]]) == [0,1,0,2]);
- assert(plane_from_points([[0,0,0], [10,10,0], [20,0,0], [8,3,0]]) == [0,0,1,0]);
- assert(plane_from_points([[0,0,2], [10,10,2], [20,0,2], [3,4,2]]) == [0,0,1,2]);
+ assert(plane_from_points([[0,0,20], [0,10,10], [0,0,0], [0,5,3]]) == [1,0,0,0]);
+ assert(plane_from_points([[2,0,20], [2,10,10], [2,0,0], [2,3,4]]) == [1,0,0,2]);
+ assert(plane_from_points([[0,0,0], [10,0,10], [0,0,20], [5,0,7]]) == [0,1,0,0]);
+ assert(plane_from_points([[0,2,0], [10,2,10], [0,2,20], [4,2,3]]) == [0,1,0,2]);
+ assert(plane_from_points([[0,0,0], [10,10,0], [20,0,0], [8,3,0]]) == [0,0,1,0]);
+ assert(plane_from_points([[0,0,2], [10,10,2], [20,0,2], [3,4,2]]) == [0,0,1,2]);
}
test_plane_from_points();
module test_plane_normal() {
- assert(plane_normal(plane3pt([0,0,20], [0,10,10], [0,0,0])) == [1,0,0]);
- assert(plane_normal(plane3pt([2,0,20], [2,10,10], [2,0,0])) == [1,0,0]);
- assert(plane_normal(plane3pt([0,0,0], [10,0,10], [0,0,20])) == [0,1,0]);
- assert(plane_normal(plane3pt([0,2,0], [10,2,10], [0,2,20])) == [0,1,0]);
- assert(plane_normal(plane3pt([0,0,0], [10,10,0], [20,0,0])) == [0,0,1]);
- assert(plane_normal(plane3pt([0,0,2], [10,10,2], [20,0,2])) == [0,0,1]);
+ assert(plane_normal(plane3pt([0,0,20], [0,10,10], [0,0,0])) == [1,0,0]);
+ assert(plane_normal(plane3pt([2,0,20], [2,10,10], [2,0,0])) == [1,0,0]);
+ assert(plane_normal(plane3pt([0,0,0], [10,0,10], [0,0,20])) == [0,1,0]);
+ assert(plane_normal(plane3pt([0,2,0], [10,2,10], [0,2,20])) == [0,1,0]);
+ assert(plane_normal(plane3pt([0,0,0], [10,10,0], [20,0,0])) == [0,0,1]);
+ assert(plane_normal(plane3pt([0,0,2], [10,10,2], [20,0,2])) == [0,0,1]);
}
test_plane_normal();
module test_distance_from_plane() {
- plane1 = plane3pt([-10,0,0], [0,10,0], [10,0,0]);
- assert(distance_from_plane(plane1, [0,0,5]) == 5);
- assert(distance_from_plane(plane1, [5,5,8]) == 8);
+ plane1 = plane3pt([-10,0,0], [0,10,0], [10,0,0]);
+ assert(distance_from_plane(plane1, [0,0,5]) == 5);
+ assert(distance_from_plane(plane1, [5,5,8]) == 8);
}
test_distance_from_plane();
module test_coplanar() {
- plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
- assert(coplanar(plane, [5,5,10]) == true);
- assert(coplanar(plane, [10/3,10/3,20/3]) == true);
- assert(coplanar(plane, [0,0,0]) == true);
- assert(coplanar(plane, [1,1,0]) == false);
- assert(coplanar(plane, [-1,1,0]) == true);
- assert(coplanar(plane, [1,-1,0]) == true);
- assert(coplanar(plane, [5,5,5]) == false);
+ plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
+ assert(coplanar(plane, [5,5,10]) == true);
+ assert(coplanar(plane, [10/3,10/3,20/3]) == true);
+ assert(coplanar(plane, [0,0,0]) == true);
+ assert(coplanar(plane, [1,1,0]) == false);
+ assert(coplanar(plane, [-1,1,0]) == true);
+ assert(coplanar(plane, [1,-1,0]) == true);
+ assert(coplanar(plane, [5,5,5]) == false);
}
test_coplanar();
module test_in_front_of_plane() {
- plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
- assert(in_front_of_plane(plane, [5,5,10]) == false);
- assert(in_front_of_plane(plane, [-5,0,0]) == true);
- assert(in_front_of_plane(plane, [5,0,0]) == false);
- assert(in_front_of_plane(plane, [0,-5,0]) == true);
- assert(in_front_of_plane(plane, [0,5,0]) == false);
- assert(in_front_of_plane(plane, [0,0,5]) == true);
- assert(in_front_of_plane(plane, [0,0,-5]) == false);
+ plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
+ assert(in_front_of_plane(plane, [5,5,10]) == false);
+ assert(in_front_of_plane(plane, [-5,0,0]) == true);
+ assert(in_front_of_plane(plane, [5,0,0]) == false);
+ assert(in_front_of_plane(plane, [0,-5,0]) == true);
+ assert(in_front_of_plane(plane, [0,5,0]) == false);
+ assert(in_front_of_plane(plane, [0,0,5]) == true);
+ assert(in_front_of_plane(plane, [0,0,-5]) == false);
}
test_in_front_of_plane();
module test_is_path() {
- assert(!is_path(123));
- assert(!is_path("foo"));
- assert(!is_path(true));
- assert(!is_path([]));
- assert(!is_path([[]]));
- assert(!is_path([["foo","bar","baz"]]));
- assert(!is_path([[1,2,3]]));
- assert(!is_path([["foo","bar","baz"],["qux","quux","quuux"]]));
- assert(is_path([[1,2,3],[4,5,6]]));
- assert(is_path([[1,2,3],[4,5,6],[7,8,9]]));
+ assert(!is_path(123));
+ assert(!is_path("foo"));
+ assert(!is_path(true));
+ assert(!is_path([]));
+ assert(!is_path([[]]));
+ assert(!is_path([["foo","bar","baz"]]));
+ assert(!is_path([[1,2,3]]));
+ assert(!is_path([["foo","bar","baz"],["qux","quux","quuux"]]));
+ assert(is_path([[1,2,3],[4,5,6]]));
+ assert(is_path([[1,2,3],[4,5,6],[7,8,9]]));
}
test_is_path();
module test_is_closed_path() {
- assert(!is_closed_path([[1,2,3],[4,5,6],[1,8,9]]));
- assert(is_closed_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]));
+ assert(!is_closed_path([[1,2,3],[4,5,6],[1,8,9]]));
+ assert(is_closed_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]));
}
test_is_closed_path();
module test_close_path() {
- assert(close_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
- assert(close_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
+ assert(close_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
+ assert(close_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
}
test_close_path();
module test_cleanup_path() {
- assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9]]);
- assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9]]);
+ assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9]]);
+ assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9]]);
}
test_cleanup_path();
@@ -500,71 +500,71 @@ test_cleanup_path();
module test_polygon_area() {
- assert(approx(polygon_area([[1,1],[-1,1],[-1,-1],[1,-1]]), 4));
- assert(approx(polygon_area(circle(r=50,$fn=1000)), -PI*50*50, eps=0.1));
+ assert(approx(polygon_area([[1,1],[-1,1],[-1,-1],[1,-1]]), 4));
+ assert(approx(polygon_area(circle(r=50,$fn=1000)), -PI*50*50, eps=0.1));
}
test_polygon_area();
module test_polygon_shift() {
- path = [[1,1],[-1,1],[-1,-1],[1,-1]];
- assert(polygon_shift(path,1) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
- assert(polygon_shift(path,2) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
+ path = [[1,1],[-1,1],[-1,-1],[1,-1]];
+ assert(polygon_shift(path,1) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
+ assert(polygon_shift(path,2) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
}
test_polygon_shift();
module test_polygon_shift_to_closest_point() {
- path = [[1,1],[-1,1],[-1,-1],[1,-1]];
- assert(polygon_shift_to_closest_point(path,[1.1,1.1]) == [[1,1],[-1,1],[-1,-1],[1,-1]]);
- assert(polygon_shift_to_closest_point(path,[-1.1,1.1]) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
- assert(polygon_shift_to_closest_point(path,[-1.1,-1.1]) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
- assert(polygon_shift_to_closest_point(path,[1.1,-1.1]) == [[1,-1],[1,1],[-1,1],[-1,-1]]);
+ path = [[1,1],[-1,1],[-1,-1],[1,-1]];
+ assert(polygon_shift_to_closest_point(path,[1.1,1.1]) == [[1,1],[-1,1],[-1,-1],[1,-1]]);
+ assert(polygon_shift_to_closest_point(path,[-1.1,1.1]) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
+ assert(polygon_shift_to_closest_point(path,[-1.1,-1.1]) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
+ assert(polygon_shift_to_closest_point(path,[1.1,-1.1]) == [[1,-1],[1,1],[-1,1],[-1,-1]]);
}
test_polygon_shift_to_closest_point();
module test_first_noncollinear(){
- pts = [
- [1,1], [2,2], [3,3], [4,4], [4,5], [5,6]
- ];
- assert(first_noncollinear(0,1,pts) == 4);
- assert(first_noncollinear(1,0,pts) == 4);
- assert(first_noncollinear(0,2,pts) == 4);
- assert(first_noncollinear(2,0,pts) == 4);
- assert(first_noncollinear(1,2,pts) == 4);
- assert(first_noncollinear(2,1,pts) == 4);
- assert(first_noncollinear(0,3,pts) == 4);
- assert(first_noncollinear(3,0,pts) == 4);
- assert(first_noncollinear(1,3,pts) == 4);
- assert(first_noncollinear(3,1,pts) == 4);
- assert(first_noncollinear(2,3,pts) == 4);
- assert(first_noncollinear(3,2,pts) == 4);
- assert(first_noncollinear(0,4,pts) == 1);
- assert(first_noncollinear(4,0,pts) == 1);
- assert(first_noncollinear(1,4,pts) == 0);
- assert(first_noncollinear(4,1,pts) == 0);
- assert(first_noncollinear(2,4,pts) == 0);
- assert(first_noncollinear(4,2,pts) == 0);
- assert(first_noncollinear(3,4,pts) == 0);
- assert(first_noncollinear(4,3,pts) == 0);
- assert(first_noncollinear(0,5,pts) == 1);
- assert(first_noncollinear(5,0,pts) == 1);
- assert(first_noncollinear(1,5,pts) == 0);
- assert(first_noncollinear(5,1,pts) == 0);
- assert(first_noncollinear(2,5,pts) == 0);
- assert(first_noncollinear(5,2,pts) == 0);
- assert(first_noncollinear(3,5,pts) == 0);
- assert(first_noncollinear(5,3,pts) == 0);
- assert(first_noncollinear(4,5,pts) == 0);
- assert(first_noncollinear(5,4,pts) == 0);
+ pts = [
+ [1,1], [2,2], [3,3], [4,4], [4,5], [5,6]
+ ];
+ assert(first_noncollinear(0,1,pts) == 4);
+ assert(first_noncollinear(1,0,pts) == 4);
+ assert(first_noncollinear(0,2,pts) == 4);
+ assert(first_noncollinear(2,0,pts) == 4);
+ assert(first_noncollinear(1,2,pts) == 4);
+ assert(first_noncollinear(2,1,pts) == 4);
+ assert(first_noncollinear(0,3,pts) == 4);
+ assert(first_noncollinear(3,0,pts) == 4);
+ assert(first_noncollinear(1,3,pts) == 4);
+ assert(first_noncollinear(3,1,pts) == 4);
+ assert(first_noncollinear(2,3,pts) == 4);
+ assert(first_noncollinear(3,2,pts) == 4);
+ assert(first_noncollinear(0,4,pts) == 1);
+ assert(first_noncollinear(4,0,pts) == 1);
+ assert(first_noncollinear(1,4,pts) == 0);
+ assert(first_noncollinear(4,1,pts) == 0);
+ assert(first_noncollinear(2,4,pts) == 0);
+ assert(first_noncollinear(4,2,pts) == 0);
+ assert(first_noncollinear(3,4,pts) == 0);
+ assert(first_noncollinear(4,3,pts) == 0);
+ assert(first_noncollinear(0,5,pts) == 1);
+ assert(first_noncollinear(5,0,pts) == 1);
+ assert(first_noncollinear(1,5,pts) == 0);
+ assert(first_noncollinear(5,1,pts) == 0);
+ assert(first_noncollinear(2,5,pts) == 0);
+ assert(first_noncollinear(5,2,pts) == 0);
+ assert(first_noncollinear(3,5,pts) == 0);
+ assert(first_noncollinear(5,3,pts) == 0);
+ assert(first_noncollinear(4,5,pts) == 0);
+ assert(first_noncollinear(5,4,pts) == 0);
}
test_first_noncollinear();
module test_find_noncollinear_points() {
- assert(find_noncollinear_points([[1,1],[2,2],[3,3],[4,4],[4,5],[5,6]]) == [0,5,3]);
- assert(find_noncollinear_points([[1,1],[2,2],[8,3],[4,4],[4,5],[5,6]]) == [0,2,5]);
+ assert(find_noncollinear_points([[1,1],[2,2],[3,3],[4,4],[4,5],[5,6]]) == [0,5,3]);
+ assert(find_noncollinear_points([[1,1],[2,2],[8,3],[4,4],[4,5],[5,6]]) == [0,2,5]);
}
test_find_noncollinear_points();
@@ -576,7 +576,7 @@ test_find_noncollinear_points();
module test_simplify_path() {
path = [[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]];
- assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]);
+ assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]);
}
test_simplify_path();
@@ -584,110 +584,110 @@ test_simplify_path();
module test_simplify_path_indexed() {
pts = [[10,0], [0,-10], [20,20], [20,10], [-20,-20], [15,30], [-10,-20]];
path = [4,6,1,0,3,2,5];
- assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]);
+ assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]);
}
test_simplify_path_indexed();
module test_point_in_polygon() {
- poly = [for (a=[0:30:359]) 10*[cos(a),sin(a)]];
- assert(point_in_polygon([0,0], poly) == 1);
- assert(point_in_polygon([20,0], poly) == -1);
- assert(point_in_polygon([5,5], poly) == 1);
- assert(point_in_polygon([-5,5], poly) == 1);
- assert(point_in_polygon([-5,-5], poly) == 1);
- assert(point_in_polygon([5,-5], poly) == 1);
- assert(point_in_polygon([-10,-10], poly) == -1);
- assert(point_in_polygon([10,0], poly) == 0);
- assert(point_in_polygon([0,10], poly) == 0);
- assert(point_in_polygon([0,-10], poly) == 0);
+ poly = [for (a=[0:30:359]) 10*[cos(a),sin(a)]];
+ assert(point_in_polygon([0,0], poly) == 1);
+ assert(point_in_polygon([20,0], poly) == -1);
+ assert(point_in_polygon([5,5], poly) == 1);
+ assert(point_in_polygon([-5,5], poly) == 1);
+ assert(point_in_polygon([-5,-5], poly) == 1);
+ assert(point_in_polygon([5,-5], poly) == 1);
+ assert(point_in_polygon([-10,-10], poly) == -1);
+ assert(point_in_polygon([10,0], poly) == 0);
+ assert(point_in_polygon([0,10], poly) == 0);
+ assert(point_in_polygon([0,-10], poly) == 0);
}
test_point_in_polygon();
module test_pointlist_bounds() {
- pts = [
- [-53,27,12],
- [-63,97,36],
- [84,-32,-5],
- [63,-24,42],
- [23,57,-42]
- ];
- assert(pointlist_bounds(pts) == [[-63,-32,-42], [84,97,42]]);
+ pts = [
+ [-53,27,12],
+ [-63,97,36],
+ [84,-32,-5],
+ [63,-24,42],
+ [23,57,-42]
+ ];
+ assert(pointlist_bounds(pts) == [[-63,-32,-42], [84,97,42]]);
}
test_pointlist_bounds();
module test_closest_point() {
- ptlist = [for (i=list_range(100)) rands(-100,100,2,seed_value=8463)];
- testpts = [for (i=list_range(100)) rands(-100,100,2,seed_value=6834)];
- for (pt = testpts) {
- pidx = closest_point(pt,ptlist);
- dists = [for (p=ptlist) norm(pt-p)];
- mindist = min(dists);
- assert(mindist == dists[pidx]);
- }
+ ptlist = [for (i=list_range(100)) rands(-100,100,2,seed_value=8463)];
+ testpts = [for (i=list_range(100)) rands(-100,100,2,seed_value=6834)];
+ for (pt = testpts) {
+ pidx = closest_point(pt,ptlist);
+ dists = [for (p=ptlist) norm(pt-p)];
+ mindist = min(dists);
+ assert(mindist == dists[pidx]);
+ }
}
test_closest_point();
module test_furthest_point() {
- ptlist = [for (i=list_range(100)) rands(-100,100,2,seed_value=8463)];
- testpts = [for (i=list_range(100)) rands(-100,100,2,seed_value=6834)];
- for (pt = testpts) {
- pidx = furthest_point(pt,ptlist);
- dists = [for (p=ptlist) norm(pt-p)];
- mindist = max(dists);
- assert(mindist == dists[pidx]);
- }
+ ptlist = [for (i=list_range(100)) rands(-100,100,2,seed_value=8463)];
+ testpts = [for (i=list_range(100)) rands(-100,100,2,seed_value=6834)];
+ for (pt = testpts) {
+ pidx = furthest_point(pt,ptlist);
+ dists = [for (p=ptlist) norm(pt-p)];
+ mindist = max(dists);
+ assert(mindist == dists[pidx]);
+ }
}
test_furthest_point();
module test_polygon_is_clockwise() {
- assert(polygon_is_clockwise([[-1,1],[1,1],[1,-1],[-1,-1]]));
- assert(!polygon_is_clockwise([[1,1],[-1,1],[-1,-1],[1,-1]]));
- assert(polygon_is_clockwise(circle(d=100)));
- assert(polygon_is_clockwise(square(100)));
+ assert(polygon_is_clockwise([[-1,1],[1,1],[1,-1],[-1,-1]]));
+ assert(!polygon_is_clockwise([[1,1],[-1,1],[-1,-1],[1,-1]]));
+ assert(polygon_is_clockwise(circle(d=100)));
+ assert(polygon_is_clockwise(square(100)));
}
test_polygon_is_clockwise();
module test_clockwise_polygon() {
- path = circle(d=100);
- rpath = concat([path[0]], reverse(select(path,1,-1)));
- assert(clockwise_polygon(path) == path);
- assert(clockwise_polygon(rpath) == path);
+ path = circle(d=100);
+ rpath = concat([path[0]], reverse(select(path,1,-1)));
+ assert(clockwise_polygon(path) == path);
+ assert(clockwise_polygon(rpath) == path);
}
test_clockwise_polygon();
module test_ccw_polygon() {
- path = circle(d=100);
- rpath = concat([path[0]], reverse(select(path,1,-1)));
- assert(ccw_polygon(path) == rpath);
- assert(ccw_polygon(rpath) == rpath);
+ path = circle(d=100);
+ rpath = concat([path[0]], reverse(select(path,1,-1)));
+ assert(ccw_polygon(path) == rpath);
+ assert(ccw_polygon(rpath) == rpath);
}
test_ccw_polygon();
module test_reverse_polygon() {
- path = circle(d=100);
- rpath = concat([path[0]], reverse(select(path,1,-1)));
- assert(reverse_polygon(path) == rpath);
- assert(reverse_polygon(rpath) == path);
+ path = circle(d=100);
+ rpath = concat([path[0]], reverse(select(path,1,-1)));
+ assert(reverse_polygon(path) == rpath);
+ assert(reverse_polygon(rpath) == path);
}
test_reverse_polygon();
module test_is_region() {
- assert(is_region([circle(d=10),square(10)]));
- assert(is_region([circle(d=10),square(10),circle(d=50)]));
- assert(is_region([square(10)]));
- assert(!is_region([]));
- assert(!is_region(23));
- assert(!is_region(true));
- assert(!is_region("foo"));
+ assert(is_region([circle(d=10),square(10)]));
+ assert(is_region([circle(d=10),square(10),circle(d=50)]));
+ assert(is_region([square(10)]));
+ assert(!is_region([]));
+ assert(!is_region(23));
+ assert(!is_region(true));
+ assert(!is_region("foo"));
}
test_is_region();
@@ -708,4 +708,4 @@ test_is_region();
cube(); // Prevents warning about no top-level geometry.
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_math.scad b/tests/test_math.scad
index 2103ed0..5a3dd7e 100644
--- a/tests/test_math.scad
+++ b/tests/test_math.scad
@@ -3,377 +3,377 @@ include
// Simple Calculations
module test_quant() {
- assert(quant(-4,3) == -3);
- assert(quant(-3,3) == -3);
- assert(quant(-2,3) == -3);
- assert(quant(-1,3) == 0);
- assert(quant(0,3) == 0);
- assert(quant(1,3) == 0);
- assert(quant(2,3) == 3);
- assert(quant(3,3) == 3);
- assert(quant(4,3) == 3);
- assert(quant(7,3) == 6);
- assert(quant([12,13,13.1,14,14.1,15,16],4) == [12,12,12,16,16,16,16]);
- assert(quant([9,10,10.4,10.5,11,12],3) == [9,9,9,12,12,12]);
- assert(quant([[9,10,10.4],[10.5,11,12]],3) == [[9,9,9],[12,12,12]]);
+ assert(quant(-4,3) == -3);
+ assert(quant(-3,3) == -3);
+ assert(quant(-2,3) == -3);
+ assert(quant(-1,3) == 0);
+ assert(quant(0,3) == 0);
+ assert(quant(1,3) == 0);
+ assert(quant(2,3) == 3);
+ assert(quant(3,3) == 3);
+ assert(quant(4,3) == 3);
+ assert(quant(7,3) == 6);
+ assert(quant([12,13,13.1,14,14.1,15,16],4) == [12,12,12,16,16,16,16]);
+ assert(quant([9,10,10.4,10.5,11,12],3) == [9,9,9,12,12,12]);
+ assert(quant([[9,10,10.4],[10.5,11,12]],3) == [[9,9,9],[12,12,12]]);
}
test_quant();
module test_quantdn() {
- assert(quantdn(-4,3) == -6);
- assert(quantdn(-3,3) == -3);
- assert(quantdn(-2,3) == -3);
- assert(quantdn(-1,3) == -3);
- assert(quantdn(0,3) == 0);
- assert(quantdn(1,3) == 0);
- assert(quantdn(2,3) == 0);
- assert(quantdn(3,3) == 3);
- assert(quantdn(4,3) == 3);
- assert(quantdn(7,3) == 6);
- assert(quantdn([12,13,13.1,14,14.1,15,16],4) == [12,12,12,12,12,12,16]);
- assert(quantdn([9,10,10.4,10.5,11,12],3) == [9,9,9,9,9,12]);
- assert(quantdn([[9,10,10.4],[10.5,11,12]],3) == [[9,9,9],[9,9,12]]);
+ assert(quantdn(-4,3) == -6);
+ assert(quantdn(-3,3) == -3);
+ assert(quantdn(-2,3) == -3);
+ assert(quantdn(-1,3) == -3);
+ assert(quantdn(0,3) == 0);
+ assert(quantdn(1,3) == 0);
+ assert(quantdn(2,3) == 0);
+ assert(quantdn(3,3) == 3);
+ assert(quantdn(4,3) == 3);
+ assert(quantdn(7,3) == 6);
+ assert(quantdn([12,13,13.1,14,14.1,15,16],4) == [12,12,12,12,12,12,16]);
+ assert(quantdn([9,10,10.4,10.5,11,12],3) == [9,9,9,9,9,12]);
+ assert(quantdn([[9,10,10.4],[10.5,11,12]],3) == [[9,9,9],[9,9,12]]);
}
test_quantdn();
module test_quantup() {
- assert(quantup(-4,3) == -3);
- assert(quantup(-3,3) == -3);
- assert(quantup(-2,3) == 0);
- assert(quantup(-1,3) == 0);
- assert(quantup(0,3) == 0);
- assert(quantup(1,3) == 3);
- assert(quantup(2,3) == 3);
- assert(quantup(3,3) == 3);
- assert(quantup(4,3) == 6);
- assert(quantup(7,3) == 9);
- assert(quantup([12,13,13.1,14,14.1,15,16],4) == [12,16,16,16,16,16,16]);
- assert(quantup([9,10,10.4,10.5,11,12],3) == [9,12,12,12,12,12]);
- assert(quantup([[9,10,10.4],[10.5,11,12]],3) == [[9,12,12],[12,12,12]]);
+ assert(quantup(-4,3) == -3);
+ assert(quantup(-3,3) == -3);
+ assert(quantup(-2,3) == 0);
+ assert(quantup(-1,3) == 0);
+ assert(quantup(0,3) == 0);
+ assert(quantup(1,3) == 3);
+ assert(quantup(2,3) == 3);
+ assert(quantup(3,3) == 3);
+ assert(quantup(4,3) == 6);
+ assert(quantup(7,3) == 9);
+ assert(quantup([12,13,13.1,14,14.1,15,16],4) == [12,16,16,16,16,16,16]);
+ assert(quantup([9,10,10.4,10.5,11,12],3) == [9,12,12,12,12,12]);
+ assert(quantup([[9,10,10.4],[10.5,11,12]],3) == [[9,12,12],[12,12,12]]);
}
test_quantup();
module test_constrain() {
- assert(constrain(-2,-1,1) == -1);
- assert(constrain(-1.75,-1,1) == -1);
- assert(constrain(-1,-1,1) == -1);
- assert(constrain(-0.75,-1,1) == -0.75);
- assert(constrain(0,-1,1) == 0);
- assert(constrain(0.75,-1,1) == 0.75);
- assert(constrain(1,-1,1) == 1);
- assert(constrain(1.75,-1,1) == 1);
- assert(constrain(2,-1,1) == 1);
+ assert(constrain(-2,-1,1) == -1);
+ assert(constrain(-1.75,-1,1) == -1);
+ assert(constrain(-1,-1,1) == -1);
+ assert(constrain(-0.75,-1,1) == -0.75);
+ assert(constrain(0,-1,1) == 0);
+ assert(constrain(0.75,-1,1) == 0.75);
+ assert(constrain(1,-1,1) == 1);
+ assert(constrain(1.75,-1,1) == 1);
+ assert(constrain(2,-1,1) == 1);
}
test_constrain();
module test_approx() {
- assert(approx(PI, 3.141592653589793236) == true);
- assert(approx(PI, 3.1415926) == false);
- assert(approx(PI, 3.1415926, eps=1e-6) == true);
- assert(approx(-PI, -3.141592653589793236) == true);
- assert(approx(-PI, -3.1415926) == false);
- assert(approx(-PI, -3.1415926, eps=1e-6) == true);
- assert(approx(1/3, 0.3333333333) == true);
- assert(approx(-1/3, -0.3333333333) == true);
- assert(approx(10*[cos(30),sin(30)], 10*[sqrt(3)/2, 1/2]) == true);
+ assert(approx(PI, 3.141592653589793236) == true);
+ assert(approx(PI, 3.1415926) == false);
+ assert(approx(PI, 3.1415926, eps=1e-6) == true);
+ assert(approx(-PI, -3.141592653589793236) == true);
+ assert(approx(-PI, -3.1415926) == false);
+ assert(approx(-PI, -3.1415926, eps=1e-6) == true);
+ assert(approx(1/3, 0.3333333333) == true);
+ assert(approx(-1/3, -0.3333333333) == true);
+ assert(approx(10*[cos(30),sin(30)], 10*[sqrt(3)/2, 1/2]) == true);
}
test_approx();
module test_min_index() {
- vals = rands(-100,100,100);
- minval = min(vals);
- minidx = min_index(vals);
- assert(vals[minidx] == minval);
- assert(min_index([3,4,5,6]) == 0);
- assert(min_index([4,3,5,6]) == 1);
- assert(min_index([4,5,3,6]) == 2);
- assert(min_index([4,5,6,3]) == 3);
- assert(min_index([6,5,4,3]) == 3);
- assert(min_index([6,3,4,5]) == 1);
- assert(min_index([-56,72,-874,5]) == 2);
+ vals = rands(-100,100,100);
+ minval = min(vals);
+ minidx = min_index(vals);
+ assert(vals[minidx] == minval);
+ assert(min_index([3,4,5,6]) == 0);
+ assert(min_index([4,3,5,6]) == 1);
+ assert(min_index([4,5,3,6]) == 2);
+ assert(min_index([4,5,6,3]) == 3);
+ assert(min_index([6,5,4,3]) == 3);
+ assert(min_index([6,3,4,5]) == 1);
+ assert(min_index([-56,72,-874,5]) == 2);
}
test_min_index();
module test_max_index() {
- vals = rands(-100,100,100);
- maxval = max(vals);
- maxidx = max_index(vals);
- assert(vals[maxidx] == maxval);
- assert(max_index([3,4,5,6]) == 3);
- assert(max_index([3,4,6,5]) == 2);
- assert(max_index([3,6,4,5]) == 1);
- assert(max_index([6,3,4,5]) == 0);
- assert(max_index([5,6,4,3]) == 1);
- assert(max_index([-56,72,-874,5]) == 1);
+ vals = rands(-100,100,100);
+ maxval = max(vals);
+ maxidx = max_index(vals);
+ assert(vals[maxidx] == maxval);
+ assert(max_index([3,4,5,6]) == 3);
+ assert(max_index([3,4,6,5]) == 2);
+ assert(max_index([3,6,4,5]) == 1);
+ assert(max_index([6,3,4,5]) == 0);
+ assert(max_index([5,6,4,3]) == 1);
+ assert(max_index([-56,72,-874,5]) == 1);
}
test_max_index();
module test_posmod() {
- assert(posmod(-5,3) == 1);
- assert(posmod(-4,3) == 2);
- assert(posmod(-3,3) == 0);
- assert(posmod(-2,3) == 1);
- assert(posmod(-1,3) == 2);
- assert(posmod(0,3) == 0);
- assert(posmod(1,3) == 1);
- assert(posmod(2,3) == 2);
- assert(posmod(3,3) == 0);
+ assert(posmod(-5,3) == 1);
+ assert(posmod(-4,3) == 2);
+ assert(posmod(-3,3) == 0);
+ assert(posmod(-2,3) == 1);
+ assert(posmod(-1,3) == 2);
+ assert(posmod(0,3) == 0);
+ assert(posmod(1,3) == 1);
+ assert(posmod(2,3) == 2);
+ assert(posmod(3,3) == 0);
}
test_posmod();
module test_modang() {
- assert(modang(-700) == 20);
- assert(modang(-270) == 90);
- assert(modang(-120) == -120);
- assert(modang(120) == 120);
- assert(modang(270) == -90);
- assert(modang(700) == -20);
+ assert(modang(-700) == 20);
+ assert(modang(-270) == 90);
+ assert(modang(-120) == -120);
+ assert(modang(120) == 120);
+ assert(modang(270) == -90);
+ assert(modang(700) == -20);
}
test_modang();
module test_modrange() {
- assert(modrange(-5,5,3) == [1,2]);
- assert(modrange(-1,4,3) == [2,0,1]);
- assert(modrange(1,8,10,step=2) == [1,3,5,7]);
- assert(modrange(5,12,10,step=2) == [5,7,9,1]);
+ assert(modrange(-5,5,3) == [1,2]);
+ assert(modrange(-1,4,3) == [2,0,1]);
+ assert(modrange(1,8,10,step=2) == [1,3,5,7]);
+ assert(modrange(5,12,10,step=2) == [5,7,9,1]);
}
test_modrange();
module test_sqr() {
- assert(sqr(-3) == 9);
- assert(sqr(0) == 0);
- assert(sqr(1) == 1);
- assert(sqr(2) == 4);
- assert(sqr(3) == 9);
- assert(sqr(16) == 256);
+ assert(sqr(-3) == 9);
+ assert(sqr(0) == 0);
+ assert(sqr(1) == 1);
+ assert(sqr(2) == 4);
+ assert(sqr(3) == 9);
+ assert(sqr(16) == 256);
}
test_sqr();
module test_log2() {
- assert(log2(0.125) == -3);
- assert(log2(16) == 4);
- assert(log2(256) == 8);
+ assert(log2(0.125) == -3);
+ assert(log2(16) == 4);
+ assert(log2(256) == 8);
}
test_log2();
module test_rand_int() {
- nums = rand_int(-100,100,1000,seed=2134);
- assert(len(nums)==1000);
- for (num = nums) {
- assert(num>=-100);
- assert(num<=100);
- assert(num==floor(num));
- }
+ nums = rand_int(-100,100,1000,seed=2134);
+ assert(len(nums)==1000);
+ for (num = nums) {
+ assert(num>=-100);
+ assert(num<=100);
+ assert(num==floor(num));
+ }
}
test_rand_int();
module test_gaussian_rands() {
- nums1 = gaussian_rands(0,10,1000,seed=2132);
- nums2 = gaussian_rands(0,10,1000,seed=2130);
- nums3 = gaussian_rands(0,10,1000,seed=2132);
- assert(len(nums1)==1000);
- assert(len(nums2)==1000);
- assert(len(nums3)==1000);
- assert(nums1==nums3);
- assert(nums1!=nums2);
+ nums1 = gaussian_rands(0,10,1000,seed=2132);
+ nums2 = gaussian_rands(0,10,1000,seed=2130);
+ nums3 = gaussian_rands(0,10,1000,seed=2132);
+ assert(len(nums1)==1000);
+ assert(len(nums2)==1000);
+ assert(len(nums3)==1000);
+ assert(nums1==nums3);
+ assert(nums1!=nums2);
}
test_gaussian_rands();
module test_log_rands() {
- nums1 = log_rands(0,100,10,1000,seed=2189);
- nums2 = log_rands(0,100,10,1000,seed=2310);
- nums3 = log_rands(0,100,10,1000,seed=2189);
- assert(len(nums1)==1000);
- assert(len(nums2)==1000);
- assert(len(nums3)==1000);
- assert(nums1==nums3);
- assert(nums1!=nums2);
+ nums1 = log_rands(0,100,10,1000,seed=2189);
+ nums2 = log_rands(0,100,10,1000,seed=2310);
+ nums3 = log_rands(0,100,10,1000,seed=2189);
+ assert(len(nums1)==1000);
+ assert(len(nums2)==1000);
+ assert(len(nums3)==1000);
+ assert(nums1==nums3);
+ assert(nums1!=nums2);
}
test_log_rands();
module test_segs() {
- assert(segs(50,$fn=8) == 8);
- assert(segs(50,$fa=2,$fs=2) == 158);
+ assert(segs(50,$fn=8) == 8);
+ assert(segs(50,$fa=2,$fs=2) == 158);
}
test_segs();
module test_lerp() {
- assert(lerp(-20,20,0) == -20);
- assert(lerp(-20,20,0.25) == -10);
- assert(lerp(-20,20,0.5) == 0);
- assert(lerp(-20,20,0.75) == 10);
- assert(lerp(-20,20,1) == 20);
- assert(lerp(-20,20,[0,0.25,0.5,0.75,1]) == [-20,-10,0,10,20]);
- assert(lerp(-20,20,[0:0.25:1]) == [-20,-10,0,10,20]);
- assert(lerp([10,10],[30,-10],0.5) == [20,0]);
+ assert(lerp(-20,20,0) == -20);
+ assert(lerp(-20,20,0.25) == -10);
+ assert(lerp(-20,20,0.5) == 0);
+ assert(lerp(-20,20,0.75) == 10);
+ assert(lerp(-20,20,1) == 20);
+ assert(lerp(-20,20,[0,0.25,0.5,0.75,1]) == [-20,-10,0,10,20]);
+ assert(lerp(-20,20,[0:0.25:1]) == [-20,-10,0,10,20]);
+ assert(lerp([10,10],[30,-10],0.5) == [20,0]);
}
test_lerp();
module test_hypot() {
- assert(hypot(20,30) == norm([20,30]));
+ assert(hypot(20,30) == norm([20,30]));
}
test_hypot();
module test_sinh() {
- assert(abs(sinh(-2)+3.6268604078) < EPSILON);
- assert(abs(sinh(-1)+1.1752011936) < EPSILON);
- assert(abs(sinh(0)) < EPSILON);
- assert(abs(sinh(1)-1.1752011936) < EPSILON);
- assert(abs(sinh(2)-3.6268604078) < EPSILON);
+ assert(abs(sinh(-2)+3.6268604078) < EPSILON);
+ assert(abs(sinh(-1)+1.1752011936) < EPSILON);
+ assert(abs(sinh(0)) < EPSILON);
+ assert(abs(sinh(1)-1.1752011936) < EPSILON);
+ assert(abs(sinh(2)-3.6268604078) < EPSILON);
}
test_sinh();
module test_cosh() {
- assert(abs(cosh(-2)-3.7621956911) < EPSILON);
- assert(abs(cosh(-1)-1.5430806348) < EPSILON);
- assert(abs(cosh(0)-1) < EPSILON);
- assert(abs(cosh(1)-1.5430806348) < EPSILON);
- assert(abs(cosh(2)-3.7621956911) < EPSILON);
+ assert(abs(cosh(-2)-3.7621956911) < EPSILON);
+ assert(abs(cosh(-1)-1.5430806348) < EPSILON);
+ assert(abs(cosh(0)-1) < EPSILON);
+ assert(abs(cosh(1)-1.5430806348) < EPSILON);
+ assert(abs(cosh(2)-3.7621956911) < EPSILON);
}
test_cosh();
module test_tanh() {
- assert(abs(tanh(-2)+0.9640275801) < EPSILON);
- assert(abs(tanh(-1)+0.761594156) < EPSILON);
- assert(abs(tanh(0)) < EPSILON);
- assert(abs(tanh(1)-0.761594156) < EPSILON);
- assert(abs(tanh(2)-0.9640275801) < EPSILON);
+ assert(abs(tanh(-2)+0.9640275801) < EPSILON);
+ assert(abs(tanh(-1)+0.761594156) < EPSILON);
+ assert(abs(tanh(0)) < EPSILON);
+ assert(abs(tanh(1)-0.761594156) < EPSILON);
+ assert(abs(tanh(2)-0.9640275801) < EPSILON);
}
test_tanh();
module test_asinh() {
- assert(abs(asinh(sinh(-2))+2) < EPSILON);
- assert(abs(asinh(sinh(-1))+1) < EPSILON);
- assert(abs(asinh(sinh(0))) < EPSILON);
- assert(abs(asinh(sinh(1))-1) < EPSILON);
- assert(abs(asinh(sinh(2))-2) < EPSILON);
+ assert(abs(asinh(sinh(-2))+2) < EPSILON);
+ assert(abs(asinh(sinh(-1))+1) < EPSILON);
+ assert(abs(asinh(sinh(0))) < EPSILON);
+ assert(abs(asinh(sinh(1))-1) < EPSILON);
+ assert(abs(asinh(sinh(2))-2) < EPSILON);
}
test_asinh();
module test_acosh() {
- assert(abs(acosh(cosh(-2))-2) < EPSILON);
- assert(abs(acosh(cosh(-1))-1) < EPSILON);
- assert(abs(acosh(cosh(0))) < EPSILON);
- assert(abs(acosh(cosh(1))-1) < EPSILON);
- assert(abs(acosh(cosh(2))-2) < EPSILON);
+ assert(abs(acosh(cosh(-2))-2) < EPSILON);
+ assert(abs(acosh(cosh(-1))-1) < EPSILON);
+ assert(abs(acosh(cosh(0))) < EPSILON);
+ assert(abs(acosh(cosh(1))-1) < EPSILON);
+ assert(abs(acosh(cosh(2))-2) < EPSILON);
}
test_acosh();
module test_atanh() {
- assert(abs(atanh(tanh(-2))+2) < EPSILON);
- assert(abs(atanh(tanh(-1))+1) < EPSILON);
- assert(abs(atanh(tanh(0))) < EPSILON);
- assert(abs(atanh(tanh(1))-1) < EPSILON);
- assert(abs(atanh(tanh(2))-2) < EPSILON);
+ assert(abs(atanh(tanh(-2))+2) < EPSILON);
+ assert(abs(atanh(tanh(-1))+1) < EPSILON);
+ assert(abs(atanh(tanh(0))) < EPSILON);
+ assert(abs(atanh(tanh(1))-1) < EPSILON);
+ assert(abs(atanh(tanh(2))-2) < EPSILON);
}
test_atanh();
module test_sum() {
- assert(sum([]) == 0);
- assert(sum([],dflt=undef) == undef);
- assert(sum([1,2,3]) == 6);
- assert(sum([-2,-1,0,1,2]) == 0);
- assert(sum([[1,2,3], [3,4,5], [5,6,7]]) == [9,12,15]);
+ assert(sum([]) == 0);
+ assert(sum([],dflt=undef) == undef);
+ assert(sum([1,2,3]) == 6);
+ assert(sum([-2,-1,0,1,2]) == 0);
+ assert(sum([[1,2,3], [3,4,5], [5,6,7]]) == [9,12,15]);
}
test_sum();
module test_cumsum() {
- assert(cumsum([]) == []);
- assert(cumsum([1,1,1]) == [1,2,3]);
- assert(cumsum([2,2,2]) == [2,4,6]);
- assert(cumsum([1,2,3]) == [1,3,6]);
- assert(cumsum([-2,-1,0,1,2]) == [-2,-3,-3,-2,0]);
- assert(cumsum([[1,2,3], [3,4,5], [5,6,7]]) == [[1,2,3],[4,6,8],[9,12,15]]);
+ assert(cumsum([]) == []);
+ assert(cumsum([1,1,1]) == [1,2,3]);
+ assert(cumsum([2,2,2]) == [2,4,6]);
+ assert(cumsum([1,2,3]) == [1,3,6]);
+ assert(cumsum([-2,-1,0,1,2]) == [-2,-3,-3,-2,0]);
+ assert(cumsum([[1,2,3], [3,4,5], [5,6,7]]) == [[1,2,3],[4,6,8],[9,12,15]]);
}
test_cumsum();
module test_sum_of_squares() {
- assert(sum_of_squares([1,2,3]) == 14);
- assert(sum_of_squares([1,2,4]) == 21);
- assert(sum_of_squares([-3,-2,-1]) == 14);
+ assert(sum_of_squares([1,2,3]) == 14);
+ assert(sum_of_squares([1,2,4]) == 21);
+ assert(sum_of_squares([-3,-2,-1]) == 14);
}
test_sum_of_squares();
module test_sum_of_sines() {
- assert(sum_of_sines(0, [[3,4,0],[2,2,0]]) == 0);
- assert(sum_of_sines(45, [[3,4,0],[2,2,0]]) == 2);
- assert(sum_of_sines(90, [[3,4,0],[2,2,0]]) == 0);
- assert(sum_of_sines(135, [[3,4,0],[2,2,0]]) == -2);
- assert(sum_of_sines(180, [[3,4,0],[2,2,0]]) == 0);
+ assert(sum_of_sines(0, [[3,4,0],[2,2,0]]) == 0);
+ assert(sum_of_sines(45, [[3,4,0],[2,2,0]]) == 2);
+ assert(sum_of_sines(90, [[3,4,0],[2,2,0]]) == 0);
+ assert(sum_of_sines(135, [[3,4,0],[2,2,0]]) == -2);
+ assert(sum_of_sines(180, [[3,4,0],[2,2,0]]) == 0);
}
test_sum_of_sines();
module test_deltas() {
- assert(deltas([2,5,9,17]) == [3,4,8]);
- assert(deltas([[1,2,3], [3,6,8], [4,8,11]]) == [[2,4,5], [1,2,3]]);
+ assert(deltas([2,5,9,17]) == [3,4,8]);
+ assert(deltas([[1,2,3], [3,6,8], [4,8,11]]) == [[2,4,5], [1,2,3]]);
}
test_deltas();
module test_product() {
- assert(product([2,3,4]) == 24);
- assert(product([[1,2,3], [3,4,5], [5,6,7]]) == [15, 48, 105]);
- m1 = [[2,3,4],[4,5,6],[6,7,8]];
- m2 = [[4,1,2],[3,7,2],[8,7,4]];
- m3 = [[3,7,8],[9,2,4],[5,8,3]];
- assert(product([m1,m2,m3]) == m1*m2*m3);
+ assert(product([2,3,4]) == 24);
+ assert(product([[1,2,3], [3,4,5], [5,6,7]]) == [15, 48, 105]);
+ m1 = [[2,3,4],[4,5,6],[6,7,8]];
+ m2 = [[4,1,2],[3,7,2],[8,7,4]];
+ m3 = [[3,7,8],[9,2,4],[5,8,3]];
+ assert(product([m1,m2,m3]) == m1*m2*m3);
}
test_product();
module test_mean() {
- assert(mean([2,3,4]) == 3);
- assert(mean([[1,2,3], [3,4,5], [5,6,7]]) == [3,4,5]);
+ assert(mean([2,3,4]) == 3);
+ assert(mean([[1,2,3], [3,4,5], [5,6,7]]) == [3,4,5]);
}
test_mean();
module test_det2() {
- assert(det2([[6,-2], [1,8]]) == 50);
- assert(det2([[4,7], [3,2]]) == -13);
- assert(det2([[4,3], [3,4]]) == 7);
+ assert(det2([[6,-2], [1,8]]) == 50);
+ assert(det2([[4,7], [3,2]]) == -13);
+ assert(det2([[4,3], [3,4]]) == 7);
}
test_det2();
module test_det3() {
- M = [ [6,4,-2], [1,-2,8], [1,5,7] ];
- assert(det3(M) == -334);
+ M = [ [6,4,-2], [1,-2,8], [1,5,7] ];
+ assert(det3(M) == -334);
}
test_det3();
module test_determinant() {
- M = [ [6,4,-2,9], [1,-2,8,3], [1,5,7,6], [4,2,5,1] ];
- assert(determinant(M) == 2267);
+ M = [ [6,4,-2,9], [1,-2,8,3], [1,5,7,6], [4,2,5,1] ];
+ assert(determinant(M) == 2267);
}
test_determinant();
@@ -382,167 +382,167 @@ test_determinant();
module test_compare_vals() {
- assert(compare_vals(-10,0) < 0);
- assert(compare_vals(10,0) > 0);
- assert(compare_vals(10,10) == 0);
+ assert(compare_vals(-10,0) < 0);
+ assert(compare_vals(10,0) > 0);
+ assert(compare_vals(10,10) == 0);
- assert(compare_vals("abc","abcd") < 0);
- assert(compare_vals("abcd","abc") > 0);
- assert(compare_vals("abcd","abcd") == 0);
+ assert(compare_vals("abc","abcd") < 0);
+ assert(compare_vals("abcd","abc") > 0);
+ assert(compare_vals("abcd","abcd") == 0);
- assert(compare_vals(false,false) == 0);
- assert(compare_vals(true,false) > 0);
- assert(compare_vals(false,true) < 0);
- assert(compare_vals(true,true) == 0);
+ assert(compare_vals(false,false) == 0);
+ assert(compare_vals(true,false) > 0);
+ assert(compare_vals(false,true) < 0);
+ assert(compare_vals(true,true) == 0);
- assert(compare_vals([2,3,4], [2,3,4,5]) < 0);
- assert(compare_vals([2,3,4,5], [2,3,4,5]) == 0);
- assert(compare_vals([2,3,4,5], [2,3,4]) > 0);
- assert(compare_vals([2,3,4,5], [2,3,5,5]) < 0);
- assert(compare_vals([[2,3,4,5]], [[2,3,5,5]]) < 0);
+ assert(compare_vals([2,3,4], [2,3,4,5]) < 0);
+ assert(compare_vals([2,3,4,5], [2,3,4,5]) == 0);
+ assert(compare_vals([2,3,4,5], [2,3,4]) > 0);
+ assert(compare_vals([2,3,4,5], [2,3,5,5]) < 0);
+ assert(compare_vals([[2,3,4,5]], [[2,3,5,5]]) < 0);
- assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5]]) == 0);
- assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4,5], [3,4,5]]) < 0);
- assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5,6]]) < 0);
- assert(compare_vals([[2,3,4,5],[3,4,5]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_vals([[2,3,4],[3,4,5,6]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_vals([[2,3,4],[3,5,5]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,5,5]]) < 0);
+ assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5]]) == 0);
+ assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4,5], [3,4,5]]) < 0);
+ assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5,6]]) < 0);
+ assert(compare_vals([[2,3,4,5],[3,4,5]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_vals([[2,3,4],[3,4,5,6]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_vals([[2,3,4],[3,5,5]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_vals([[2,3,4],[3,4,5]], [[2,3,4], [3,5,5]]) < 0);
- assert(compare_vals(undef, undef) == 0);
- assert(compare_vals(undef, true) < 0);
- assert(compare_vals(undef, 0) < 0);
- assert(compare_vals(undef, "foo") < 0);
- assert(compare_vals(undef, [2,3,4]) < 0);
- assert(compare_vals(undef, [0:3]) < 0);
+ assert(compare_vals(undef, undef) == 0);
+ assert(compare_vals(undef, true) < 0);
+ assert(compare_vals(undef, 0) < 0);
+ assert(compare_vals(undef, "foo") < 0);
+ assert(compare_vals(undef, [2,3,4]) < 0);
+ assert(compare_vals(undef, [0:3]) < 0);
- assert(compare_vals(true, undef) > 0);
- assert(compare_vals(true, true) == 0);
- assert(compare_vals(true, 0) < 0);
- assert(compare_vals(true, "foo") < 0);
- assert(compare_vals(true, [2,3,4]) < 0);
- assert(compare_vals(true, [0:3]) < 0);
+ assert(compare_vals(true, undef) > 0);
+ assert(compare_vals(true, true) == 0);
+ assert(compare_vals(true, 0) < 0);
+ assert(compare_vals(true, "foo") < 0);
+ assert(compare_vals(true, [2,3,4]) < 0);
+ assert(compare_vals(true, [0:3]) < 0);
- assert(compare_vals(0, undef) > 0);
- assert(compare_vals(0, true) > 0);
- assert(compare_vals(0, 0) == 0);
- assert(compare_vals(0, "foo") < 0);
- assert(compare_vals(0, [2,3,4]) < 0);
- assert(compare_vals(0, [0:3]) < 0);
+ assert(compare_vals(0, undef) > 0);
+ assert(compare_vals(0, true) > 0);
+ assert(compare_vals(0, 0) == 0);
+ assert(compare_vals(0, "foo") < 0);
+ assert(compare_vals(0, [2,3,4]) < 0);
+ assert(compare_vals(0, [0:3]) < 0);
- assert(compare_vals(1, undef) > 0);
- assert(compare_vals(1, true) > 0);
- assert(compare_vals(1, 1) == 0);
- assert(compare_vals(1, "foo") < 0);
- assert(compare_vals(1, [2,3,4]) < 0);
- assert(compare_vals(1, [0:3]) < 0);
+ assert(compare_vals(1, undef) > 0);
+ assert(compare_vals(1, true) > 0);
+ assert(compare_vals(1, 1) == 0);
+ assert(compare_vals(1, "foo") < 0);
+ assert(compare_vals(1, [2,3,4]) < 0);
+ assert(compare_vals(1, [0:3]) < 0);
- assert(compare_vals("foo", undef) > 0);
- assert(compare_vals("foo", true) > 0);
- assert(compare_vals("foo", 1) > 0);
- assert(compare_vals("foo", "foo") == 0);
- assert(compare_vals("foo", [2,3,4]) < 0);
- assert(compare_vals("foo", [0:3]) < 0);
+ assert(compare_vals("foo", undef) > 0);
+ assert(compare_vals("foo", true) > 0);
+ assert(compare_vals("foo", 1) > 0);
+ assert(compare_vals("foo", "foo") == 0);
+ assert(compare_vals("foo", [2,3,4]) < 0);
+ assert(compare_vals("foo", [0:3]) < 0);
- assert(compare_vals([2,3,4], undef) > 0);
- assert(compare_vals([2,3,4], true) > 0);
- assert(compare_vals([2,3,4], 1) > 0);
- assert(compare_vals([2,3,4], "foo") > 0);
- assert(compare_vals([2,3,4], [2,3,4]) == 0);
- assert(compare_vals([2,3,4], [0:3]) < 0);
+ assert(compare_vals([2,3,4], undef) > 0);
+ assert(compare_vals([2,3,4], true) > 0);
+ assert(compare_vals([2,3,4], 1) > 0);
+ assert(compare_vals([2,3,4], "foo") > 0);
+ assert(compare_vals([2,3,4], [2,3,4]) == 0);
+ assert(compare_vals([2,3,4], [0:3]) < 0);
- assert(compare_vals([0:3], undef) > 0);
- assert(compare_vals([0:3], true) > 0);
- assert(compare_vals([0:3], 1) > 0);
- assert(compare_vals([0:3], "foo") > 0);
- assert(compare_vals([0:3], [2,3,4]) > 0);
- assert(compare_vals([0:3], [0:3]) == 0);
+ assert(compare_vals([0:3], undef) > 0);
+ assert(compare_vals([0:3], true) > 0);
+ assert(compare_vals([0:3], 1) > 0);
+ assert(compare_vals([0:3], "foo") > 0);
+ assert(compare_vals([0:3], [2,3,4]) > 0);
+ assert(compare_vals([0:3], [0:3]) == 0);
}
test_compare_vals();
module test_compare_lists() {
- assert(compare_lists([2,3,4], [2,3,4,5]) < 0);
- assert(compare_lists([2,3,4,5], [2,3,4,5]) == 0);
- assert(compare_lists([2,3,4,5], [2,3,4]) > 0);
- assert(compare_lists([2,3,4,5], [2,3,5,5]) < 0);
+ assert(compare_lists([2,3,4], [2,3,4,5]) < 0);
+ assert(compare_lists([2,3,4,5], [2,3,4,5]) == 0);
+ assert(compare_lists([2,3,4,5], [2,3,4]) > 0);
+ assert(compare_lists([2,3,4,5], [2,3,5,5]) < 0);
- assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5]]) == 0);
- assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4,5], [3,4,5]]) < 0);
- assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5,6]]) < 0);
- assert(compare_lists([[2,3,4,5],[3,4,5]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_lists([[2,3,4],[3,4,5,6]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_lists([[2,3,4],[3,5,5]], [[2,3,4], [3,4,5]]) > 0);
- assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,5,5]]) < 0);
+ assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5]]) == 0);
+ assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4,5], [3,4,5]]) < 0);
+ assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,4,5,6]]) < 0);
+ assert(compare_lists([[2,3,4,5],[3,4,5]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_lists([[2,3,4],[3,4,5,6]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_lists([[2,3,4],[3,5,5]], [[2,3,4], [3,4,5]]) > 0);
+ assert(compare_lists([[2,3,4],[3,4,5]], [[2,3,4], [3,5,5]]) < 0);
- assert(compare_lists("cat", "bat") > 0);
- assert(compare_lists(["cat"], ["bat"]) > 0);
+ assert(compare_lists("cat", "bat") > 0);
+ assert(compare_lists(["cat"], ["bat"]) > 0);
}
test_compare_lists();
module test_any() {
- assert(any([0,false,undef]) == false);
- assert(any([1,false,undef]) == true);
- assert(any([1,5,true]) == true);
- assert(any([[0,0], [0,0]]) == false);
- assert(any([[0,0], [1,0]]) == true);
+ assert(any([0,false,undef]) == false);
+ assert(any([1,false,undef]) == true);
+ assert(any([1,5,true]) == true);
+ assert(any([[0,0], [0,0]]) == false);
+ assert(any([[0,0], [1,0]]) == true);
}
test_any();
module test_all() {
- assert(all([0,false,undef]) == false);
- assert(all([1,false,undef]) == false);
- assert(all([1,5,true]) == true);
- assert(all([[0,0], [0,0]]) == false);
- assert(all([[0,0], [1,0]]) == false);
- assert(all([[1,1], [1,1]]) == true);
+ assert(all([0,false,undef]) == false);
+ assert(all([1,false,undef]) == false);
+ assert(all([1,5,true]) == true);
+ assert(all([[0,0], [0,0]]) == false);
+ assert(all([[0,0], [1,0]]) == false);
+ assert(all([[1,1], [1,1]]) == true);
}
test_all();
module test_count_true() {
- assert(count_true([0,false,undef]) == 0);
- assert(count_true([1,false,undef]) == 1);
- assert(count_true([1,5,false]) == 2);
- assert(count_true([1,5,true]) == 3);
- assert(count_true([[0,0], [0,0]]) == 0);
- assert(count_true([[0,0], [1,0]]) == 1);
- assert(count_true([[1,1], [1,1]]) == 4);
- assert(count_true([[1,1], [1,1]], nmax=3) == 3);
+ assert(count_true([0,false,undef]) == 0);
+ assert(count_true([1,false,undef]) == 1);
+ assert(count_true([1,5,false]) == 2);
+ assert(count_true([1,5,true]) == 3);
+ assert(count_true([[0,0], [0,0]]) == 0);
+ assert(count_true([[0,0], [1,0]]) == 1);
+ assert(count_true([[1,1], [1,1]]) == 4);
+ assert(count_true([[1,1], [1,1]], nmax=3) == 3);
}
test_count_true();
module test_factorial() {
- assert(factorial(1) == 1);
- assert(factorial(2) == 2);
- assert(factorial(3) == 6);
- assert(factorial(4) == 24);
- assert(factorial(5) == 120);
- assert(factorial(6) == 720);
- assert(factorial(7) == 5040);
- assert(factorial(8) == 40320);
+ assert(factorial(1) == 1);
+ assert(factorial(2) == 2);
+ assert(factorial(3) == 6);
+ assert(factorial(4) == 24);
+ assert(factorial(5) == 120);
+ assert(factorial(6) == 720);
+ assert(factorial(7) == 5040);
+ assert(factorial(8) == 40320);
}
test_factorial();
module test_gcd() {
- assert(gcd(15,25) == 5);
- assert(gcd(15,27) == 3);
- assert(gcd(270,405) == 135);
+ assert(gcd(15,25) == 5);
+ assert(gcd(15,27) == 3);
+ assert(gcd(270,405) == 135);
}
test_gcd();
module test_lcm() {
- assert(lcm(15,25) == 75);
- assert(lcm(15,27) == 135);
- assert(lcm(270,405) == 810);
+ assert(lcm(15,25) == 75);
+ assert(lcm(15,27) == 135);
+ assert(lcm(270,405) == 810);
}
test_lcm();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_primitives.scad b/tests/test_primitives.scad
index 2a15d25..c80ccf7 100644
--- a/tests/test_primitives.scad
+++ b/tests/test_primitives.scad
@@ -2,27 +2,27 @@ include
module test_square() {
- assert(square(100, center=true) == [[50,-50],[-50,-50],[-50,50],[50,50]]);
- assert(square(100, center=false) == [[100,0],[0,0],[0,100],[100,100]]);
- assert(square(100, anchor=FWD+LEFT) == [[100,0],[0,0],[0,100],[100,100]]);
- assert(square(100, anchor=BACK+RIGHT) == [[0,-100],[-100,-100],[-100,0],[0,0]]);
+ assert(square(100, center=true) == [[50,-50],[-50,-50],[-50,50],[50,50]]);
+ assert(square(100, center=false) == [[100,0],[0,0],[0,100],[100,100]]);
+ assert(square(100, anchor=FWD+LEFT) == [[100,0],[0,0],[0,100],[100,100]]);
+ assert(square(100, anchor=BACK+RIGHT) == [[0,-100],[-100,-100],[-100,0],[0,0]]);
}
test_square();
module test_circle() {
- for (pt = circle(d=200)) {
- assert(approx(norm(pt),100));
- }
- for (pt = circle(r=100)) {
- assert(approx(norm(pt),100));
- }
- assert(polygon_is_clockwise(circle(d=200)));
- assert(polygon_is_clockwise(circle(r=100)));
- assert(len(circle(d=100,$fn=6)) == 6);
- assert(len(circle(d=100,$fn=36)) == 36);
+ for (pt = circle(d=200)) {
+ assert(approx(norm(pt),100));
+ }
+ for (pt = circle(r=100)) {
+ assert(approx(norm(pt),100));
+ }
+ assert(polygon_is_clockwise(circle(d=200)));
+ assert(polygon_is_clockwise(circle(r=100)));
+ assert(len(circle(d=100,$fn=6)) == 6);
+ assert(len(circle(d=100,$fn=36)) == 36);
}
test_circle();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_quaternions.scad b/tests/test_quaternions.scad
index 4aeb08c..44eb85e 100644
--- a/tests/test_quaternions.scad
+++ b/tests/test_quaternions.scad
@@ -3,283 +3,283 @@ include
function rec_cmp(a,b,eps=1e-9) =
- typeof(a)!=typeof(b)? false :
- is_num(a)? approx(a,b,eps=eps) :
- is_list(a)? len(a)==len(b) && all([for (i=idx(a)) rec_cmp(a[i],b[i],eps=eps)]) :
- a == b;
+ typeof(a)!=typeof(b)? false :
+ is_num(a)? approx(a,b,eps=eps) :
+ is_list(a)? len(a)==len(b) && all([for (i=idx(a)) rec_cmp(a[i],b[i],eps=eps)]) :
+ a == b;
module verify_f(actual,expected) {
- if (!rec_cmp(actual,expected)) {
- echo(str("Expected: ",fmt_float(expected,10)));
- echo(str(" : ",expected));
- echo(str("Actual : ",fmt_float(actual,10)));
- echo(str(" : ",actual));
- echo(str("Delta : ",fmt_float(expected-actual,10)));
- echo(str(" : ",expected-actual));
- assert(approx(expected,actual));
- }
+ if (!rec_cmp(actual,expected)) {
+ echo(str("Expected: ",fmt_float(expected,10)));
+ echo(str(" : ",expected));
+ echo(str("Actual : ",fmt_float(actual,10)));
+ echo(str(" : ",actual));
+ echo(str("Delta : ",fmt_float(expected-actual,10)));
+ echo(str(" : ",expected-actual));
+ assert(approx(expected,actual));
+ }
}
module test_Quat() {
- verify_f(Quat(UP,0),[0,0,0,1]);
- verify_f(Quat(FWD,0),[0,0,0,1]);
- verify_f(Quat(LEFT,0),[0,0,0,1]);
- verify_f(Quat(UP,45),[0,0,0.3826834324,0.9238795325]);
- verify_f(Quat(LEFT,45),[-0.3826834324, 0, 0, 0.9238795325]);
- verify_f(Quat(BACK,45),[0,0.3826834323,0,0.9238795325]);
- verify_f(Quat(FWD+RIGHT,30),[0.1830127019, -0.1830127019, 0, 0.9659258263]);
+ verify_f(Quat(UP,0),[0,0,0,1]);
+ verify_f(Quat(FWD,0),[0,0,0,1]);
+ verify_f(Quat(LEFT,0),[0,0,0,1]);
+ verify_f(Quat(UP,45),[0,0,0.3826834324,0.9238795325]);
+ verify_f(Quat(LEFT,45),[-0.3826834324, 0, 0, 0.9238795325]);
+ verify_f(Quat(BACK,45),[0,0.3826834323,0,0.9238795325]);
+ verify_f(Quat(FWD+RIGHT,30),[0.1830127019, -0.1830127019, 0, 0.9659258263]);
}
test_Quat();
module test_QuatX() {
- verify_f(QuatX(0),[0,0,0,1]);
- verify_f(QuatX(35),[0.3007057995,0,0,0.9537169507]);
- verify_f(QuatX(45),[0.3826834324,0,0,0.9238795325]);
+ verify_f(QuatX(0),[0,0,0,1]);
+ verify_f(QuatX(35),[0.3007057995,0,0,0.9537169507]);
+ verify_f(QuatX(45),[0.3826834324,0,0,0.9238795325]);
}
test_QuatX();
module test_QuatY() {
- verify_f(QuatY(0),[0,0,0,1]);
- verify_f(QuatY(35),[0,0.3007057995,0,0.9537169507]);
- verify_f(QuatY(45),[0,0.3826834323,0,0.9238795325]);
+ verify_f(QuatY(0),[0,0,0,1]);
+ verify_f(QuatY(35),[0,0.3007057995,0,0.9537169507]);
+ verify_f(QuatY(45),[0,0.3826834323,0,0.9238795325]);
}
test_QuatY();
module test_QuatZ() {
- verify_f(QuatZ(0),[0,0,0,1]);
- verify_f(QuatZ(36),[0,0,0.3090169944,0.9510565163]);
- verify_f(QuatZ(45),[0,0,0.3826834324,0.9238795325]);
+ verify_f(QuatZ(0),[0,0,0,1]);
+ verify_f(QuatZ(36),[0,0,0.3090169944,0.9510565163]);
+ verify_f(QuatZ(45),[0,0,0.3826834324,0.9238795325]);
}
test_QuatZ();
module test_QuatXYZ() {
- verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
- verify_f(QuatXYZ([30,0,0]), [0.2588190451, 0, 0, 0.9659258263]);
- verify_f(QuatXYZ([90,0,0]), [0.7071067812, 0, 0, 0.7071067812]);
- verify_f(QuatXYZ([-270,0,0]), [-0.7071067812, 0, 0, -0.7071067812]);
- verify_f(QuatXYZ([180,0,0]), [1,0,0,0]);
- verify_f(QuatXYZ([270,0,0]), [0.7071067812, 0, 0, -0.7071067812]);
- verify_f(QuatXYZ([-90,0,0]), [-0.7071067812, 0, 0, 0.7071067812]);
- verify_f(QuatXYZ([360,0,0]), [0,0,0,-1]);
+ verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
+ verify_f(QuatXYZ([30,0,0]), [0.2588190451, 0, 0, 0.9659258263]);
+ verify_f(QuatXYZ([90,0,0]), [0.7071067812, 0, 0, 0.7071067812]);
+ verify_f(QuatXYZ([-270,0,0]), [-0.7071067812, 0, 0, -0.7071067812]);
+ verify_f(QuatXYZ([180,0,0]), [1,0,0,0]);
+ verify_f(QuatXYZ([270,0,0]), [0.7071067812, 0, 0, -0.7071067812]);
+ verify_f(QuatXYZ([-90,0,0]), [-0.7071067812, 0, 0, 0.7071067812]);
+ verify_f(QuatXYZ([360,0,0]), [0,0,0,-1]);
- verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
- verify_f(QuatXYZ([0,30,0]), [0, 0.2588190451, 0, 0.9659258263]);
- verify_f(QuatXYZ([0,90,0]), [0, 0.7071067812, 0, 0.7071067812]);
- verify_f(QuatXYZ([0,-270,0]), [0, -0.7071067812, 0, -0.7071067812]);
- verify_f(QuatXYZ([0,180,0]), [0,1,0,0]);
- verify_f(QuatXYZ([0,270,0]), [0, 0.7071067812, 0, -0.7071067812]);
- verify_f(QuatXYZ([0,-90,0]), [0, -0.7071067812, 0, 0.7071067812]);
- verify_f(QuatXYZ([0,360,0]), [0,0,0,-1]);
+ verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
+ verify_f(QuatXYZ([0,30,0]), [0, 0.2588190451, 0, 0.9659258263]);
+ verify_f(QuatXYZ([0,90,0]), [0, 0.7071067812, 0, 0.7071067812]);
+ verify_f(QuatXYZ([0,-270,0]), [0, -0.7071067812, 0, -0.7071067812]);
+ verify_f(QuatXYZ([0,180,0]), [0,1,0,0]);
+ verify_f(QuatXYZ([0,270,0]), [0, 0.7071067812, 0, -0.7071067812]);
+ verify_f(QuatXYZ([0,-90,0]), [0, -0.7071067812, 0, 0.7071067812]);
+ verify_f(QuatXYZ([0,360,0]), [0,0,0,-1]);
- verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
- verify_f(QuatXYZ([0,0,30]), [0, 0, 0.2588190451, 0.9659258263]);
- verify_f(QuatXYZ([0,0,90]), [0, 0, 0.7071067812, 0.7071067812]);
- verify_f(QuatXYZ([0,0,-270]), [0, 0, -0.7071067812, -0.7071067812]);
- verify_f(QuatXYZ([0,0,180]), [0,0,1,0]);
- verify_f(QuatXYZ([0,0,270]), [0, 0, 0.7071067812, -0.7071067812]);
- verify_f(QuatXYZ([0,0,-90]), [0, 0, -0.7071067812, 0.7071067812]);
- verify_f(QuatXYZ([0,0,360]), [0,0,0,-1]);
+ verify_f(QuatXYZ([0,0,0]), [0,0,0,1]);
+ verify_f(QuatXYZ([0,0,30]), [0, 0, 0.2588190451, 0.9659258263]);
+ verify_f(QuatXYZ([0,0,90]), [0, 0, 0.7071067812, 0.7071067812]);
+ verify_f(QuatXYZ([0,0,-270]), [0, 0, -0.7071067812, -0.7071067812]);
+ verify_f(QuatXYZ([0,0,180]), [0,0,1,0]);
+ verify_f(QuatXYZ([0,0,270]), [0, 0, 0.7071067812, -0.7071067812]);
+ verify_f(QuatXYZ([0,0,-90]), [0, 0, -0.7071067812, 0.7071067812]);
+ verify_f(QuatXYZ([0,0,360]), [0,0,0,-1]);
- verify_f(QuatXYZ([30,30,30]), [0.1767766953, 0.3061862178, 0.1767766953, 0.9185586535]);
- verify_f(QuatXYZ([12,34,56]), [-0.04824789229, 0.3036636044, 0.4195145429, 0.8540890495]);
+ verify_f(QuatXYZ([30,30,30]), [0.1767766953, 0.3061862178, 0.1767766953, 0.9185586535]);
+ verify_f(QuatXYZ([12,34,56]), [-0.04824789229, 0.3036636044, 0.4195145429, 0.8540890495]);
}
test_QuatXYZ();
module test_Q_Ident() {
- verify_f(Q_Ident(), [0,0,0,1]);
+ verify_f(Q_Ident(), [0,0,0,1]);
}
test_Q_Ident();
module test_Q_Add_S() {
- verify_f(Q_Add_S([0,0,0,1],3),[0,0,0,4]);
- verify_f(Q_Add_S([0,0,1,0],3),[0,0,1,3]);
- verify_f(Q_Add_S([0,1,0,0],3),[0,1,0,3]);
- verify_f(Q_Add_S([1,0,0,0],3),[1,0,0,3]);
- verify_f(Q_Add_S(Quat(LEFT+FWD,23),1),[-0.1409744184, -0.1409744184, 0, 1.979924705]);
+ verify_f(Q_Add_S([0,0,0,1],3),[0,0,0,4]);
+ verify_f(Q_Add_S([0,0,1,0],3),[0,0,1,3]);
+ verify_f(Q_Add_S([0,1,0,0],3),[0,1,0,3]);
+ verify_f(Q_Add_S([1,0,0,0],3),[1,0,0,3]);
+ verify_f(Q_Add_S(Quat(LEFT+FWD,23),1),[-0.1409744184, -0.1409744184, 0, 1.979924705]);
}
test_Q_Add_S();
module test_Q_Sub_S() {
- verify_f(Q_Sub_S([0,0,0,1],3),[0,0,0,-2]);
- verify_f(Q_Sub_S([0,0,1,0],3),[0,0,1,-3]);
- verify_f(Q_Sub_S([0,1,0,0],3),[0,1,0,-3]);
- verify_f(Q_Sub_S([1,0,0,0],3),[1,0,0,-3]);
- verify_f(Q_Sub_S(Quat(LEFT+FWD,23),1),[-0.1409744184, -0.1409744184, 0, -0.02007529538]);
+ verify_f(Q_Sub_S([0,0,0,1],3),[0,0,0,-2]);
+ verify_f(Q_Sub_S([0,0,1,0],3),[0,0,1,-3]);
+ verify_f(Q_Sub_S([0,1,0,0],3),[0,1,0,-3]);
+ verify_f(Q_Sub_S([1,0,0,0],3),[1,0,0,-3]);
+ verify_f(Q_Sub_S(Quat(LEFT+FWD,23),1),[-0.1409744184, -0.1409744184, 0, -0.02007529538]);
}
test_Q_Sub_S();
module test_Q_Mul_S() {
- verify_f(Q_Mul_S([0,0,0,1],3),[0,0,0,3]);
- verify_f(Q_Mul_S([0,0,1,0],3),[0,0,3,0]);
- verify_f(Q_Mul_S([0,1,0,0],3),[0,3,0,0]);
- verify_f(Q_Mul_S([1,0,0,0],3),[3,0,0,0]);
- verify_f(Q_Mul_S([1,0,0,1],3),[3,0,0,3]);
- verify_f(Q_Mul_S(Quat(LEFT+FWD,23),4),[-0.5638976735, -0.5638976735, 0, 3.919698818]);
+ verify_f(Q_Mul_S([0,0,0,1],3),[0,0,0,3]);
+ verify_f(Q_Mul_S([0,0,1,0],3),[0,0,3,0]);
+ verify_f(Q_Mul_S([0,1,0,0],3),[0,3,0,0]);
+ verify_f(Q_Mul_S([1,0,0,0],3),[3,0,0,0]);
+ verify_f(Q_Mul_S([1,0,0,1],3),[3,0,0,3]);
+ verify_f(Q_Mul_S(Quat(LEFT+FWD,23),4),[-0.5638976735, -0.5638976735, 0, 3.919698818]);
}
test_Q_Mul_S();
module test_Q_Div_S() {
- verify_f(Q_Div_S([0,0,0,1],3),[0,0,0,1/3]);
- verify_f(Q_Div_S([0,0,1,0],3),[0,0,1/3,0]);
- verify_f(Q_Div_S([0,1,0,0],3),[0,1/3,0,0]);
- verify_f(Q_Div_S([1,0,0,0],3),[1/3,0,0,0]);
- verify_f(Q_Div_S([1,0,0,1],3),[1/3,0,0,1/3]);
- verify_f(Q_Div_S(Quat(LEFT+FWD,23),4),[-0.03524360459, -0.03524360459, 0, 0.2449811762]);
+ verify_f(Q_Div_S([0,0,0,1],3),[0,0,0,1/3]);
+ verify_f(Q_Div_S([0,0,1,0],3),[0,0,1/3,0]);
+ verify_f(Q_Div_S([0,1,0,0],3),[0,1/3,0,0]);
+ verify_f(Q_Div_S([1,0,0,0],3),[1/3,0,0,0]);
+ verify_f(Q_Div_S([1,0,0,1],3),[1/3,0,0,1/3]);
+ verify_f(Q_Div_S(Quat(LEFT+FWD,23),4),[-0.03524360459, -0.03524360459, 0, 0.2449811762]);
}
test_Q_Div_S();
module test_Q_Add() {
- verify_f(Q_Add([2,3,4,5],[-1,-1,-1,-1]),[1,2,3,4]);
- verify_f(Q_Add([2,3,4,5],[-3,-3,-3,-3]),[-1,0,1,2]);
- verify_f(Q_Add([2,3,4,5],[0,0,0,0]),[2,3,4,5]);
- verify_f(Q_Add([2,3,4,5],[1,1,1,1]),[3,4,5,6]);
- verify_f(Q_Add([2,3,4,5],[1,0,0,0]),[3,3,4,5]);
- verify_f(Q_Add([2,3,4,5],[0,1,0,0]),[2,4,4,5]);
- verify_f(Q_Add([2,3,4,5],[0,0,1,0]),[2,3,5,5]);
- verify_f(Q_Add([2,3,4,5],[0,0,0,1]),[2,3,4,6]);
- verify_f(Q_Add([2,3,4,5],[2,1,2,1]),[4,4,6,6]);
- verify_f(Q_Add([2,3,4,5],[1,2,1,2]),[3,5,5,7]);
+ verify_f(Q_Add([2,3,4,5],[-1,-1,-1,-1]),[1,2,3,4]);
+ verify_f(Q_Add([2,3,4,5],[-3,-3,-3,-3]),[-1,0,1,2]);
+ verify_f(Q_Add([2,3,4,5],[0,0,0,0]),[2,3,4,5]);
+ verify_f(Q_Add([2,3,4,5],[1,1,1,1]),[3,4,5,6]);
+ verify_f(Q_Add([2,3,4,5],[1,0,0,0]),[3,3,4,5]);
+ verify_f(Q_Add([2,3,4,5],[0,1,0,0]),[2,4,4,5]);
+ verify_f(Q_Add([2,3,4,5],[0,0,1,0]),[2,3,5,5]);
+ verify_f(Q_Add([2,3,4,5],[0,0,0,1]),[2,3,4,6]);
+ verify_f(Q_Add([2,3,4,5],[2,1,2,1]),[4,4,6,6]);
+ verify_f(Q_Add([2,3,4,5],[1,2,1,2]),[3,5,5,7]);
}
test_Q_Add();
module test_Q_Sub() {
- verify_f(Q_Sub([2,3,4,5],[-1,-1,-1,-1]),[3,4,5,6]);
- verify_f(Q_Sub([2,3,4,5],[-3,-3,-3,-3]),[5,6,7,8]);
- verify_f(Q_Sub([2,3,4,5],[0,0,0,0]),[2,3,4,5]);
- verify_f(Q_Sub([2,3,4,5],[1,1,1,1]),[1,2,3,4]);
- verify_f(Q_Sub([2,3,4,5],[1,0,0,0]),[1,3,4,5]);
- verify_f(Q_Sub([2,3,4,5],[0,1,0,0]),[2,2,4,5]);
- verify_f(Q_Sub([2,3,4,5],[0,0,1,0]),[2,3,3,5]);
- verify_f(Q_Sub([2,3,4,5],[0,0,0,1]),[2,3,4,4]);
- verify_f(Q_Sub([2,3,4,5],[2,1,2,1]),[0,2,2,4]);
- verify_f(Q_Sub([2,3,4,5],[1,2,1,2]),[1,1,3,3]);
+ verify_f(Q_Sub([2,3,4,5],[-1,-1,-1,-1]),[3,4,5,6]);
+ verify_f(Q_Sub([2,3,4,5],[-3,-3,-3,-3]),[5,6,7,8]);
+ verify_f(Q_Sub([2,3,4,5],[0,0,0,0]),[2,3,4,5]);
+ verify_f(Q_Sub([2,3,4,5],[1,1,1,1]),[1,2,3,4]);
+ verify_f(Q_Sub([2,3,4,5],[1,0,0,0]),[1,3,4,5]);
+ verify_f(Q_Sub([2,3,4,5],[0,1,0,0]),[2,2,4,5]);
+ verify_f(Q_Sub([2,3,4,5],[0,0,1,0]),[2,3,3,5]);
+ verify_f(Q_Sub([2,3,4,5],[0,0,0,1]),[2,3,4,4]);
+ verify_f(Q_Sub([2,3,4,5],[2,1,2,1]),[0,2,2,4]);
+ verify_f(Q_Sub([2,3,4,5],[1,2,1,2]),[1,1,3,3]);
}
test_Q_Sub();
module test_Q_Mul() {
- verify_f(Q_Mul(QuatZ(30),QuatX(57)),[0.4608999698, 0.1234977747, 0.2274546059, 0.8488721457]);
- verify_f(Q_Mul(QuatY(30),QuatZ(23)),[0.05160021841, 0.2536231763, 0.1925746368, 0.94653458]);
+ verify_f(Q_Mul(QuatZ(30),QuatX(57)),[0.4608999698, 0.1234977747, 0.2274546059, 0.8488721457]);
+ verify_f(Q_Mul(QuatY(30),QuatZ(23)),[0.05160021841, 0.2536231763, 0.1925746368, 0.94653458]);
}
test_Q_Mul();
module test_Q_Dot() {
- verify_f(Q_Dot(QuatZ(30),QuatX(57)),0.8488721457);
- verify_f(Q_Dot(QuatY(30),QuatZ(23)),0.94653458);
+ verify_f(Q_Dot(QuatZ(30),QuatX(57)),0.8488721457);
+ verify_f(Q_Dot(QuatY(30),QuatZ(23)),0.94653458);
}
test_Q_Dot();
module test_Q_Neg() {
- verify_f(Q_Neg([1,0,0,1]),[-1,0,0,-1]);
- verify_f(Q_Neg([0,1,1,0]),[0,-1,-1,0]);
- verify_f(Q_Neg(QuatXYZ([23,45,67])),[0.0533818345,-0.4143703268,-0.4360652669,-0.7970537592]);
+ verify_f(Q_Neg([1,0,0,1]),[-1,0,0,-1]);
+ verify_f(Q_Neg([0,1,1,0]),[0,-1,-1,0]);
+ verify_f(Q_Neg(QuatXYZ([23,45,67])),[0.0533818345,-0.4143703268,-0.4360652669,-0.7970537592]);
}
test_Q_Neg();
module test_Q_Conj() {
- verify_f(Q_Conj([1,0,0,1]),[-1,0,0,1]);
- verify_f(Q_Conj([0,1,1,0]),[0,-1,-1,0]);
- verify_f(Q_Conj(QuatXYZ([23,45,67])),[0.0533818345, -0.4143703268, -0.4360652669, 0.7970537592]);
+ verify_f(Q_Conj([1,0,0,1]),[-1,0,0,1]);
+ verify_f(Q_Conj([0,1,1,0]),[0,-1,-1,0]);
+ verify_f(Q_Conj(QuatXYZ([23,45,67])),[0.0533818345, -0.4143703268, -0.4360652669, 0.7970537592]);
}
test_Q_Conj();
module test_Q_Norm() {
- verify_f(Q_Norm([1,0,0,1]),1.414213562);
- verify_f(Q_Norm([0,1,1,0]),1.414213562);
- verify_f(Q_Norm(QuatXYZ([23,45,67])),1);
+ verify_f(Q_Norm([1,0,0,1]),1.414213562);
+ verify_f(Q_Norm([0,1,1,0]),1.414213562);
+ verify_f(Q_Norm(QuatXYZ([23,45,67])),1);
}
test_Q_Norm();
module test_Q_Normalize() {
- verify_f(Q_Normalize([1,0,0,1]),[0.7071067812, 0, 0, 0.7071067812]);
- verify_f(Q_Normalize([0,1,1,0]),[0, 0.7071067812, 0.7071067812, 0]);
- verify_f(Q_Normalize(QuatXYZ([23,45,67])),[-0.0533818345, 0.4143703268, 0.4360652669, 0.7970537592]);
+ verify_f(Q_Normalize([1,0,0,1]),[0.7071067812, 0, 0, 0.7071067812]);
+ verify_f(Q_Normalize([0,1,1,0]),[0, 0.7071067812, 0.7071067812, 0]);
+ verify_f(Q_Normalize(QuatXYZ([23,45,67])),[-0.0533818345, 0.4143703268, 0.4360652669, 0.7970537592]);
}
test_Q_Normalize();
module test_Q_Dist() {
- verify_f(Q_Dist(QuatXYZ([23,45,67]),QuatXYZ([23,45,67])),0);
- verify_f(Q_Dist(QuatXYZ([23,45,67]),QuatXYZ([12,34,56])),0.1257349854);
+ verify_f(Q_Dist(QuatXYZ([23,45,67]),QuatXYZ([23,45,67])),0);
+ verify_f(Q_Dist(QuatXYZ([23,45,67]),QuatXYZ([12,34,56])),0.1257349854);
}
test_Q_Dist();
module test_Q_Slerp() {
- verify_f(Q_Slerp(QuatX(45),QuatY(30),0.0),QuatX(45));
- verify_f(Q_Slerp(QuatX(45),QuatY(30),0.5),[0.1967063121, 0.1330377423, 0, 0.9713946602]);
- verify_f(Q_Slerp(QuatX(45),QuatY(30),1.0),QuatY(30));
+ verify_f(Q_Slerp(QuatX(45),QuatY(30),0.0),QuatX(45));
+ verify_f(Q_Slerp(QuatX(45),QuatY(30),0.5),[0.1967063121, 0.1330377423, 0, 0.9713946602]);
+ verify_f(Q_Slerp(QuatX(45),QuatY(30),1.0),QuatY(30));
}
test_Q_Slerp();
module test_Q_Matrix3() {
- verify_f(Q_Matrix3(QuatZ(37)),rot(37,planar=true));
- verify_f(Q_Matrix3(QuatZ(-49)),rot(-49,planar=true));
+ verify_f(Q_Matrix3(QuatZ(37)),rot(37,planar=true));
+ verify_f(Q_Matrix3(QuatZ(-49)),rot(-49,planar=true));
}
test_Q_Matrix3();
module test_Q_Matrix4() {
- verify_f(Q_Matrix4(QuatZ(37)),rot(37));
- verify_f(Q_Matrix4(QuatZ(-49)),rot(-49));
- verify_f(Q_Matrix4(QuatX(37)),rot([37,0,0]));
- verify_f(Q_Matrix4(QuatY(37)),rot([0,37,0]));
- verify_f(Q_Matrix4(QuatXYZ([12,34,56])),rot([12,34,56]));
+ verify_f(Q_Matrix4(QuatZ(37)),rot(37));
+ verify_f(Q_Matrix4(QuatZ(-49)),rot(-49));
+ verify_f(Q_Matrix4(QuatX(37)),rot([37,0,0]));
+ verify_f(Q_Matrix4(QuatY(37)),rot([0,37,0]));
+ verify_f(Q_Matrix4(QuatXYZ([12,34,56])),rot([12,34,56]));
}
test_Q_Matrix4();
module test_Q_Axis() {
- verify_f(Q_Axis(QuatX(37)),RIGHT);
- verify_f(Q_Axis(QuatX(-37)),LEFT);
- verify_f(Q_Axis(QuatY(37)),BACK);
- verify_f(Q_Axis(QuatY(-37)),FWD);
- verify_f(Q_Axis(QuatZ(37)),UP);
- verify_f(Q_Axis(QuatZ(-37)),DOWN);
+ verify_f(Q_Axis(QuatX(37)),RIGHT);
+ verify_f(Q_Axis(QuatX(-37)),LEFT);
+ verify_f(Q_Axis(QuatY(37)),BACK);
+ verify_f(Q_Axis(QuatY(-37)),FWD);
+ verify_f(Q_Axis(QuatZ(37)),UP);
+ verify_f(Q_Axis(QuatZ(-37)),DOWN);
}
test_Q_Axis();
module test_Q_Angle() {
- verify_f(Q_Angle(QuatX(0)),0);
- verify_f(Q_Angle(QuatY(0)),0);
- verify_f(Q_Angle(QuatZ(0)),0);
- verify_f(Q_Angle(QuatX(37)),37);
- verify_f(Q_Angle(QuatX(-37)),37);
- verify_f(Q_Angle(QuatY(37)),37);
- verify_f(Q_Angle(QuatY(-37)),37);
- verify_f(Q_Angle(QuatZ(37)),37);
- verify_f(Q_Angle(QuatZ(-37)),37);
+ verify_f(Q_Angle(QuatX(0)),0);
+ verify_f(Q_Angle(QuatY(0)),0);
+ verify_f(Q_Angle(QuatZ(0)),0);
+ verify_f(Q_Angle(QuatX(37)),37);
+ verify_f(Q_Angle(QuatX(-37)),37);
+ verify_f(Q_Angle(QuatY(37)),37);
+ verify_f(Q_Angle(QuatY(-37)),37);
+ verify_f(Q_Angle(QuatZ(37)),37);
+ verify_f(Q_Angle(QuatZ(-37)),37);
}
test_Q_Angle();
module test_Qrot() {
- verify_f(Qrot(QuatXYZ([12,34,56])),rot([12,34,56]));
- verify_f(Qrot(QuatXYZ([12,34,56]),p=[2,3,4]),rot([12,34,56],p=[2,3,4]));
- verify_f(Qrot(QuatXYZ([12,34,56]),p=[[2,3,4],[4,9,6]]),rot([12,34,56],p=[[2,3,4],[4,9,6]]));
+ verify_f(Qrot(QuatXYZ([12,34,56])),rot([12,34,56]));
+ verify_f(Qrot(QuatXYZ([12,34,56]),p=[2,3,4]),rot([12,34,56],p=[2,3,4]));
+ verify_f(Qrot(QuatXYZ([12,34,56]),p=[[2,3,4],[4,9,6]]),rot([12,34,56],p=[[2,3,4],[4,9,6]]));
}
test_Qrot();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_queues.scad b/tests/test_queues.scad
index bda43cb..cf45eef 100644
--- a/tests/test_queues.scad
+++ b/tests/test_queues.scad
@@ -3,75 +3,75 @@ include
module test_queue_init() {
- assert(queue_init()==[]);
+ assert(queue_init()==[]);
}
test_queue_init();
module test_queue_empty() {
- assert(queue_empty([]));
- assert(!queue_empty([3]));
- assert(!queue_empty([2,4,8]));
+ assert(queue_empty([]));
+ assert(!queue_empty([3]));
+ assert(!queue_empty([2,4,8]));
}
test_queue_empty();
module test_queue_size() {
- assert(queue_size([]) == 0);
- assert(queue_size([3]) == 1);
- assert(queue_size([2,4,8]) == 3);
+ assert(queue_size([]) == 0);
+ assert(queue_size([3]) == 1);
+ assert(queue_size([2,4,8]) == 3);
}
test_queue_size();
module test_queue_head() {
- assert(queue_head([]) == undef);
- assert(queue_head([3,5,7,9]) == 3);
- assert(queue_head([3,5,7,9], 3) == [3,5,7]);
+ assert(queue_head([]) == undef);
+ assert(queue_head([3,5,7,9]) == 3);
+ assert(queue_head([3,5,7,9], 3) == [3,5,7]);
}
test_queue_head();
module test_queue_tail() {
- assert(queue_tail([]) == undef);
- assert(queue_tail([3,5,7,9]) == 9);
- assert(queue_tail([3,5,7,9], 3) == [5,7,9]);
+ assert(queue_tail([]) == undef);
+ assert(queue_tail([3,5,7,9]) == 9);
+ assert(queue_tail([3,5,7,9], 3) == [5,7,9]);
}
test_queue_tail();
module test_queue_peek() {
- q = [8,5,4,3,2,3,7];
- assert(queue_peek(q,0) == 8);
- assert(queue_peek(q,2) == 4);
- assert(queue_peek(q,2,1) == [4]);
- assert(queue_peek(q,2,3) == [4,3,2]);
+ q = [8,5,4,3,2,3,7];
+ assert(queue_peek(q,0) == 8);
+ assert(queue_peek(q,2) == 4);
+ assert(queue_peek(q,2,1) == [4]);
+ assert(queue_peek(q,2,3) == [4,3,2]);
}
test_queue_peek();
module test_queue_add() {
- q1 = queue_init();
- q2 = queue_add(q1, "Foo");
- assert(q2==["Foo"]);
- q3 = queue_add(q2, "Bar");
- assert(q3==["Foo","Bar"]);
- q4 = queue_add(q3, "Baz");
- assert(q4==["Foo","Bar","Baz"]);
+ q1 = queue_init();
+ q2 = queue_add(q1, "Foo");
+ assert(q2==["Foo"]);
+ q3 = queue_add(q2, "Bar");
+ assert(q3==["Foo","Bar"]);
+ q4 = queue_add(q3, "Baz");
+ assert(q4==["Foo","Bar","Baz"]);
}
test_queue_add();
module test_queue_pop() {
- q = ["Foo", "Bar", "Baz", "Qux"];
- q1 = queue_pop(q);
- assert(q1 == ["Bar", "Baz", "Qux"]);
- q2 = queue_pop(q,2);
- assert(q2 == ["Baz", "Qux"]);
- q3 = queue_pop(q,3);
- assert(q3 == ["Qux"]);
+ q = ["Foo", "Bar", "Baz", "Qux"];
+ q1 = queue_pop(q);
+ assert(q1 == ["Bar", "Baz", "Qux"]);
+ q2 = queue_pop(q,2);
+ assert(q2 == ["Baz", "Qux"]);
+ q3 = queue_pop(q,3);
+ assert(q3 == ["Qux"]);
}
test_queue_pop();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_skin.scad b/tests/test_skin.scad
index 767ffb4..a799240 100644
--- a/tests/test_skin.scad
+++ b/tests/test_skin.scad
@@ -3,17 +3,17 @@ include
module test_skin() {
- profiles = [
- [[-100,-100,0], [0,100,0], [100,-100,0]],
- [[-100,-100,100], [-100,100,100], [100,100,100], [100,-100,100]],
- ];
- vnf1 = skin(profiles, caps=false, method="distance");
- assert(vnf1 == [[[-100,-100,0],[-100,100,100],[-100,-100,100],[0,100,0],[100,100,100],[100,-100,0],[100,-100,100]],[[0,1,2],[0,3,1],[3,4,1],[3,5,4],[5,6,4],[5,2,6],[5,0,2]]]);
- vnf2 = skin(profiles, caps=true, method="distance");
- assert(vnf2 == [[[-100,-100,0],[-100,100,100],[-100,-100,100],[0,100,0],[100,100,100],[100,-100,0],[100,-100,100],[100,-100,0],[0,100,0],[-100,-100,0],[-100,-100,100],[-100,100,100],[100,100,100],[100,-100,100]],[[0,1,2],[0,3,1],[3,4,1],[3,5,4],[5,6,4],[5,2,6],[5,0,2],[7,8,9],[10,11,12],[12,13,10]]]);
- vnf_polyhedron(vnf2);
+ profiles = [
+ [[-100,-100,0], [0,100,0], [100,-100,0]],
+ [[-100,-100,100], [-100,100,100], [100,100,100], [100,-100,100]],
+ ];
+ vnf1 = skin(profiles, caps=false, method="distance");
+ assert(vnf1 == [[[-100,-100,0],[-100,100,100],[-100,-100,100],[0,100,0],[100,100,100],[100,-100,0],[100,-100,100]],[[0,1,2],[0,3,1],[3,4,1],[3,5,4],[5,6,4],[5,2,6],[5,0,2]]]);
+ vnf2 = skin(profiles, caps=true, method="distance");
+ assert(vnf2 == [[[-100,-100,0],[-100,100,100],[-100,-100,100],[0,100,0],[100,100,100],[100,-100,0],[100,-100,100],[100,-100,0],[0,100,0],[-100,-100,0],[-100,-100,100],[-100,100,100],[100,100,100],[100,-100,100]],[[0,1,2],[0,3,1],[3,4,1],[3,5,4],[5,6,4],[5,2,6],[5,0,2],[7,8,9],[10,11,12],[12,13,10]]]);
+ vnf_polyhedron(vnf2);
}
test_skin();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_stacks.scad b/tests/test_stacks.scad
index e261093..3f3f0d2 100644
--- a/tests/test_stacks.scad
+++ b/tests/test_stacks.scad
@@ -3,77 +3,77 @@ include
module test_stack_init() {
- assert(stack_init()==[]);
+ assert(stack_init()==[]);
}
test_stack_init();
module test_stack_empty() {
- assert(stack_empty([]));
- assert(!stack_empty([3]));
- assert(!stack_empty([2,4,8]));
+ assert(stack_empty([]));
+ assert(!stack_empty([3]));
+ assert(!stack_empty([2,4,8]));
}
test_stack_empty();
module test_stack_depth() {
- assert(stack_depth([]) == 0);
- assert(stack_depth([3]) == 1);
- assert(stack_depth([2,4,8]) == 3);
+ assert(stack_depth([]) == 0);
+ assert(stack_depth([3]) == 1);
+ assert(stack_depth([2,4,8]) == 3);
}
test_stack_depth();
module test_stack_top() {
- assert(stack_top([]) == undef);
- assert(stack_top([3,5,7,9]) == 9);
- assert(stack_top([3,5,7,9], 3) == [5,7,9]);
+ assert(stack_top([]) == undef);
+ assert(stack_top([3,5,7,9]) == 9);
+ assert(stack_top([3,5,7,9], 3) == [5,7,9]);
}
test_stack_top();
module test_stack_peek() {
- s = [8,5,4,3,2,3,7];
- assert(stack_peek(s,0) == 7);
- assert(stack_peek(s,2) == 2);
- assert(stack_peek(s,2,1) == [2]);
- assert(stack_peek(s,2,3) == [2,3,7]);
+ s = [8,5,4,3,2,3,7];
+ assert(stack_peek(s,0) == 7);
+ assert(stack_peek(s,2) == 2);
+ assert(stack_peek(s,2,1) == [2]);
+ assert(stack_peek(s,2,3) == [2,3,7]);
}
test_stack_peek();
module test_stack_push() {
- s1 = stack_init();
- s2 = stack_push(s1, "Foo");
- assert(s2==["Foo"]);
- s3 = stack_push(s2, "Bar");
- assert(s3==["Foo","Bar"]);
- s4 = stack_push(s3, "Baz");
- assert(s4==["Foo","Bar","Baz"]);
+ s1 = stack_init();
+ s2 = stack_push(s1, "Foo");
+ assert(s2==["Foo"]);
+ s3 = stack_push(s2, "Bar");
+ assert(s3==["Foo","Bar"]);
+ s4 = stack_push(s3, "Baz");
+ assert(s4==["Foo","Bar","Baz"]);
}
test_stack_push();
module test_stack_pop() {
- s = ["Foo", "Bar", "Baz", "Qux"];
- s1 = stack_pop(s);
- assert(s1 == ["Foo", "Bar", "Baz"]);
- s2 = stack_pop(s,2);
- assert(s2 == ["Foo", "Bar"]);
- s3 = stack_pop(s,3);
- assert(s3 == ["Foo"]);
+ s = ["Foo", "Bar", "Baz", "Qux"];
+ s1 = stack_pop(s);
+ assert(s1 == ["Foo", "Bar", "Baz"]);
+ s2 = stack_pop(s,2);
+ assert(s2 == ["Foo", "Bar"]);
+ s3 = stack_pop(s,3);
+ assert(s3 == ["Foo"]);
}
test_stack_pop();
module test_stack_rotate() {
- s = ["Foo", "Bar", "Baz", "Qux", "Quux"];
- s1 = stack_rotate(s,4);
- assert(s1 == ["Foo", "Baz", "Qux", "Quux", "Bar"]);
- s2 = stack_rotate(s,-4);
- assert(s2 == ["Foo", "Quux", "Bar", "Baz", "Qux"]);
+ s = ["Foo", "Bar", "Baz", "Qux", "Quux"];
+ s1 = stack_rotate(s,4);
+ assert(s1 == ["Foo", "Baz", "Qux", "Quux", "Bar"]);
+ s2 = stack_rotate(s,-4);
+ assert(s2 == ["Foo", "Quux", "Bar", "Baz", "Qux"]);
}
test_stack_rotate();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_structs.scad b/tests/test_structs.scad
index 147990a..55db3b4 100644
--- a/tests/test_structs.scad
+++ b/tests/test_structs.scad
@@ -3,57 +3,57 @@ include
module test_struct_set() {
- st = struct_set([], "Foo", 42);
- assert(st == [["Foo",42]]);
- st2 = struct_set(st, "Bar", 28);
- assert(st2 == [["Foo",42],["Bar",28]]);
- st3 = struct_set(st2, "Foo", 91);
- assert(st3 == [["Foo",91],["Bar",28]]);
+ st = struct_set([], "Foo", 42);
+ assert(st == [["Foo",42]]);
+ st2 = struct_set(st, "Bar", 28);
+ assert(st2 == [["Foo",42],["Bar",28]]);
+ st3 = struct_set(st2, "Foo", 91);
+ assert(st3 == [["Foo",91],["Bar",28]]);
}
test_struct_set();
module test_struct_remove() {
- st = [["Foo",91],["Bar",28],["Baz",9]];
- assert(struct_remove(st, "Foo") == [["Bar",28],["Baz",9]]);
- assert(struct_remove(st, "Bar") == [["Foo",91],["Baz",9]]);
- assert(struct_remove(st, "Baz") == [["Foo",91],["Bar",28]]);
+ st = [["Foo",91],["Bar",28],["Baz",9]];
+ assert(struct_remove(st, "Foo") == [["Bar",28],["Baz",9]]);
+ assert(struct_remove(st, "Bar") == [["Foo",91],["Baz",9]]);
+ assert(struct_remove(st, "Baz") == [["Foo",91],["Bar",28]]);
}
test_struct_remove();
module test_struct_val() {
- st = [["Foo",91],["Bar",28],["Baz",9]];
- assert(struct_val(st,"Foo") == 91);
- assert(struct_val(st,"Bar") == 28);
- assert(struct_val(st,"Baz") == 9);
+ st = [["Foo",91],["Bar",28],["Baz",9]];
+ assert(struct_val(st,"Foo") == 91);
+ assert(struct_val(st,"Bar") == 28);
+ assert(struct_val(st,"Baz") == 9);
}
test_struct_val();
module test_struct_keys() {
- assert(struct_keys([["Foo",3],["Bar",2],["Baz",1]]) == ["Foo","Bar","Baz"]);
- assert(struct_keys([["Zee",1],["Why",2],["Exx",3]]) == ["Zee","Why","Exx"]);
+ assert(struct_keys([["Foo",3],["Bar",2],["Baz",1]]) == ["Foo","Bar","Baz"]);
+ assert(struct_keys([["Zee",1],["Why",2],["Exx",3]]) == ["Zee","Why","Exx"]);
}
test_struct_keys();
module test_struct_echo() {
- // Can't yet test echo output
+ // Can't yet test echo output
}
test_struct_echo();
module test_is_struct() {
- assert(is_struct([["Foo",1],["Bar",2],["Baz",3]]));
- assert(!is_struct([["Foo"],["Bar"],["Baz"]]));
- assert(!is_struct(["Foo","Bar","Baz"]));
- assert(!is_struct([3,4,5]));
- assert(!is_struct(3));
- assert(!is_struct(true));
- assert(!is_struct("foo"));
+ assert(is_struct([["Foo",1],["Bar",2],["Baz",3]]));
+ assert(!is_struct([["Foo"],["Bar"],["Baz"]]));
+ assert(!is_struct(["Foo","Bar","Baz"]));
+ assert(!is_struct([3,4,5]));
+ assert(!is_struct(3));
+ assert(!is_struct(true));
+ assert(!is_struct("foo"));
}
test_is_struct();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_transforms.scad b/tests/test_transforms.scad
index 1db7ff5..1e2a787 100644
--- a/tests/test_transforms.scad
+++ b/tests/test_transforms.scad
@@ -1,159 +1,159 @@
include
module test(got,expect,extra_info) {
- if (
- is_undef(expect) != is_undef(got) ||
- expect*0 != got*0 ||
- (is_vnf(expect) && !all([for (i=idx(expect[0])) approx(got[0][i],expect[0][i])]) && got[1]!=expect[1]) ||
- (is_matrix(expect) && !all([for (i=idx(expect)) approx(got[i],expect[i])])) ||
- (got!=expect && !approx(got, expect))
- ) {
- fmt = is_int(expect)? "{:.14i}" :
- is_num(expect)? "{:.14g}" :
- is_vector(expect)? "{:.14g}" :
- "{}";
- echofmt(str("Expected: ",fmt),[expect]);
- echofmt(str("But Got : ",fmt),[got]);
- if (expect*0 == got*0) {
- echofmt(str("Delta is: ",fmt),[expect-got]);
- }
- if (!is_undef(extra_info)) {
- echo(str("Extra Info: ",extra_info));
- }
- assert(false, "TEST FAILED!");
- }
+ if (
+ is_undef(expect) != is_undef(got) ||
+ expect*0 != got*0 ||
+ (is_vnf(expect) && !all([for (i=idx(expect[0])) approx(got[0][i],expect[0][i])]) && got[1]!=expect[1]) ||
+ (is_matrix(expect) && !all([for (i=idx(expect)) approx(got[i],expect[i])])) ||
+ (got!=expect && !approx(got, expect))
+ ) {
+ fmt = is_int(expect)? "{:.14i}" :
+ is_num(expect)? "{:.14g}" :
+ is_vector(expect)? "{:.14g}" :
+ "{}";
+ echofmt(str("Expected: ",fmt),[expect]);
+ echofmt(str("But Got : ",fmt),[got]);
+ if (expect*0 == got*0) {
+ echofmt(str("Delta is: ",fmt),[expect-got]);
+ }
+ if (!is_undef(extra_info)) {
+ echo(str("Extra Info: ",extra_info));
+ }
+ assert(false, "TEST FAILED!");
+ }
}
module test_rot() {
- pts2d = 50 * [for (x=[-1,0,1],y=[-1,0,1]) [x,y]];
- pts3d = 50 * [for (x=[-1,0,1],y=[-1,0,1],z=[-1,0,1]) [x,y,z]];
- vecs2d = [
- for (x=[-1,0,1], y=[-1,0,1]) if(x!=0||y!=0) [x,y],
- polar_to_xy(1, -75),
- polar_to_xy(1, 75)
- ];
- vecs3d = [
- LEFT, RIGHT, FRONT, BACK, DOWN, UP,
- spherical_to_xyz(1, -30, 45),
- spherical_to_xyz(1, 0, 45),
- spherical_to_xyz(1, 30, 45),
- spherical_to_xyz(2, 30, 45),
- spherical_to_xyz(1, -30, 135),
- spherical_to_xyz(2, -30, 135),
- spherical_to_xyz(1, 0, 135),
- spherical_to_xyz(1, 30, 135),
- spherical_to_xyz(1, -30, 75),
- spherical_to_xyz(1, 45, 45),
- ];
- angs = [-180, -90, -45, 0, 30, 45, 90];
- for (a = [-360*3:360:360*3]) {
- test(rot(a), affine3d_identity(), extra_info=str("rot(",a,") != identity"));
- test(rot(a,p=pts2d), pts2d, extra_info=str("rot(",a,",p=...), 2D"));
- test(rot(a,p=pts3d), pts3d, extra_info=str("rot(",a,",p=...), 3D"));
- }
- test(rot(90), [[0,-1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]])
- for (a=angs) {
- test(rot(a), affine3d_zrot(a), extra_info=str("Z angle (only) = ",a));
- test(rot([a,0,0]), affine3d_xrot(a), extra_info=str("X angle = ",a));
- test(rot([0,a,0]), affine3d_yrot(a), extra_info=str("Y angle = ",a));
- test(rot([0,0,a]), affine3d_zrot(a), extra_info=str("Z angle = ",a));
+ pts2d = 50 * [for (x=[-1,0,1],y=[-1,0,1]) [x,y]];
+ pts3d = 50 * [for (x=[-1,0,1],y=[-1,0,1],z=[-1,0,1]) [x,y,z]];
+ vecs2d = [
+ for (x=[-1,0,1], y=[-1,0,1]) if(x!=0||y!=0) [x,y],
+ polar_to_xy(1, -75),
+ polar_to_xy(1, 75)
+ ];
+ vecs3d = [
+ LEFT, RIGHT, FRONT, BACK, DOWN, UP,
+ spherical_to_xyz(1, -30, 45),
+ spherical_to_xyz(1, 0, 45),
+ spherical_to_xyz(1, 30, 45),
+ spherical_to_xyz(2, 30, 45),
+ spherical_to_xyz(1, -30, 135),
+ spherical_to_xyz(2, -30, 135),
+ spherical_to_xyz(1, 0, 135),
+ spherical_to_xyz(1, 30, 135),
+ spherical_to_xyz(1, -30, 75),
+ spherical_to_xyz(1, 45, 45),
+ ];
+ angs = [-180, -90, -45, 0, 30, 45, 90];
+ for (a = [-360*3:360:360*3]) {
+ test(rot(a), affine3d_identity(), extra_info=str("rot(",a,") != identity"));
+ test(rot(a,p=pts2d), pts2d, extra_info=str("rot(",a,",p=...), 2D"));
+ test(rot(a,p=pts3d), pts3d, extra_info=str("rot(",a,",p=...), 3D"));
+ }
+ test(rot(90), [[0,-1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]])
+ for (a=angs) {
+ test(rot(a), affine3d_zrot(a), extra_info=str("Z angle (only) = ",a));
+ test(rot([a,0,0]), affine3d_xrot(a), extra_info=str("X angle = ",a));
+ test(rot([0,a,0]), affine3d_yrot(a), extra_info=str("Y angle = ",a));
+ test(rot([0,0,a]), affine3d_zrot(a), extra_info=str("Z angle = ",a));
- test(rot(a,p=pts2d), apply(affine3d_zrot(a),pts2d), extra_info=str("Z angle (only) = ",a, ", p=..., 2D"));
- test(rot([0,0,a],p=pts2d), apply(affine3d_zrot(a),pts2d), extra_info=str("Z angle = ",a, ", p=..., 2D"));
+ test(rot(a,p=pts2d), apply(affine3d_zrot(a),pts2d), extra_info=str("Z angle (only) = ",a, ", p=..., 2D"));
+ test(rot([0,0,a],p=pts2d), apply(affine3d_zrot(a),pts2d), extra_info=str("Z angle = ",a, ", p=..., 2D"));
- test(rot(a,p=pts3d), apply(affine3d_zrot(a),pts3d), extra_info=str("Z angle (only) = ",a, ", p=..., 3D"));
- test(rot([a,0,0],p=pts3d), apply(affine3d_xrot(a),pts3d), extra_info=str("X angle = ",a, ", p=..., 3D"));
- test(rot([0,a,0],p=pts3d), apply(affine3d_yrot(a),pts3d), extra_info=str("Y angle = ",a, ", p=..., 3D"));
- test(rot([0,0,a],p=pts3d), apply(affine3d_zrot(a),pts3d), extra_info=str("Z angle = ",a, ", p=..., 3D"));
- }
- for (xa=angs, ya=angs, za=angs) {
- test(
- rot([xa,ya,za]),
- affine3d_chain([
- affine3d_xrot(xa),
- affine3d_yrot(ya),
- affine3d_zrot(za)
- ]),
- extra_info=str("[X,Y,Z] = ",[xa,ya,za])
- );
- test(
- rot([xa,ya,za],p=pts3d),
- apply(
- affine3d_chain([
- affine3d_xrot(xa),
- affine3d_yrot(ya),
- affine3d_zrot(za)
- ]),
- pts3d
- ),
- extra_info=str("[X,Y,Z] = ",[xa,ya,za], ", p=...")
- );
- }
- for (vec1 = vecs3d) {
- for (ang = angs) {
- test(
- rot(a=ang, v=vec1),
- affine3d_rot_by_axis(vec1,ang),
- extra_info=str("a = ",ang,", v = ", vec1)
- );
- test(
- rot(a=ang, v=vec1, p=pts3d),
- apply(affine3d_rot_by_axis(vec1,ang), pts3d),
- extra_info=str("a = ",ang,", v = ", vec1, ", p=...")
- );
- }
- }
- for (vec1 = vecs2d) {
- for (vec2 = vecs2d) {
- test(
- rot(from=vec1, to=vec2, p=pts2d, planar=true),
- apply(affine2d_zrot(vang(vec2)-vang(vec1)), pts2d),
- extra_info=str(
- "from = ", vec1, ", ",
- "to = ", vec2, ", ",
- "planar = ", true, ", ",
- "p=..., 2D"
- )
- );
- }
- }
- for (vec1 = vecs3d) {
- for (vec2 = vecs3d) {
- for (a = angs) {
- test(
- rot(from=vec1, to=vec2, a=a),
- affine3d_chain([
- affine3d_zrot(a),
- affine3d_rot_from_to(vec1,vec2)
- ]),
- extra_info=str(
- "from = ", vec1, ", ",
- "to = ", vec2, ", ",
- "a = ", a
- )
- );
- test(
- rot(from=vec1, to=vec2, a=a, p=pts3d),
- apply(
- affine3d_chain([
- affine3d_zrot(a),
- affine3d_rot_from_to(vec1,vec2)
- ]),
- pts3d
- ),
- extra_info=str(
- "from = ", vec1, ", ",
- "to = ", vec2, ", ",
- "a = ", a, ", ",
- "p=..., 3D"
- )
- );
- }
- }
- }
+ test(rot(a,p=pts3d), apply(affine3d_zrot(a),pts3d), extra_info=str("Z angle (only) = ",a, ", p=..., 3D"));
+ test(rot([a,0,0],p=pts3d), apply(affine3d_xrot(a),pts3d), extra_info=str("X angle = ",a, ", p=..., 3D"));
+ test(rot([0,a,0],p=pts3d), apply(affine3d_yrot(a),pts3d), extra_info=str("Y angle = ",a, ", p=..., 3D"));
+ test(rot([0,0,a],p=pts3d), apply(affine3d_zrot(a),pts3d), extra_info=str("Z angle = ",a, ", p=..., 3D"));
+ }
+ for (xa=angs, ya=angs, za=angs) {
+ test(
+ rot([xa,ya,za]),
+ affine3d_chain([
+ affine3d_xrot(xa),
+ affine3d_yrot(ya),
+ affine3d_zrot(za)
+ ]),
+ extra_info=str("[X,Y,Z] = ",[xa,ya,za])
+ );
+ test(
+ rot([xa,ya,za],p=pts3d),
+ apply(
+ affine3d_chain([
+ affine3d_xrot(xa),
+ affine3d_yrot(ya),
+ affine3d_zrot(za)
+ ]),
+ pts3d
+ ),
+ extra_info=str("[X,Y,Z] = ",[xa,ya,za], ", p=...")
+ );
+ }
+ for (vec1 = vecs3d) {
+ for (ang = angs) {
+ test(
+ rot(a=ang, v=vec1),
+ affine3d_rot_by_axis(vec1,ang),
+ extra_info=str("a = ",ang,", v = ", vec1)
+ );
+ test(
+ rot(a=ang, v=vec1, p=pts3d),
+ apply(affine3d_rot_by_axis(vec1,ang), pts3d),
+ extra_info=str("a = ",ang,", v = ", vec1, ", p=...")
+ );
+ }
+ }
+ for (vec1 = vecs2d) {
+ for (vec2 = vecs2d) {
+ test(
+ rot(from=vec1, to=vec2, p=pts2d, planar=true),
+ apply(affine2d_zrot(vang(vec2)-vang(vec1)), pts2d),
+ extra_info=str(
+ "from = ", vec1, ", ",
+ "to = ", vec2, ", ",
+ "planar = ", true, ", ",
+ "p=..., 2D"
+ )
+ );
+ }
+ }
+ for (vec1 = vecs3d) {
+ for (vec2 = vecs3d) {
+ for (a = angs) {
+ test(
+ rot(from=vec1, to=vec2, a=a),
+ affine3d_chain([
+ affine3d_zrot(a),
+ affine3d_rot_from_to(vec1,vec2)
+ ]),
+ extra_info=str(
+ "from = ", vec1, ", ",
+ "to = ", vec2, ", ",
+ "a = ", a
+ )
+ );
+ test(
+ rot(from=vec1, to=vec2, a=a, p=pts3d),
+ apply(
+ affine3d_chain([
+ affine3d_zrot(a),
+ affine3d_rot_from_to(vec1,vec2)
+ ]),
+ pts3d
+ ),
+ extra_info=str(
+ "from = ", vec1, ", ",
+ "to = ", vec2, ", ",
+ "a = ", a, ", ",
+ "p=..., 3D"
+ )
+ );
+ }
+ }
+ }
}
test_rot();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_vectors.scad b/tests/test_vectors.scad
index b13ead9..7090c4f 100644
--- a/tests/test_vectors.scad
+++ b/tests/test_vectors.scad
@@ -2,121 +2,121 @@ include
module test_is_vector() {
- assert(is_vector([1,2,3]) == true);
- assert(is_vector([[1,2,3]]) == false);
- assert(is_vector(["foo"]) == false);
- assert(is_vector([]) == false);
- assert(is_vector(1) == false);
- assert(is_vector("foo") == false);
- assert(is_vector(true) == false);
+ assert(is_vector([1,2,3]) == true);
+ assert(is_vector([[1,2,3]]) == false);
+ assert(is_vector(["foo"]) == false);
+ assert(is_vector([]) == false);
+ assert(is_vector(1) == false);
+ assert(is_vector("foo") == false);
+ assert(is_vector(true) == false);
}
test_is_vector();
module test_add_scalar() {
- assert(add_scalar([1,2,3],3) == [4,5,6]);
- assert(add_scalar([[1,2,3],[3,4,5]],3) == [[4,5,6],[6,7,8]]);
+ assert(add_scalar([1,2,3],3) == [4,5,6]);
+ assert(add_scalar([[1,2,3],[3,4,5]],3) == [[4,5,6],[6,7,8]]);
}
test_add_scalar();
module test_vmul() {
- assert(vmul([3,4,5], [8,7,6]) == [24,28,30]);
- assert(vmul([1,2,3], [4,5,6]) == [4,10,18]);
+ assert(vmul([3,4,5], [8,7,6]) == [24,28,30]);
+ assert(vmul([1,2,3], [4,5,6]) == [4,10,18]);
}
test_vmul();
module test_vdiv() {
- assert(vdiv([24,28,30], [8,7,6]) == [3, 4, 5]);
+ assert(vdiv([24,28,30], [8,7,6]) == [3, 4, 5]);
}
test_vdiv();
module test_vabs() {
- assert(vabs([2,4,8]) == [2,4,8]);
- assert(vabs([-2,-4,-8]) == [2,4,8]);
- assert(vabs([-2,4,8]) == [2,4,8]);
- assert(vabs([2,-4,8]) == [2,4,8]);
- assert(vabs([2,4,-8]) == [2,4,8]);
+ assert(vabs([2,4,8]) == [2,4,8]);
+ assert(vabs([-2,-4,-8]) == [2,4,8]);
+ assert(vabs([-2,4,8]) == [2,4,8]);
+ assert(vabs([2,-4,8]) == [2,4,8]);
+ assert(vabs([2,4,-8]) == [2,4,8]);
}
test_vabs();
include
module test_vang() {
- assert(vang([1,0])==0);
- assert(vang([0,1])==90);
- assert(vang([-1,0])==180);
- assert(vang([0,-1])==-90);
- assert(vang([1,1])==45);
- assert(vang([-1,1])==135);
- assert(vang([1,-1])==-45);
- assert(vang([-1,-1])==-135);
- assert(vang([0,0,1])==[0,90]);
- assert(vang([0,1,1])==[90,45]);
- assert(vang([0,1,-1])==[90,-45]);
- assert(vang([1,0,0])==[0,0]);
- assert(vang([0,1,0])==[90,0]);
- assert(vang([0,-1,0])==[-90,0]);
- assert(vang([-1,0,0])==[180,0]);
- assert(vang([1,0,1])==[0,45]);
- assert(vang([0,1,1])==[90,45]);
- assert(vang([0,-1,1])==[-90,45]);
- assert(approx(vang([1,1,1]),[45, 35.2643896828]));
+ assert(vang([1,0])==0);
+ assert(vang([0,1])==90);
+ assert(vang([-1,0])==180);
+ assert(vang([0,-1])==-90);
+ assert(vang([1,1])==45);
+ assert(vang([-1,1])==135);
+ assert(vang([1,-1])==-45);
+ assert(vang([-1,-1])==-135);
+ assert(vang([0,0,1])==[0,90]);
+ assert(vang([0,1,1])==[90,45]);
+ assert(vang([0,1,-1])==[90,-45]);
+ assert(vang([1,0,0])==[0,0]);
+ assert(vang([0,1,0])==[90,0]);
+ assert(vang([0,-1,0])==[-90,0]);
+ assert(vang([-1,0,0])==[180,0]);
+ assert(vang([1,0,1])==[0,45]);
+ assert(vang([0,1,1])==[90,45]);
+ assert(vang([0,-1,1])==[-90,45]);
+ assert(approx(vang([1,1,1]),[45, 35.2643896828]));
}
test_vang();
module test_unit() {
- assert(unit([10,0,0]) == [1,0,0]);
- assert(unit([0,10,0]) == [0,1,0]);
- assert(unit([0,0,10]) == [0,0,1]);
- assert(abs(norm(unit([10,10,10]))-1) < EPSILON);
- assert(abs(norm(unit([-10,-10,-10]))-1) < EPSILON);
- assert(abs(norm(unit([-10,0,0]))-1) < EPSILON);
- assert(abs(norm(unit([0,-10,0]))-1) < EPSILON);
- assert(abs(norm(unit([0,0,-10]))-1) < EPSILON);
+ assert(unit([10,0,0]) == [1,0,0]);
+ assert(unit([0,10,0]) == [0,1,0]);
+ assert(unit([0,0,10]) == [0,0,1]);
+ assert(abs(norm(unit([10,10,10]))-1) < EPSILON);
+ assert(abs(norm(unit([-10,-10,-10]))-1) < EPSILON);
+ assert(abs(norm(unit([-10,0,0]))-1) < EPSILON);
+ assert(abs(norm(unit([0,-10,0]))-1) < EPSILON);
+ assert(abs(norm(unit([0,0,-10]))-1) < EPSILON);
}
test_unit();
module test_vector_angle() {
- vecs = [[10,0,0], [-10,0,0], [0,10,0], [0,-10,0], [0,0,10], [0,0,-10]];
- for (a=vecs, b=vecs) {
- if(a==b) {
- assert(vector_angle(a,b)==0);
- assert(vector_angle([a,b])==0);
- } else if(a==-b) {
- assert(vector_angle(a,b)==180);
- assert(vector_angle([a,b])==180);
- } else {
- assert(vector_angle(a,b)==90);
- assert(vector_angle([a,b])==90);
- }
- }
- assert(abs(vector_angle([10,10,0],[10,0,0])-45) < EPSILON);
- assert(abs(vector_angle([[10,10,0],[10,0,0]])-45) < EPSILON);
- assert(abs(vector_angle([11,11,1],[1,1,1],[11,-9,1])-90) < EPSILON);
- assert(abs(vector_angle([[11,11,1],[1,1,1],[11,-9,1]])-90) < EPSILON);
+ vecs = [[10,0,0], [-10,0,0], [0,10,0], [0,-10,0], [0,0,10], [0,0,-10]];
+ for (a=vecs, b=vecs) {
+ if(a==b) {
+ assert(vector_angle(a,b)==0);
+ assert(vector_angle([a,b])==0);
+ } else if(a==-b) {
+ assert(vector_angle(a,b)==180);
+ assert(vector_angle([a,b])==180);
+ } else {
+ assert(vector_angle(a,b)==90);
+ assert(vector_angle([a,b])==90);
+ }
+ }
+ assert(abs(vector_angle([10,10,0],[10,0,0])-45) < EPSILON);
+ assert(abs(vector_angle([[10,10,0],[10,0,0]])-45) < EPSILON);
+ assert(abs(vector_angle([11,11,1],[1,1,1],[11,-9,1])-90) < EPSILON);
+ assert(abs(vector_angle([[11,11,1],[1,1,1],[11,-9,1]])-90) < EPSILON);
}
test_vector_angle();
module test_vector_axis() {
- assert(norm(vector_axis([10,0,0],[10,10,0]) - [0,0,1]) < EPSILON);
- assert(norm(vector_axis([[10,0,0],[10,10,0]]) - [0,0,1]) < EPSILON);
- assert(norm(vector_axis([10,0,0],[0,10,0]) - [0,0,1]) < EPSILON);
- assert(norm(vector_axis([[10,0,0],[0,10,0]]) - [0,0,1]) < EPSILON);
- assert(norm(vector_axis([0,10,0],[10,0,0]) - [0,0,-1]) < EPSILON);
- assert(norm(vector_axis([[0,10,0],[10,0,0]]) - [0,0,-1]) < EPSILON);
- assert(norm(vector_axis([0,0,10],[10,0,0]) - [0,1,0]) < EPSILON);
- assert(norm(vector_axis([[0,0,10],[10,0,0]]) - [0,1,0]) < EPSILON);
- assert(norm(vector_axis([10,0,0],[0,0,10]) - [0,-1,0]) < EPSILON);
- assert(norm(vector_axis([[10,0,0],[0,0,10]]) - [0,-1,0]) < EPSILON);
- assert(norm(vector_axis([10,0,10],[0,-10,0]) - [sin(45),0,-sin(45)]) < EPSILON);
- assert(norm(vector_axis([[10,0,10],[0,-10,0]]) - [sin(45),0,-sin(45)]) < EPSILON);
- assert(norm(vector_axis([11,1,11],[1,1,1],[1,-9,1]) - [sin(45),0,-sin(45)]) < EPSILON);
- assert(norm(vector_axis([[11,1,11],[1,1,1],[1,-9,1]]) - [sin(45),0,-sin(45)]) < EPSILON);
+ assert(norm(vector_axis([10,0,0],[10,10,0]) - [0,0,1]) < EPSILON);
+ assert(norm(vector_axis([[10,0,0],[10,10,0]]) - [0,0,1]) < EPSILON);
+ assert(norm(vector_axis([10,0,0],[0,10,0]) - [0,0,1]) < EPSILON);
+ assert(norm(vector_axis([[10,0,0],[0,10,0]]) - [0,0,1]) < EPSILON);
+ assert(norm(vector_axis([0,10,0],[10,0,0]) - [0,0,-1]) < EPSILON);
+ assert(norm(vector_axis([[0,10,0],[10,0,0]]) - [0,0,-1]) < EPSILON);
+ assert(norm(vector_axis([0,0,10],[10,0,0]) - [0,1,0]) < EPSILON);
+ assert(norm(vector_axis([[0,0,10],[10,0,0]]) - [0,1,0]) < EPSILON);
+ assert(norm(vector_axis([10,0,0],[0,0,10]) - [0,-1,0]) < EPSILON);
+ assert(norm(vector_axis([[10,0,0],[0,0,10]]) - [0,-1,0]) < EPSILON);
+ assert(norm(vector_axis([10,0,10],[0,-10,0]) - [sin(45),0,-sin(45)]) < EPSILON);
+ assert(norm(vector_axis([[10,0,10],[0,-10,0]]) - [sin(45),0,-sin(45)]) < EPSILON);
+ assert(norm(vector_axis([11,1,11],[1,1,1],[1,-9,1]) - [sin(45),0,-sin(45)]) < EPSILON);
+ assert(norm(vector_axis([[11,1,11],[1,1,1],[1,-9,1]]) - [sin(45),0,-sin(45)]) < EPSILON);
}
test_vector_axis();
@@ -124,4 +124,4 @@ test_vector_axis();
cube();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_version.scad b/tests/test_version.scad
index 9a65c80..f877b5c 100644
--- a/tests/test_version.scad
+++ b/tests/test_version.scad
@@ -2,116 +2,116 @@ include
module test_bosl_version() {
- assert(is_vector(bosl_version())); // Returned value is a vector.
- assert(len(bosl_version())==3); // of three numbers.
- assert(bosl_version()[0]==2); // The major version is 2.
- for (v=bosl_version()) {
- assert(floor(v)==v); // All version parts are integers.
- }
+ assert(is_vector(bosl_version())); // Returned value is a vector.
+ assert(len(bosl_version())==3); // of three numbers.
+ assert(bosl_version()[0]==2); // The major version is 2.
+ for (v=bosl_version()) {
+ assert(floor(v)==v); // All version parts are integers.
+ }
}
test_bosl_version();
module test_bosl_version_num() {
- assert(is_num(bosl_version_num()));
- v = bosl_version();
- assert(bosl_version_num() == v[0]+v[1]/100+v[2]/1000000);
+ assert(is_num(bosl_version_num()));
+ v = bosl_version();
+ assert(bosl_version_num() == v[0]+v[1]/100+v[2]/1000000);
}
test_bosl_version_num();
module test_bosl_version_str() {
- assert(is_string(bosl_version_str()));
- v = bosl_version();
- assert(bosl_version_str() == str(v[0],".",v[1],".",v[2]));
+ assert(is_string(bosl_version_str()));
+ v = bosl_version();
+ assert(bosl_version_str() == str(v[0],".",v[1],".",v[2]));
}
test_bosl_version_str();
module test_bosl_required() {
- bosl_required(2.000001);
- bosl_required("2.0.1");
- bosl_required([2,0,1]);
+ bosl_required(2.000001);
+ bosl_required("2.0.1");
+ bosl_required([2,0,1]);
}
test_bosl_required();
module test_version_to_list() {
- assert(is_list(version_to_list(2.010001)));
- assert(is_list(version_to_list("2.1.1")));
- assert(is_list(version_to_list([2,1,1])));
- assert(version_to_list(2.010001)==[2,1,1]);
- assert(version_to_list("2.1.1")==[2,1,1]);
- assert(version_to_list([2,1,1])==[2,1,1]);
- assert(version_to_list(2.010035)==[2,1,35]);
- assert(version_to_list(2.345678)==[2,34,5678]);
- assert(version_to_list("2.34.5678")==[2,34,5678]);
- assert(version_to_list([2,34,5678])==[2,34,5678]);
- assert(version_to_list([2,34,56,78])==[2,34,56]);
+ assert(is_list(version_to_list(2.010001)));
+ assert(is_list(version_to_list("2.1.1")));
+ assert(is_list(version_to_list([2,1,1])));
+ assert(version_to_list(2.010001)==[2,1,1]);
+ assert(version_to_list("2.1.1")==[2,1,1]);
+ assert(version_to_list([2,1,1])==[2,1,1]);
+ assert(version_to_list(2.010035)==[2,1,35]);
+ assert(version_to_list(2.345678)==[2,34,5678]);
+ assert(version_to_list("2.34.5678")==[2,34,5678]);
+ assert(version_to_list([2,34,5678])==[2,34,5678]);
+ assert(version_to_list([2,34,56,78])==[2,34,56]);
}
test_version_to_list();
module test_version_to_str() {
- assert(is_string(version_to_str(2.010001)));
- assert(is_string(version_to_str("2.1.1")));
- assert(is_string(version_to_str([2,1,1])));
- assert(version_to_str(2.010001)=="2.1.1");
- assert(version_to_str("2.1.1")=="2.1.1");
- assert(version_to_str([2,1,1])=="2.1.1");
- assert(version_to_str(2.345678)=="2.34.5678");
- assert(version_to_str("2.34.5678")=="2.34.5678");
- assert(version_to_str([2,34,5678])=="2.34.5678");
- assert(version_to_str([2,34,56,78])=="2.34.56");
+ assert(is_string(version_to_str(2.010001)));
+ assert(is_string(version_to_str("2.1.1")));
+ assert(is_string(version_to_str([2,1,1])));
+ assert(version_to_str(2.010001)=="2.1.1");
+ assert(version_to_str("2.1.1")=="2.1.1");
+ assert(version_to_str([2,1,1])=="2.1.1");
+ assert(version_to_str(2.345678)=="2.34.5678");
+ assert(version_to_str("2.34.5678")=="2.34.5678");
+ assert(version_to_str([2,34,5678])=="2.34.5678");
+ assert(version_to_str([2,34,56,78])=="2.34.56");
}
test_version_to_str();
module test_version_to_num() {
- assert(is_num(version_to_num(2.010001)));
- assert(is_num(version_to_num("2.1.1")));
- assert(is_num(version_to_num([2,1,1])));
- assert(version_to_num(2.010001)==2.010001);
- assert(version_to_num("2.1.1")==2.010001);
- assert(version_to_num([2,1,1])==2.010001);
- assert(version_to_num(2.345678)==2.345678);
- assert(version_to_num("2.34.5678")==2.345678);
- assert(version_to_num([2,34,5678])==2.345678);
- assert(version_to_num([2,34,56,78])==2.340056);
+ assert(is_num(version_to_num(2.010001)));
+ assert(is_num(version_to_num("2.1.1")));
+ assert(is_num(version_to_num([2,1,1])));
+ assert(version_to_num(2.010001)==2.010001);
+ assert(version_to_num("2.1.1")==2.010001);
+ assert(version_to_num([2,1,1])==2.010001);
+ assert(version_to_num(2.345678)==2.345678);
+ assert(version_to_num("2.34.5678")==2.345678);
+ assert(version_to_num([2,34,5678])==2.345678);
+ assert(version_to_num([2,34,56,78])==2.340056);
}
test_version_to_num();
module test_version_cmp() {
- function diversify(x) = [
- version_to_num(x),
- version_to_str(x),
- version_to_list(x)
- ];
+ function diversify(x) = [
+ version_to_num(x),
+ version_to_str(x),
+ version_to_list(x)
+ ];
- module testvercmp(x,y,z) {
- for (a = diversify(y)) {
- for (b = diversify(x)) {
- assert(version_cmp(a,b)>0);
- }
- for (b = diversify(y)) {
- assert(version_cmp(a,b)==0);
- }
- for (b = diversify(z)) {
- assert(version_cmp(a,b)<0);
- }
- }
- }
+ module testvercmp(x,y,z) {
+ for (a = diversify(y)) {
+ for (b = diversify(x)) {
+ assert(version_cmp(a,b)>0);
+ }
+ for (b = diversify(y)) {
+ assert(version_cmp(a,b)==0);
+ }
+ for (b = diversify(z)) {
+ assert(version_cmp(a,b)<0);
+ }
+ }
+ }
- testvercmp([2,1,33],[2,1,34],[2,1,35]);
- testvercmp([2,2,1],[2,2,34],[2,2,67]);
- testvercmp([2,2,34],[2,3,34],[2,4,34]);
- testvercmp([2,3,34],[3,3,34],[4,3,34]);
- testvercmp([2,3,34],[3,1,1],[4,1,1]);
- testvercmp([2,1,1],[3,3,34],[4,1,1]);
- testvercmp([2,1,1],[3,1,1],[4,3,34]);
+ testvercmp([2,1,33],[2,1,34],[2,1,35]);
+ testvercmp([2,2,1],[2,2,34],[2,2,67]);
+ testvercmp([2,2,34],[2,3,34],[2,4,34]);
+ testvercmp([2,3,34],[3,3,34],[4,3,34]);
+ testvercmp([2,3,34],[3,1,1],[4,1,1]);
+ testvercmp([2,1,1],[3,3,34],[4,1,1]);
+ testvercmp([2,1,1],[3,1,1],[4,3,34]);
}
test_version_cmp();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tests/test_vnf.scad b/tests/test_vnf.scad
index 52da3fb..353d117 100644
--- a/tests/test_vnf.scad
+++ b/tests/test_vnf.scad
@@ -3,101 +3,101 @@ include
module test_is_vnf() {
- assert(is_vnf([[],[]]));
- assert(!is_vnf([]));
- assert(is_vnf([[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]));
+ assert(is_vnf([[],[]]));
+ assert(!is_vnf([]));
+ assert(is_vnf([[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]));
}
test_is_vnf();
module test_is_vnf_list() {
- assert(is_vnf_list([]));
- assert(!is_vnf_list([[],[]]));
- assert(is_vnf_list([[[],[]]]));
- assert(!is_vnf_list([[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]));
- assert(is_vnf_list([[[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]]));
+ assert(is_vnf_list([]));
+ assert(!is_vnf_list([[],[]]));
+ assert(is_vnf_list([[[],[]]]));
+ assert(!is_vnf_list([[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]));
+ assert(is_vnf_list([[[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]]]));
}
test_is_vnf_list();
module test_vnf_vertices() {
- vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
- assert(vnf_vertices(vnf) == vnf[0]);
+ vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
+ assert(vnf_vertices(vnf) == vnf[0]);
}
test_vnf_vertices();
module test_vnf_faces() {
- vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
- assert(vnf_faces(vnf) == vnf[1]);
+ vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
+ assert(vnf_faces(vnf) == vnf[1]);
}
test_vnf_faces();
module test_vnf_get_vertex() {
- vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
- assert(vnf_get_vertex(vnf,[0,1,-1]) == [2,vnf]);
- assert(vnf_get_vertex(vnf,[0,1,2]) == [4,[concat(vnf[0],[[0,1,2]]),vnf[1]]]);
+ vnf = [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]],[[0,1,2],[0,3,1],[1,3,2],[2,3,0]]];
+ assert(vnf_get_vertex(vnf,[0,1,-1]) == [2,vnf]);
+ assert(vnf_get_vertex(vnf,[0,1,2]) == [4,[concat(vnf[0],[[0,1,2]]),vnf[1]]]);
}
test_vnf_get_vertex();
module test_vnf_add_face() {
- verts = [[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]];
- faces = [[0,1,2],[0,3,1],[1,3,2],[2,3,0]];
- vnf1 = vnf_add_face(pts=select(verts,faces[0]));
- vnf2 = vnf_add_face(vnf1, pts=select(verts,faces[1]));
- vnf3 = vnf_add_face(vnf2, pts=select(verts,faces[2]));
- vnf4 = vnf_add_face(vnf3, pts=select(verts,faces[3]));
- assert(vnf1 == [select(verts,0,2),select(faces,[0])]);
- assert(vnf2 == [verts,select(faces,[0:1])]);
- assert(vnf3 == [verts,select(faces,[0:2])]);
- assert(vnf4 == [verts,faces]);
+ verts = [[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]];
+ faces = [[0,1,2],[0,3,1],[1,3,2],[2,3,0]];
+ vnf1 = vnf_add_face(pts=select(verts,faces[0]));
+ vnf2 = vnf_add_face(vnf1, pts=select(verts,faces[1]));
+ vnf3 = vnf_add_face(vnf2, pts=select(verts,faces[2]));
+ vnf4 = vnf_add_face(vnf3, pts=select(verts,faces[3]));
+ assert(vnf1 == [select(verts,0,2),select(faces,[0])]);
+ assert(vnf2 == [verts,select(faces,[0:1])]);
+ assert(vnf3 == [verts,select(faces,[0:2])]);
+ assert(vnf4 == [verts,faces]);
}
test_vnf_add_face();
module test_vnf_add_faces() {
- verts = [[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]];
- faces = [[0,1,2],[0,3,1],[1,3,2],[2,3,0]];
- assert(vnf_add_faces(faces=[for (face=faces) select(verts,face)]) == [verts,faces]);
+ verts = [[-1,-1,-1],[1,-1,-1],[0,1,-1],[0,0,1]];
+ faces = [[0,1,2],[0,3,1],[1,3,2],[2,3,0]];
+ assert(vnf_add_faces(faces=[for (face=faces) select(verts,face)]) == [verts,faces]);
}
test_vnf_add_faces();
module test_vnf_merge() {
- vnf1 = vnf_add_face(pts=[[-1,-1,-1],[1,-1,-1],[0,1,-1]]);
- vnf2 = vnf_add_face(pts=[[1,1,1],[-1,1,1],[0,1,-1]]);
- assert(vnf_merge([vnf1,vnf2]) == [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[1,1,1],[-1,1,1],[0,1,-1]],[[0,1,2],[3,4,5]]]);
+ vnf1 = vnf_add_face(pts=[[-1,-1,-1],[1,-1,-1],[0,1,-1]]);
+ vnf2 = vnf_add_face(pts=[[1,1,1],[-1,1,1],[0,1,-1]]);
+ assert(vnf_merge([vnf1,vnf2]) == [[[-1,-1,-1],[1,-1,-1],[0,1,-1],[1,1,1],[-1,1,1],[0,1,-1]],[[0,1,2],[3,4,5]]]);
}
test_vnf_merge();
module test_vnf_triangulate() {
- vnf = [[[-1,-1,0],[1,-1,0],[1,1,0],[-1,1,0]],[[0,1,2,3]]];
- assert(vnf_triangulate(vnf) == [[[-1,-1,0],[1,-1,0],[1,1,0],[-1,1,0]], [[0,1,2],[2,3,0]]]);
+ vnf = [[[-1,-1,0],[1,-1,0],[1,1,0],[-1,1,0]],[[0,1,2,3]]];
+ assert(vnf_triangulate(vnf) == [[[-1,-1,0],[1,-1,0],[1,1,0],[-1,1,0]], [[0,1,2],[2,3,0]]]);
}
test_vnf_triangulate();
module test_vnf_vertex_array() {
- vnf1 = vnf_vertex_array(
- points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
- col_wrap=true, caps=true
- );
- vnf2 = vnf_vertex_array(
- points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
- col_wrap=true, caps=true, style="alt"
- );
- vnf3 = vnf_vertex_array(
- points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
- col_wrap=true, caps=true, style="quincunx"
- );
- assert(vnf1 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100]],[[0,4,3],[0,1,4],[1,5,4],[1,2,5],[2,3,5],[2,0,3],[2,1,0],[3,4,5]]]);
- assert(vnf2 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100]],[[0,1,3],[3,1,4],[1,2,4],[4,2,5],[2,0,5],[5,0,3],[2,1,0],[3,4,5]]]);
- assert(vnf3 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100],[0,-50,50],[-50,25,50],[50,25,50]],[[0,6,3],[3,6,4],[4,6,1],[1,6,0],[1,7,4],[4,7,5],[5,7,2],[2,7,1],[2,8,5],[5,8,3],[3,8,0],[0,8,2],[2,1,0],[3,4,5]]]);
+ vnf1 = vnf_vertex_array(
+ points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
+ col_wrap=true, caps=true
+ );
+ vnf2 = vnf_vertex_array(
+ points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
+ col_wrap=true, caps=true, style="alt"
+ );
+ vnf3 = vnf_vertex_array(
+ points=[for (h=[0:100:100]) [[100,-50,h],[-100,-50,h],[0,100,h]]],
+ col_wrap=true, caps=true, style="quincunx"
+ );
+ assert(vnf1 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100]],[[0,4,3],[0,1,4],[1,5,4],[1,2,5],[2,3,5],[2,0,3],[2,1,0],[3,4,5]]]);
+ assert(vnf2 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100]],[[0,1,3],[3,1,4],[1,2,4],[4,2,5],[2,0,5],[5,0,3],[2,1,0],[3,4,5]]]);
+ assert(vnf3 == [[[100,-50,0],[-100,-50,0],[0,100,0],[100,-50,100],[-100,-50,100],[0,100,100],[0,-50,50],[-50,25,50],[50,25,50]],[[0,6,3],[3,6,4],[4,6,1],[1,6,0],[1,7,4],[4,7,5],[5,7,2],[2,7,1],[2,8,5],[5,8,3],[3,8,0],[0,8,2],[2,1,0],[3,4,5]]]);
}
test_vnf_vertex_array();
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/threading.scad b/threading.scad
index 1ea3313..7d4ced5 100644
--- a/threading.scad
+++ b/threading.scad
@@ -43,34 +43,34 @@
// stroke(profile, width=0.02);
module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=720, profile=undef, left_handed=false, higbee=60, internal=false, anchor=CENTER, spin=0, orient=UP)
{
- h = pitch*twist/360;
- r = base_d/2;
- dz = thread_depth/pitch * tan(thread_angle);
- cap = (1 - 2*dz)/2;
- profile = !is_undef(profile)? profile : (
- internal? [
- [thread_depth/pitch, -cap/2-dz],
- [0, -cap/2],
- [0, +cap/2],
- [thread_depth/pitch, +cap/2+dz],
- ] : [
- [0, +cap/2+dz],
- [thread_depth/pitch, +cap/2],
- [thread_depth/pitch, -cap/2],
- [0, -cap/2-dz],
- ]
- );
- pline = profile * pitch;
- dir = left_handed? -1 : 1;
- idir = internal? -1 : 1;
- attachable(anchor,spin,orient, r=r, l=h) {
- difference() {
- spiral_sweep(pline, h=h, r=base_d/2, twist=twist*dir, $fn=segs(base_d/2), anchor=CENTER);
- down(h/2) right(r) right(internal? thread_depth : 0) zrot(higbee*dir*idir) fwd(dir*pitch/2) cube([3*thread_depth/cos(higbee), pitch, pitch], center=true);
- up(h/2) zrot(twist*dir) right(r) right(internal? thread_depth : 0) zrot(-higbee*dir*idir) back(dir*pitch/2) cube([3*thread_depth/cos(higbee), pitch, pitch], center=true);
- }
- children();
- }
+ h = pitch*twist/360;
+ r = base_d/2;
+ dz = thread_depth/pitch * tan(thread_angle);
+ cap = (1 - 2*dz)/2;
+ profile = !is_undef(profile)? profile : (
+ internal? [
+ [thread_depth/pitch, -cap/2-dz],
+ [0, -cap/2],
+ [0, +cap/2],
+ [thread_depth/pitch, +cap/2+dz],
+ ] : [
+ [0, +cap/2+dz],
+ [thread_depth/pitch, +cap/2],
+ [thread_depth/pitch, -cap/2],
+ [0, -cap/2-dz],
+ ]
+ );
+ pline = profile * pitch;
+ dir = left_handed? -1 : 1;
+ idir = internal? -1 : 1;
+ attachable(anchor,spin,orient, r=r, l=h) {
+ difference() {
+ spiral_sweep(pline, h=h, r=base_d/2, twist=twist*dir, $fn=segs(base_d/2), anchor=CENTER);
+ down(h/2) right(r) right(internal? thread_depth : 0) zrot(higbee*dir*idir) fwd(dir*pitch/2) cube([3*thread_depth/cos(higbee), pitch, pitch], center=true);
+ up(h/2) zrot(twist*dir) right(r) right(internal? thread_depth : 0) zrot(-higbee*dir*idir) back(dir*pitch/2) cube([3*thread_depth/cos(higbee), pitch, pitch], center=true);
+ }
+ children();
+ }
}
@@ -127,162 +127,162 @@ module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=72
// ];
// stroke(profile, width=0.02);
module trapezoidal_threaded_rod(
- d=10,
- l=100,
- pitch=2,
- thread_angle=15,
- thread_depth=undef,
- left_handed=false,
- bevel=false,
- starts=1,
- profile=undef,
- internal=false,
- center, anchor, spin=0, orient=UP
+ d=10,
+ l=100,
+ pitch=2,
+ thread_angle=15,
+ thread_depth=undef,
+ left_handed=false,
+ bevel=false,
+ starts=1,
+ profile=undef,
+ internal=false,
+ center, anchor, spin=0, orient=UP
) {
- function _thread_pt(thread, threads, start, starts, astep, asteps, part, parts) =
- astep + asteps * (thread + threads * (part + parts * start));
+ function _thread_pt(thread, threads, start, starts, astep, asteps, part, parts) =
+ astep + asteps * (thread + threads * (part + parts * start));
- d = internal? (d/cos(180/segs(d/2)) + $slop*3) : d;
- astep = 360 / quantup(segs(d/2), starts);
- asteps = ceil(360/astep);
- threads = ceil(l/pitch/starts)+(starts<4?4-starts:1);
- depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
- pa_delta = min(pitch/4-0.01,depth*tan(thread_angle)/2)/pitch;
- dir = left_handed? -1 : 1;
- r1 = -depth/pitch;
- z1 = 1/4-pa_delta;
- z2 = 1/4+pa_delta;
- profile = profile!=undef? profile : [
- [-z2, r1],
- [-z1, 0],
- [ z1, 0],
- [ z2, r1],
- ];
- parts = len(profile);
- poly_points = concat(
- [
- for (
- start = [0:1:starts-1],
- part = [0:1:parts-1],
- thread = [0:1:threads-1],
- astep = [0:1:asteps-1]
- ) let (
- ppt = profile[part] * pitch,
- dz = ppt.x,
- r = ppt.y + d/2,
- a = astep / asteps,
- c = cos(360 * (a * dir + start/starts)),
- s = sin(360 * (a * dir + start/starts)),
- z = (thread + a - threads/2) * starts * pitch
- ) [r*c, r*s, z+dz]
- ],
- [[0, 0, -threads*pitch*starts/2-pitch/4], [0, 0, threads*pitch*starts/2+pitch/4]]
- );
- point_count = len(poly_points);
- poly_faces = concat(
- // Thread surfaces
- [
- for (
- start = [0:1:starts-1],
- part = [0:1:parts-2],
- thread = [0:1:threads-1],
- astep = [0:1:asteps-1],
- trinum = [0, 1]
- ) let (
- p0 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
- p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
- p2 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part, parts),
- p3 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part+1, parts),
- tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
- otri = left_handed? [tri[0], tri[2], tri[1]] : tri
- )
- if (!(thread == threads-1 && astep == asteps-1)) otri
- ],
- // Thread trough bottom
- [
- for (
- start = [0:1:starts-1],
- thread = [0:1:threads-1],
- astep = [0:1:asteps-1],
- trinum = [0, 1]
- ) let (
- p0 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
- p1 = _thread_pt(thread, threads, (start+(left_handed?1:starts-1))%starts, starts, astep+asteps/starts, asteps, 0, parts),
- p2 = p0 + 1,
- p3 = p1 + 1,
- tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
- otri = left_handed? [tri[0], tri[2], tri[1]] : tri
- )
- if (
- !(thread >= threads-1 && astep > asteps-asteps/starts-2) &&
- !(thread >= threads-2 && starts == 1 && astep >= asteps-1)
- ) otri
- ],
- // top and bottom thread endcap
- [
- for (
- start = [0:1:starts-1],
- part = [1:1:parts-2],
- is_top = [0, 1]
- ) let (
- astep = is_top? asteps-1 : 0,
- thread = is_top? threads-1 : 0,
- p0 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
- p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
- p2 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
- tri = is_top? [p0, p1, p2] : [p0, p2, p1],
- otri = left_handed? [tri[0], tri[2], tri[1]] : tri
- ) otri
- ],
- // body side triangles
- [
- for (
- start = [0:1:starts-1],
- is_top = [false, true],
- trinum = [0, 1]
- ) let (
- astep = is_top? asteps-1 : 0,
- thread = is_top? threads-1 : 0,
- ostart = (is_top != left_handed? (start+1) : (start+starts-1))%starts,
- ostep = is_top? astep-asteps/starts : astep+asteps/starts,
- oparts = is_top? parts-1 : 0,
- p0 = is_top? point_count-1 : point_count-2,
- p1 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
- p2 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
- p3 = _thread_pt(thread, threads, ostart, starts, ostep, asteps, oparts, parts),
- tri = trinum==0?
- (is_top? [p0, p1, p2] : [p0, p2, p1]) :
- (is_top? [p0, p3, p1] : [p0, p3, p2]),
- otri = left_handed? [tri[0], tri[2], tri[1]] : tri
- ) otri
- ],
- // Caps
- [
- for (
- start = [0:1:starts-1],
- astep = [0:1:asteps/starts-1],
- is_top = [0, 1]
- ) let (
- thread = is_top? threads-1 : 0,
- part = is_top? parts-1 : 0,
- ostep = is_top? asteps-astep-2 : astep,
- p0 = is_top? point_count-1 : point_count-2,
- p1 = _thread_pt(thread, threads, start, starts, ostep, asteps, part, parts),
- p2 = _thread_pt(thread, threads, start, starts, ostep+1, asteps, part, parts),
- tri = is_top? [p0, p2, p1] : [p0, p1, p2],
- otri = left_handed? [tri[0], tri[2], tri[1]] : tri
- ) otri
- ]
- );
- anchor = get_anchor(anchor, center, BOT, CENTER);
- attachable(anchor,spin,orient, d=d, l=l) {
- difference() {
- polyhedron(points=poly_points, faces=poly_faces, convexity=threads*starts*2);
- zcopies(l+4*pitch*starts) cube([d+1, d+1, 4*pitch*starts], center=true);
- if (bevel) cylinder_mask(d=d, l=l+0.01, chamfer=depth);
- }
- children();
- }
+ d = internal? (d/cos(180/segs(d/2)) + $slop*3) : d;
+ astep = 360 / quantup(segs(d/2), starts);
+ asteps = ceil(360/astep);
+ threads = ceil(l/pitch/starts)+(starts<4?4-starts:1);
+ depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
+ pa_delta = min(pitch/4-0.01,depth*tan(thread_angle)/2)/pitch;
+ dir = left_handed? -1 : 1;
+ r1 = -depth/pitch;
+ z1 = 1/4-pa_delta;
+ z2 = 1/4+pa_delta;
+ profile = profile!=undef? profile : [
+ [-z2, r1],
+ [-z1, 0],
+ [ z1, 0],
+ [ z2, r1],
+ ];
+ parts = len(profile);
+ poly_points = concat(
+ [
+ for (
+ start = [0:1:starts-1],
+ part = [0:1:parts-1],
+ thread = [0:1:threads-1],
+ astep = [0:1:asteps-1]
+ ) let (
+ ppt = profile[part] * pitch,
+ dz = ppt.x,
+ r = ppt.y + d/2,
+ a = astep / asteps,
+ c = cos(360 * (a * dir + start/starts)),
+ s = sin(360 * (a * dir + start/starts)),
+ z = (thread + a - threads/2) * starts * pitch
+ ) [r*c, r*s, z+dz]
+ ],
+ [[0, 0, -threads*pitch*starts/2-pitch/4], [0, 0, threads*pitch*starts/2+pitch/4]]
+ );
+ point_count = len(poly_points);
+ poly_faces = concat(
+ // Thread surfaces
+ [
+ for (
+ start = [0:1:starts-1],
+ part = [0:1:parts-2],
+ thread = [0:1:threads-1],
+ astep = [0:1:asteps-1],
+ trinum = [0, 1]
+ ) let (
+ p0 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
+ p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
+ p2 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part, parts),
+ p3 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part+1, parts),
+ tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
+ otri = left_handed? [tri[0], tri[2], tri[1]] : tri
+ )
+ if (!(thread == threads-1 && astep == asteps-1)) otri
+ ],
+ // Thread trough bottom
+ [
+ for (
+ start = [0:1:starts-1],
+ thread = [0:1:threads-1],
+ astep = [0:1:asteps-1],
+ trinum = [0, 1]
+ ) let (
+ p0 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
+ p1 = _thread_pt(thread, threads, (start+(left_handed?1:starts-1))%starts, starts, astep+asteps/starts, asteps, 0, parts),
+ p2 = p0 + 1,
+ p3 = p1 + 1,
+ tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
+ otri = left_handed? [tri[0], tri[2], tri[1]] : tri
+ )
+ if (
+ !(thread >= threads-1 && astep > asteps-asteps/starts-2) &&
+ !(thread >= threads-2 && starts == 1 && astep >= asteps-1)
+ ) otri
+ ],
+ // top and bottom thread endcap
+ [
+ for (
+ start = [0:1:starts-1],
+ part = [1:1:parts-2],
+ is_top = [0, 1]
+ ) let (
+ astep = is_top? asteps-1 : 0,
+ thread = is_top? threads-1 : 0,
+ p0 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
+ p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
+ p2 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
+ tri = is_top? [p0, p1, p2] : [p0, p2, p1],
+ otri = left_handed? [tri[0], tri[2], tri[1]] : tri
+ ) otri
+ ],
+ // body side triangles
+ [
+ for (
+ start = [0:1:starts-1],
+ is_top = [false, true],
+ trinum = [0, 1]
+ ) let (
+ astep = is_top? asteps-1 : 0,
+ thread = is_top? threads-1 : 0,
+ ostart = (is_top != left_handed? (start+1) : (start+starts-1))%starts,
+ ostep = is_top? astep-asteps/starts : astep+asteps/starts,
+ oparts = is_top? parts-1 : 0,
+ p0 = is_top? point_count-1 : point_count-2,
+ p1 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
+ p2 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
+ p3 = _thread_pt(thread, threads, ostart, starts, ostep, asteps, oparts, parts),
+ tri = trinum==0?
+ (is_top? [p0, p1, p2] : [p0, p2, p1]) :
+ (is_top? [p0, p3, p1] : [p0, p3, p2]),
+ otri = left_handed? [tri[0], tri[2], tri[1]] : tri
+ ) otri
+ ],
+ // Caps
+ [
+ for (
+ start = [0:1:starts-1],
+ astep = [0:1:asteps/starts-1],
+ is_top = [0, 1]
+ ) let (
+ thread = is_top? threads-1 : 0,
+ part = is_top? parts-1 : 0,
+ ostep = is_top? asteps-astep-2 : astep,
+ p0 = is_top? point_count-1 : point_count-2,
+ p1 = _thread_pt(thread, threads, start, starts, ostep, asteps, part, parts),
+ p2 = _thread_pt(thread, threads, start, starts, ostep+1, asteps, part, parts),
+ tri = is_top? [p0, p2, p1] : [p0, p1, p2],
+ otri = left_handed? [tri[0], tri[2], tri[1]] : tri
+ ) otri
+ ]
+ );
+ anchor = get_anchor(anchor, center, BOT, CENTER);
+ attachable(anchor,spin,orient, d=d, l=l) {
+ difference() {
+ polyhedron(points=poly_points, faces=poly_faces, convexity=threads*starts*2);
+ zcopies(l+4*pitch*starts) cube([d+1, d+1, 4*pitch*starts], center=true);
+ if (bevel) cylinder_mask(d=d, l=l+0.01, chamfer=depth);
+ }
+ children();
+ }
}
@@ -315,45 +315,45 @@ module trapezoidal_threaded_rod(
// trapezoidal_threaded_nut(od=17.4, id=10, h=10, pitch=2, $slop=0.2, left_handed=true);
// trapezoidal_threaded_nut(od=17.4, id=10, h=10, pitch=2, thread_angle=15, starts=3, $fa=1, $fs=1);
module trapezoidal_threaded_nut(
- od=17.4,
- id=10,
- h=10,
- pitch=2,
- thread_depth=undef,
- thread_angle=15,
- profile=undef,
- left_handed=false,
- starts=1,
- bevel=true,
- anchor=CENTER,
- spin=0,
- orient=UP
+ od=17.4,
+ id=10,
+ h=10,
+ pitch=2,
+ thread_depth=undef,
+ thread_angle=15,
+ profile=undef,
+ left_handed=false,
+ starts=1,
+ bevel=true,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
- attachable(anchor,spin,orient, size=[od/cos(30),od,h]) {
- difference() {
- cylinder(d=od/cos(30), h=h, center=true, $fn=6);
- trapezoidal_threaded_rod(
- d=id,
- l=h+1,
- pitch=pitch,
- thread_depth=depth,
- thread_angle=thread_angle,
- profile=profile,
- left_handed=left_handed,
- starts=starts,
- internal=true
- );
- if (bevel) {
- zflip_copy() {
- down(h/2+0.01) {
- cylinder(r1=id/2+$slop, r2=id/2+$slop-depth, h=depth, center=false);
- }
- }
- }
- }
- children();
- }
+ depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
+ attachable(anchor,spin,orient, size=[od/cos(30),od,h]) {
+ difference() {
+ cylinder(d=od/cos(30), h=h, center=true, $fn=6);
+ trapezoidal_threaded_rod(
+ d=id,
+ l=h+1,
+ pitch=pitch,
+ thread_depth=depth,
+ thread_angle=thread_angle,
+ profile=profile,
+ left_handed=left_handed,
+ starts=starts,
+ internal=true
+ );
+ if (bevel) {
+ zflip_copy() {
+ down(h/2+0.01) {
+ cylinder(r1=id/2+$slop, r2=id/2+$slop-depth, h=depth, center=false);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -381,42 +381,42 @@ module trapezoidal_threaded_nut(
// threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
// threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1);
module threaded_rod(
- d=10, l=100, pitch=2,
- left_handed=false,
- bevel=false,
- internal=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2,
+ left_handed=false,
+ bevel=false,
+ internal=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- depth = pitch * cos(30) * 5/8;
- profile = internal? [
- [-6/16, -depth/pitch],
- [-1/16, 0],
- [-1/32, 0.02],
- [ 1/32, 0.02],
- [ 1/16, 0],
- [ 6/16, -depth/pitch]
- ] : [
- [-7/16, -depth/pitch*1.07],
- [-6/16, -depth/pitch],
- [-1/16, 0],
- [ 1/16, 0],
- [ 6/16, -depth/pitch],
- [ 7/16, -depth/pitch*1.07]
- ];
- trapezoidal_threaded_rod(
- d=d, l=l, pitch=pitch,
- thread_depth=depth,
- thread_angle=30,
- profile=profile,
- left_handed=left_handed,
- bevel=bevel,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ depth = pitch * cos(30) * 5/8;
+ profile = internal? [
+ [-6/16, -depth/pitch],
+ [-1/16, 0],
+ [-1/32, 0.02],
+ [ 1/32, 0.02],
+ [ 1/16, 0],
+ [ 6/16, -depth/pitch]
+ ] : [
+ [-7/16, -depth/pitch*1.07],
+ [-6/16, -depth/pitch],
+ [-1/16, 0],
+ [ 1/16, 0],
+ [ 6/16, -depth/pitch],
+ [ 7/16, -depth/pitch*1.07]
+ ];
+ trapezoidal_threaded_rod(
+ d=d, l=l, pitch=pitch,
+ thread_depth=depth,
+ thread_angle=30,
+ profile=profile,
+ left_handed=left_handed,
+ bevel=bevel,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -439,28 +439,28 @@ module threaded_rod(
// Examples(Med):
// threaded_nut(od=16, id=8, h=8, pitch=1.25, left_handed=true, $slop=0.2, $fa=1, $fs=1);
module threaded_nut(
- od=16, id=10, h=10,
- pitch=2, left_handed=false, bevel=false,
- anchor=CENTER, spin=0, orient=UP
+ od=16, id=10, h=10,
+ pitch=2, left_handed=false, bevel=false,
+ anchor=CENTER, spin=0, orient=UP
) {
- depth = pitch * cos(30) * 5/8;
- profile = [
- [-6/16, -depth/pitch],
- [-1/16, 0],
- [-1/32, 0.02],
- [ 1/32, 0.02],
- [ 1/16, 0],
- [ 6/16, -depth/pitch]
- ];
- trapezoidal_threaded_nut(
- od=od, id=id, h=h,
- pitch=pitch, thread_angle=30,
- profile=profile,
- left_handed=left_handed,
- bevel=bevel,
- anchor=anchor, spin=spin,
- orient=orient
- ) children();
+ depth = pitch * cos(30) * 5/8;
+ profile = [
+ [-6/16, -depth/pitch],
+ [-1/16, 0],
+ [-1/32, 0.02],
+ [ 1/32, 0.02],
+ [ 1/16, 0],
+ [ 6/16, -depth/pitch]
+ ];
+ trapezoidal_threaded_nut(
+ od=od, id=id, h=h,
+ pitch=pitch, thread_angle=30,
+ profile=profile,
+ left_handed=left_handed,
+ bevel=bevel,
+ anchor=anchor, spin=spin,
+ orient=orient
+ ) children();
}
@@ -488,34 +488,34 @@ module threaded_nut(
// buttress_threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
// buttress_threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1);
module buttress_threaded_rod(
- d=10, l=100, pitch=2,
- left_handed=false,
- bevel=false,
- internal=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2,
+ left_handed=false,
+ bevel=false,
+ internal=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- depth = pitch * 3/4;
- profile = [
- [ -7/16, -0.75],
- [ 5/16, 0],
- [ 7/16, 0],
- [ 7/16, -0.75],
- [ 1/ 2, -0.77],
- ];
- trapezoidal_threaded_rod(
- d=d, l=l, pitch=pitch,
- thread_depth=depth,
- thread_angle=30,
- profile=profile,
- left_handed=left_handed,
- bevel=bevel,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ depth = pitch * 3/4;
+ profile = [
+ [ -7/16, -0.75],
+ [ 5/16, 0],
+ [ 7/16, 0],
+ [ 7/16, -0.75],
+ [ 1/ 2, -0.77],
+ ];
+ trapezoidal_threaded_rod(
+ d=d, l=l, pitch=pitch,
+ thread_depth=depth,
+ thread_angle=30,
+ profile=profile,
+ left_handed=left_handed,
+ bevel=bevel,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -538,31 +538,31 @@ module buttress_threaded_rod(
// Examples(Med):
// buttress_threaded_nut(od=16, id=8, h=8, pitch=1.25, left_handed=true, $slop=0.2, $fa=1, $fs=1);
module buttress_threaded_nut(
- od=16, id=10, h=10,
- pitch=2, left_handed=false,
- bevel=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ od=16, id=10, h=10,
+ pitch=2, left_handed=false,
+ bevel=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- depth = pitch * 3/4;
- profile = [
- [ -7/16, -0.75],
- [ 5/16, 0],
- [ 7/16, 0],
- [ 7/16, -0.75],
- [ 1/ 2, -0.77],
- ];
- trapezoidal_threaded_nut(
- od=od, id=id, h=h,
- pitch=pitch, thread_angle=30,
- profile=profile,
- thread_depth=pitch*3*sqrt(3)/8,
- left_handed=left_handed,
- bevel=bevel,
- anchor=anchor, spin=spin,
- orient=orient
- ) children();
+ depth = pitch * 3/4;
+ profile = [
+ [ -7/16, -0.75],
+ [ 5/16, 0],
+ [ 7/16, 0],
+ [ 7/16, -0.75],
+ [ 1/ 2, -0.77],
+ ];
+ trapezoidal_threaded_nut(
+ od=od, id=id, h=h,
+ pitch=pitch, thread_angle=30,
+ profile=profile,
+ thread_depth=pitch*3*sqrt(3)/8,
+ left_handed=left_handed,
+ bevel=bevel,
+ anchor=anchor, spin=spin,
+ orient=orient
+ ) children();
}
@@ -590,27 +590,27 @@ module buttress_threaded_nut(
// Examples(Med):
// metric_trapezoidal_threaded_rod(d=10, l=30, pitch=2, left_handed=true, $fa=1, $fs=1);
module metric_trapezoidal_threaded_rod(
- d=10, l=100, pitch=2,
- left_handed=false,
- starts=1,
- bevel=false,
- internal=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2,
+ left_handed=false,
+ starts=1,
+ bevel=false,
+ internal=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_rod(
- d=d, l=l,
- pitch=pitch,
- thread_angle=15,
- left_handed=left_handed,
- starts=starts,
- bevel=bevel,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_rod(
+ d=d, l=l,
+ pitch=pitch,
+ thread_angle=15,
+ left_handed=left_handed,
+ starts=starts,
+ bevel=bevel,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -634,25 +634,25 @@ module metric_trapezoidal_threaded_rod(
// Examples(Med):
// metric_trapezoidal_threaded_nut(od=16, id=10, h=10, pitch=2, left_handed=true, bevel=true, $fa=1, $fs=1);
module metric_trapezoidal_threaded_nut(
- od=17.4, id=10.5, h=10,
- pitch=3.175,
- starts=1,
- left_handed=false,
- bevel=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ od=17.4, id=10.5, h=10,
+ pitch=3.175,
+ starts=1,
+ left_handed=false,
+ bevel=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_nut(
- od=od, id=id, h=h,
- pitch=pitch, thread_angle=15,
- left_handed=left_handed,
- starts=starts,
- bevel=bevel,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_nut(
+ od=od, id=id, h=h,
+ pitch=pitch, thread_angle=15,
+ left_handed=left_handed,
+ starts=starts,
+ bevel=bevel,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -683,29 +683,29 @@ module metric_trapezoidal_threaded_nut(
// acme_threaded_rod(d=3/8*25.4, l=20, pitch=1/8*25.4, $fn=32);
// acme_threaded_rod(d=10, l=30, pitch=2, starts=3, $fa=1, $fs=1);
module acme_threaded_rod(
- d=10, l=100, pitch=2,
- thread_angle=14.5,
- thread_depth=undef,
- starts=1,
- left_handed=false,
- bevel=false,
- internal=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2,
+ thread_angle=14.5,
+ thread_depth=undef,
+ starts=1,
+ left_handed=false,
+ bevel=false,
+ internal=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_rod(
- d=d, l=l, pitch=pitch,
- thread_angle=thread_angle,
- thread_depth=thread_depth,
- starts=starts,
- left_handed=left_handed,
- bevel=bevel,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_rod(
+ d=d, l=l, pitch=pitch,
+ thread_angle=thread_angle,
+ thread_depth=thread_depth,
+ starts=starts,
+ left_handed=left_handed,
+ bevel=bevel,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -731,27 +731,27 @@ module acme_threaded_rod(
// acme_threaded_nut(od=16, id=3/8*25.4, h=8, pitch=1/8*25.4, $slop=0.2);
// acme_threaded_nut(od=16, id=10, h=10, pitch=2, starts=3, $slop=0.2, $fa=1, $fs=1);
module acme_threaded_nut(
- od, id, h, pitch,
- thread_angle=14.5,
- thread_depth=undef,
- starts=1,
- left_handed=false,
- bevel=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ od, id, h, pitch,
+ thread_angle=14.5,
+ thread_depth=undef,
+ starts=1,
+ left_handed=false,
+ bevel=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_nut(
- od=od, id=id, h=h, pitch=pitch,
- thread_depth=thread_depth,
- thread_angle=thread_angle,
- left_handed=left_handed,
- bevel=bevel,
- starts=starts,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_nut(
+ od=od, id=id, h=h, pitch=pitch,
+ thread_depth=thread_depth,
+ thread_angle=thread_angle,
+ left_handed=left_handed,
+ bevel=bevel,
+ starts=starts,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -779,26 +779,26 @@ module acme_threaded_nut(
// Examples(Med):
// square_threaded_rod(d=10, l=20, pitch=2, starts=2, $fn=32);
module square_threaded_rod(
- d=10, l=100, pitch=2,
- left_handed=false,
- bevel=false,
- starts=1,
- internal=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2,
+ left_handed=false,
+ bevel=false,
+ starts=1,
+ internal=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_rod(
- d=d, l=l, pitch=pitch,
- thread_angle=0,
- left_handed=left_handed,
- bevel=bevel,
- starts=starts,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_rod(
+ d=d, l=l, pitch=pitch,
+ thread_angle=0,
+ left_handed=left_handed,
+ bevel=bevel,
+ starts=starts,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -822,25 +822,25 @@ module square_threaded_rod(
// Examples(Med):
// square_threaded_nut(od=16, id=10, h=10, pitch=2, starts=2, $slop=0.15, $fn=32);
module square_threaded_nut(
- od=17.4, id=10.5, h=10,
- pitch=3.175,
- left_handed=false,
- bevel=false,
- starts=1,
- anchor=CENTER,
- spin=0,
- orient=UP
+ od=17.4, id=10.5, h=10,
+ pitch=3.175,
+ left_handed=false,
+ bevel=false,
+ starts=1,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- trapezoidal_threaded_nut(
- od=od, id=id, h=h, pitch=pitch,
- thread_angle=0,
- left_handed=left_handed,
- bevel=bevel,
- starts=starts,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ trapezoidal_threaded_nut(
+ od=od, id=id, h=h, pitch=pitch,
+ thread_angle=0,
+ left_handed=left_handed,
+ bevel=bevel,
+ starts=starts,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
@@ -874,32 +874,32 @@ module square_threaded_nut(
// ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, $fa=1, $fs=1);
// ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, left_handed=true, $fa=1, $fs=1);
module ball_screw_rod(
- d=10, l=100, pitch=2, starts=1,
- ball_diam=5, ball_arc=100,
- left_handed=false,
- internal=false,
- bevel=false,
- anchor=CENTER,
- spin=0,
- orient=UP
+ d=10, l=100, pitch=2, starts=1,
+ ball_diam=5, ball_arc=100,
+ left_handed=false,
+ internal=false,
+ bevel=false,
+ anchor=CENTER,
+ spin=0,
+ orient=UP
) {
- depth = ball_diam * (1-cos(ball_arc/2))/2;
- profile = arc(N=11, d=ball_diam/pitch, cp=[0,ball_diam/2/pitch*cos(ball_arc/2)], start=270-ball_arc/2, angle=ball_arc);
- trapezoidal_threaded_rod(
- d=d, l=l, pitch=pitch,
- thread_depth=depth,
- thread_angle=90-ball_arc/2,
- profile=profile,
- left_handed=left_handed,
- starts=starts,
- bevel=bevel,
- internal=internal,
- anchor=anchor,
- spin=spin,
- orient=orient
- ) children();
+ depth = ball_diam * (1-cos(ball_arc/2))/2;
+ profile = arc(N=11, d=ball_diam/pitch, cp=[0,ball_diam/2/pitch*cos(ball_arc/2)], start=270-ball_arc/2, angle=ball_arc);
+ trapezoidal_threaded_rod(
+ d=d, l=l, pitch=pitch,
+ thread_depth=depth,
+ thread_angle=90-ball_arc/2,
+ profile=profile,
+ left_handed=left_handed,
+ starts=starts,
+ bevel=bevel,
+ internal=internal,
+ anchor=anchor,
+ spin=spin,
+ orient=orient
+ ) children();
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/torx_drive.scad b/torx_drive.scad
index 573d1e8..1206b33 100644
--- a/torx_drive.scad
+++ b/torx_drive.scad
@@ -17,22 +17,22 @@
// Arguments:
// size = Torx size.
function torx_outer_diam(size) = lookup(size, [
- [ 6, 1.75],
- [ 8, 2.40],
- [ 10, 2.80],
- [ 15, 3.35],
- [ 20, 3.95],
- [ 25, 4.50],
- [ 30, 5.60],
- [ 40, 6.75],
- [ 45, 7.93],
- [ 50, 8.95],
- [ 55, 11.35],
- [ 60, 13.45],
- [ 70, 15.70],
- [ 80, 17.75],
- [ 90, 20.20],
- [100, 22.40]
+ [ 6, 1.75],
+ [ 8, 2.40],
+ [ 10, 2.80],
+ [ 15, 3.35],
+ [ 20, 3.95],
+ [ 25, 4.50],
+ [ 30, 5.60],
+ [ 40, 6.75],
+ [ 45, 7.93],
+ [ 50, 8.95],
+ [ 55, 11.35],
+ [ 60, 13.45],
+ [ 70, 15.70],
+ [ 80, 17.75],
+ [ 90, 20.20],
+ [100, 22.40]
]);
@@ -41,22 +41,22 @@ function torx_outer_diam(size) = lookup(size, [
// Arguments:
// size = Torx size.
function torx_inner_diam(size) = lookup(size, [
- [ 6, 1.27],
- [ 8, 1.75],
- [ 10, 2.05],
- [ 15, 2.40],
- [ 20, 2.85],
- [ 25, 3.25],
- [ 30, 4.05],
- [ 40, 4.85],
- [ 45, 5.64],
- [ 50, 6.45],
- [ 55, 8.05],
- [ 60, 9.60],
- [ 70, 11.20],
- [ 80, 12.80],
- [ 90, 14.40],
- [100, 16.00]
+ [ 6, 1.27],
+ [ 8, 1.75],
+ [ 10, 2.05],
+ [ 15, 2.40],
+ [ 20, 2.85],
+ [ 25, 3.25],
+ [ 30, 4.05],
+ [ 40, 4.85],
+ [ 45, 5.64],
+ [ 50, 6.45],
+ [ 55, 8.05],
+ [ 60, 9.60],
+ [ 70, 11.20],
+ [ 80, 12.80],
+ [ 90, 14.40],
+ [100, 16.00]
]);
@@ -65,22 +65,22 @@ function torx_inner_diam(size) = lookup(size, [
// Arguments:
// size = Torx size.
function torx_depth(size) = lookup(size, [
- [ 6, 1.82],
- [ 8, 3.05],
- [ 10, 3.56],
- [ 15, 3.81],
- [ 20, 4.07],
- [ 25, 4.45],
- [ 30, 4.95],
- [ 40, 5.59],
- [ 45, 6.22],
- [ 50, 6.48],
- [ 55, 6.73],
- [ 60, 8.17],
- [ 70, 8.96],
- [ 80, 9.90],
- [ 90, 10.56],
- [100, 11.35]
+ [ 6, 1.82],
+ [ 8, 3.05],
+ [ 10, 3.56],
+ [ 15, 3.81],
+ [ 20, 4.07],
+ [ 25, 4.45],
+ [ 30, 4.95],
+ [ 40, 5.59],
+ [ 45, 6.22],
+ [ 50, 6.48],
+ [ 55, 6.73],
+ [ 60, 8.17],
+ [ 70, 8.96],
+ [ 80, 9.90],
+ [ 90, 10.56],
+ [100, 11.35]
]);
@@ -89,22 +89,22 @@ function torx_depth(size) = lookup(size, [
// Arguments:
// size = Torx size.
function torx_tip_radius(size) = lookup(size, [
- [ 6, 0.132],
- [ 8, 0.190],
- [ 10, 0.229],
- [ 15, 0.267],
- [ 20, 0.305],
- [ 25, 0.375],
- [ 30, 0.451],
- [ 40, 0.546],
- [ 45, 0.574],
- [ 50, 0.775],
- [ 55, 0.867],
- [ 60, 1.067],
- [ 70, 1.194],
- [ 80, 1.526],
- [ 90, 1.530],
- [100, 1.720]
+ [ 6, 0.132],
+ [ 8, 0.190],
+ [ 10, 0.229],
+ [ 15, 0.267],
+ [ 20, 0.305],
+ [ 25, 0.375],
+ [ 30, 0.451],
+ [ 40, 0.546],
+ [ 45, 0.574],
+ [ 50, 0.775],
+ [ 55, 0.867],
+ [ 60, 1.067],
+ [ 70, 1.194],
+ [ 80, 1.526],
+ [ 90, 1.530],
+ [100, 1.720]
]);
@@ -113,22 +113,22 @@ function torx_tip_radius(size) = lookup(size, [
// Arguments:
// size = Torx size.
function torx_rounding_radius(size) = lookup(size, [
- [ 6, 0.383],
- [ 8, 0.510],
- [ 10, 0.598],
- [ 15, 0.716],
- [ 20, 0.859],
- [ 25, 0.920],
- [ 30, 1.194],
- [ 40, 1.428],
- [ 45, 1.796],
- [ 50, 1.816],
- [ 55, 2.667],
- [ 60, 2.883],
- [ 70, 3.477],
- [ 80, 3.627],
- [ 90, 4.468],
- [100, 4.925]
+ [ 6, 0.383],
+ [ 8, 0.510],
+ [ 10, 0.598],
+ [ 15, 0.716],
+ [ 20, 0.859],
+ [ 25, 0.920],
+ [ 30, 1.194],
+ [ 40, 1.428],
+ [ 45, 1.796],
+ [ 50, 1.816],
+ [ 55, 2.667],
+ [ 60, 2.883],
+ [ 70, 3.477],
+ [ 80, 3.627],
+ [ 90, 4.468],
+ [100, 4.925]
]);
@@ -142,33 +142,33 @@ function torx_rounding_radius(size) = lookup(size, [
// Example(2D):
// torx_drive2d(size=30, $fa=1, $fs=1);
module torx_drive2d(size) {
- od = torx_outer_diam(size);
- id = torx_inner_diam(size);
- tip = torx_tip_radius(size);
- rounding = torx_rounding_radius(size);
- base = od - 2*tip;
- $fn = quantup(segs(od/2),12);
- difference() {
- union() {
- circle(d=base);
- zrot_copies(n=2) {
- hull() {
- zrot_copies(n=3) {
- translate([base/2,0,0]) {
- circle(r=tip, $fn=$fn/2);
- }
- }
- }
- }
- }
- zrot_copies(n=6) {
- zrot(180/6) {
- translate([id/2+rounding,0,0]) {
- circle(r=rounding);
- }
- }
- }
- }
+ od = torx_outer_diam(size);
+ id = torx_inner_diam(size);
+ tip = torx_tip_radius(size);
+ rounding = torx_rounding_radius(size);
+ base = od - 2*tip;
+ $fn = quantup(segs(od/2),12);
+ difference() {
+ union() {
+ circle(d=base);
+ zrot_copies(n=2) {
+ hull() {
+ zrot_copies(n=3) {
+ translate([base/2,0,0]) {
+ circle(r=tip, $fn=$fn/2);
+ }
+ }
+ }
+ }
+ }
+ zrot_copies(n=6) {
+ zrot(180/6) {
+ translate([id/2+rounding,0,0]) {
+ circle(r=rounding);
+ }
+ }
+ }
+ }
}
@@ -185,17 +185,17 @@ module torx_drive2d(size) {
// Examples:
// torx_drive(size=30, l=10, $fa=1, $fs=1);
module torx_drive(size, l=5, center, anchor, spin=0, orient=UP) {
- anchor = get_anchor(anchor, center, BOT, BOT);
- od = torx_outer_diam(size);
- attachable(anchor,spin,orient, d=od, l=l) {
- linear_extrude(height=l, convexity=4, center=true) {
- torx_drive2d(size);
- }
- children();
- }
+ anchor = get_anchor(anchor, center, BOT, BOT);
+ od = torx_outer_diam(size);
+ attachable(anchor,spin,orient, d=od, l=l) {
+ linear_extrude(height=l, convexity=4, center=true) {
+ torx_drive2d(size);
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/transforms.scad b/transforms.scad
index c0e6d74..be73fbc 100644
--- a/transforms.scad
+++ b/transforms.scad
@@ -68,20 +68,20 @@
// mat3d = move([2,3,4]); // Returns: [[1,0,0,2],[0,1,0,3],[0,0,1,4],[0,0,0,1]]
module move(v=[0,0,0], x=0, y=0, z=0)
{
- translate(point3d(v)+[x,y,z]) children();
+ translate(point3d(v)+[x,y,z]) children();
}
function move(v=[0,0,0], p=undef, x=0, y=0, z=0) =
- is_undef(p)? (
- len(v)==2? affine2d_translate(v+[x,y]) :
- affine3d_translate(point3d(v)+[x,y,z])
- ) : (
- assert(is_list(p))
- let(v=v+[x,y,z])
- is_num(p.x)? p+v :
- is_vnf(p)? [move(v=v,p=p.x), p.y] :
- [for (l=p) is_vector(l)? l+v : move(v=v, p=l)]
- );
+ is_undef(p)? (
+ len(v)==2? affine2d_translate(v+[x,y]) :
+ affine3d_translate(point3d(v)+[x,y,z])
+ ) : (
+ assert(is_list(p))
+ let(v=v+[x,y,z])
+ is_num(p.x)? p+v :
+ is_vnf(p)? [move(v=v,p=p.x), p.y] :
+ [for (l=p) is_vector(l)? l+v : move(v=v, p=l)]
+ );
function translate(v=[0,0,0], p=undef) = move(v=v, p=p);
@@ -337,57 +337,57 @@ function up(z=0,p=undef) = move([0,0,z],p=p);
// stroke(rot(30,p=path), closed=true);
module rot(a=0, v=undef, cp=undef, from=undef, to=undef, reverse=false)
{
- m = rot(a=a, v=v, cp=cp, from=from, to=to, reverse=reverse, planar=false);
- multmatrix(m) children();
+ m = rot(a=a, v=v, cp=cp, from=from, to=to, reverse=reverse, planar=false);
+ multmatrix(m) children();
}
function rot(a=0, v, cp, from, to, reverse=false, planar=false, p, _m) =
- assert(is_undef(from)==is_undef(to), "from and to must be specified together.")
- is_undef(p)? (
- planar? let(
- cp = is_undef(cp)? cp : point2d(cp),
- m1 = is_undef(from)? affine2d_zrot(a) :
- assert(is_vector(from))
- assert(!approx(norm(from),0))
- assert(approx(point3d(from).z, 0))
- assert(is_vector(to))
- assert(!approx(norm(to),0))
- assert(approx(point3d(to).z, 0))
- affine2d_zrot(
- vang(point2d(to)) -
- vang(point2d(from))
- ),
- m2 = is_undef(cp)? m1 : (move(cp) * m1 * move(-cp)),
- m3 = reverse? matrix_inverse(m2) : m2
- ) m3 : let(
- from = is_undef(from)? undef : point3d(from),
- to = is_undef(to)? undef : point3d(to),
- cp = is_undef(cp)? undef : point3d(cp),
- m1 = !is_undef(from)? (
- assert(is_vector(from))
- assert(!approx(norm(from),0))
- assert(is_vector(to))
- assert(!approx(norm(to),0))
- affine3d_rot_from_to(from,to) * affine3d_zrot(a)
- ) :
- !is_undef(v)? affine3d_rot_by_axis(v,a) :
- is_num(a)? affine3d_zrot(a) :
- affine3d_zrot(a.z) * affine3d_yrot(a.y) * affine3d_xrot(a.x),
- m2 = is_undef(cp)? m1 : (move(cp) * m1 * move(-cp)),
- m3 = reverse? matrix_inverse(m2) : m2
- ) m3
- ) : (
- assert(is_list(p))
- let(
- m = !is_undef(_m)? _m :
- rot(a=a, v=v, cp=cp, from=from, to=to, reverse=reverse, planar=planar),
- res = p==[]? [] :
- is_vector(p)? apply(m, p) :
- is_vnf(p)? [apply(m, p[0]), p[1]] :
- is_list(p[0])? [for (pp=p) rot(p=pp, _m=m)] :
- assert(false, "The p argument for rot() is not a point, path, patch, matrix, or VNF.")
- ) res
- );
+ assert(is_undef(from)==is_undef(to), "from and to must be specified together.")
+ is_undef(p)? (
+ planar? let(
+ cp = is_undef(cp)? cp : point2d(cp),
+ m1 = is_undef(from)? affine2d_zrot(a) :
+ assert(is_vector(from))
+ assert(!approx(norm(from),0))
+ assert(approx(point3d(from).z, 0))
+ assert(is_vector(to))
+ assert(!approx(norm(to),0))
+ assert(approx(point3d(to).z, 0))
+ affine2d_zrot(
+ vang(point2d(to)) -
+ vang(point2d(from))
+ ),
+ m2 = is_undef(cp)? m1 : (move(cp) * m1 * move(-cp)),
+ m3 = reverse? matrix_inverse(m2) : m2
+ ) m3 : let(
+ from = is_undef(from)? undef : point3d(from),
+ to = is_undef(to)? undef : point3d(to),
+ cp = is_undef(cp)? undef : point3d(cp),
+ m1 = !is_undef(from)? (
+ assert(is_vector(from))
+ assert(!approx(norm(from),0))
+ assert(is_vector(to))
+ assert(!approx(norm(to),0))
+ affine3d_rot_from_to(from,to) * affine3d_zrot(a)
+ ) :
+ !is_undef(v)? affine3d_rot_by_axis(v,a) :
+ is_num(a)? affine3d_zrot(a) :
+ affine3d_zrot(a.z) * affine3d_yrot(a.y) * affine3d_xrot(a.x),
+ m2 = is_undef(cp)? m1 : (move(cp) * m1 * move(-cp)),
+ m3 = reverse? matrix_inverse(m2) : m2
+ ) m3
+ ) : (
+ assert(is_list(p))
+ let(
+ m = !is_undef(_m)? _m :
+ rot(a=a, v=v, cp=cp, from=from, to=to, reverse=reverse, planar=planar),
+ res = p==[]? [] :
+ is_vector(p)? apply(m, p) :
+ is_vnf(p)? [apply(m, p[0]), p[1]] :
+ is_list(p[0])? [for (pp=p) rot(p=pp, _m=m)] :
+ assert(false, "The p argument for rot() is not a point, path, patch, matrix, or VNF.")
+ ) res
+ );
@@ -421,13 +421,13 @@ function rot(a=0, v, cp, from, to, reverse=false, planar=false, p, _m) =
// xrot(90) cylinder(h=50, r=10, center=true);
module xrot(a=0, cp=undef)
{
- if (a==0) {
- children(); // May be slightly faster?
- } else if (!is_undef(cp)) {
- translate(cp) rotate([a, 0, 0]) translate(-cp) children();
- } else {
- rotate([a, 0, 0]) children();
- }
+ if (a==0) {
+ children(); // May be slightly faster?
+ } else if (!is_undef(cp)) {
+ translate(cp) rotate([a, 0, 0]) translate(-cp) children();
+ } else {
+ rotate([a, 0, 0]) children();
+ }
}
function xrot(a=0, cp=undef, p=undef) = rot([a,0,0], cp=cp, p=p);
@@ -462,13 +462,13 @@ function xrot(a=0, cp=undef, p=undef) = rot([a,0,0], cp=cp, p=p);
// yrot(90) cylinder(h=50, r=10, center=true);
module yrot(a=0, cp=undef)
{
- if (a==0) {
- children(); // May be slightly faster?
- } else if (!is_undef(cp)) {
- translate(cp) rotate([0, a, 0]) translate(-cp) children();
- } else {
- rotate([0, a, 0]) children();
- }
+ if (a==0) {
+ children(); // May be slightly faster?
+ } else if (!is_undef(cp)) {
+ translate(cp) rotate([0, a, 0]) translate(-cp) children();
+ } else {
+ rotate([0, a, 0]) children();
+ }
}
function yrot(a=0, cp=undef, p=undef) = rot([0,a,0], cp=cp, p=p);
@@ -503,13 +503,13 @@ function yrot(a=0, cp=undef, p=undef) = rot([0,a,0], cp=cp, p=p);
// zrot(90) cube(size=[60,20,40], center=true);
module zrot(a=0, cp=undef)
{
- if (a==0) {
- children(); // May be slightly faster?
- } else if (!is_undef(cp)) {
- translate(cp) rotate(a) translate(-cp) children();
- } else {
- rotate(a) children();
- }
+ if (a==0) {
+ children(); // May be slightly faster?
+ } else if (!is_undef(cp)) {
+ translate(cp) rotate(a) translate(-cp) children();
+ } else {
+ rotate(a) children();
+ }
}
function zrot(a=0, cp=undef, p=undef) = rot(a, cp=cp, p=p);
@@ -551,20 +551,20 @@ function zrot(a=0, cp=undef, p=undef) = rot(a, cp=cp, p=p);
// #stroke(path,closed=true);
// stroke(scale([1.5,3],p=path),closed=true);
function scale(v=1, p=undef) =
- assert(is_num(v) || is_vector(v))
- assert(is_undef(p) || is_list(p))
- let(v = is_num(v)? [v,v,v] : v)
- is_undef(p)? (
- len(v)==2? affine2d_scale(v) : affine3d_scale(point3d(v))
- ) : (
- assert(is_list(p))
- is_num(p.x)? vmul(p,v) :
- is_vnf(p)? let(inv=product([for (x=v) x<0? -1 : 1])) [
- scale(v=v,p=p.x),
- inv>=0? p.y : [for (l=p.y) reverse(l)]
- ] :
- [for (l=p) is_vector(l)? vmul(l,v) : scale(v=v, p=l)]
- );
+ assert(is_num(v) || is_vector(v))
+ assert(is_undef(p) || is_list(p))
+ let(v = is_num(v)? [v,v,v] : v)
+ is_undef(p)? (
+ len(v)==2? affine2d_scale(v) : affine3d_scale(point3d(v))
+ ) : (
+ assert(is_list(p))
+ is_num(p.x)? vmul(p,v) :
+ is_vnf(p)? let(inv=product([for (x=v) x<0? -1 : 1])) [
+ scale(v=v,p=p.x),
+ inv>=0? p.y : [for (l=p.y) reverse(l)]
+ ] :
+ [for (l=p) is_vector(l)? vmul(l,v) : scale(v=v, p=l)]
+ );
// Function&Module: xscale()
@@ -737,13 +737,13 @@ function zscale(z=1, p=undef) = scale([1,1,z],p=p);
// #stroke(path,closed=true);
// stroke(mirror(n, p=path),closed=true);
function mirror(v, p) =
- assert(is_vector(v))
- assert(is_undef(p) || is_list(p))
- let(m = len(v)==2? affine2d_mirror(v) : affine3d_mirror(v))
- is_undef(p)? m :
- is_num(p.x)? apply(m,p) :
- is_vnf(p)? [mirror(v=v,p=p[0]), [for (face=p[1]) reverse(face)]] :
- [for (l=p) is_vector(l)? apply(m,l) : mirror(v=v, p=l)];
+ assert(is_vector(v))
+ assert(is_undef(p) || is_list(p))
+ let(m = len(v)==2? affine2d_mirror(v) : affine3d_mirror(v))
+ is_undef(p)? m :
+ is_num(p.x)? apply(m,p) :
+ is_vnf(p)? [mirror(v=v,p=p[0]), [for (face=p[1]) reverse(face)]] :
+ [for (l=p) is_vector(l)? apply(m,l) : mirror(v=v, p=l)];
// Function&Module: xflip()
@@ -780,8 +780,8 @@ function mirror(v, p) =
module xflip(x=0) translate([x,0,0]) mirror([1,0,0]) translate([-x,0,0]) children();
function xflip(x=0,p) =
- x==0? mirror([1,0,0],p=p) :
- move([x,0,0],p=mirror([1,0,0],p=move([-x,0,0],p=p)));
+ x==0? mirror([1,0,0],p=p) :
+ move([x,0,0],p=mirror([1,0,0],p=move([-x,0,0],p=p)));
// Function&Module: yflip()
@@ -818,8 +818,8 @@ function xflip(x=0,p) =
module yflip(y=0) translate([0,y,0]) mirror([0,1,0]) translate([0,-y,0]) children();
function yflip(y=0,p) =
- y==0? mirror([0,1,0],p=p) :
- move([0,y,0],p=mirror([0,1,0],p=move([0,-y,0],p=p)));
+ y==0? mirror([0,1,0],p=p) :
+ move([0,y,0],p=mirror([0,1,0],p=move([0,-y,0],p=p)));
@@ -857,8 +857,8 @@ function yflip(y=0,p) =
module zflip(z=0) translate([0,0,z]) mirror([0,0,1]) translate([0,0,-z]) children();
function zflip(z=0,p) =
- z==0? mirror([0,0,1],p=p) :
- move([0,0,z],p=mirror([0,0,1],p=move([0,0,-z],p=p)));
+ z==0? mirror([0,0,1],p=p) :
+ move([0,0,z],p=mirror([0,0,1],p=move([0,0,-z],p=p)));
@@ -918,29 +918,29 @@ function zflip(z=0,p) =
// trace_polyline(close_path(pts), showpts=true);
module skew(sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0)
{
- multmatrix(
- affine3d_skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy)
- ) children();
+ multmatrix(
+ affine3d_skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy)
+ ) children();
}
function skew(p, sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0, planar=false) =
- let(
- planar = planar || (is_list(p) && is_num(p.x) && len(p)==2),
- m = planar? [
- [ 1, sxy, 0],
- [syx, 1, 0],
- [ 0, 0, 1]
- ] : affine3d_skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy)
- )
- is_undef(p)? m :
- assert(is_list(p))
- is_num(p.x)? (
- planar?
- point2d(m*concat(point2d(p),[1])) :
- point3d(m*concat(point3d(p),[1]))
- ) :
- is_vnf(p)? [skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy, planar=planar, p=p.x), p.y] :
- [for (l=p) skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy, planar=planar, p=l)];
+ let(
+ planar = planar || (is_list(p) && is_num(p.x) && len(p)==2),
+ m = planar? [
+ [ 1, sxy, 0],
+ [syx, 1, 0],
+ [ 0, 0, 1]
+ ] : affine3d_skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy)
+ )
+ is_undef(p)? m :
+ assert(is_list(p))
+ is_num(p.x)? (
+ planar?
+ point2d(m*concat(point2d(p),[1])) :
+ point3d(m*concat(point3d(p),[1]))
+ ) :
+ is_vnf(p)? [skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy, planar=planar, p=p.x), p.y] :
+ [for (l=p) skew(sxy=sxy, sxz=sxz, syx=syx, syz=syz, szx=szx, szy=szy, planar=planar, p=l)];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/triangulation.scad b/triangulation.scad
index 3da350d..9dbd2ef 100644
--- a/triangulation.scad
+++ b/triangulation.scad
@@ -20,17 +20,17 @@
// points = Array of vertices for the polyhedron.
// face = The face, given as a list of indices into the vertex array `points`.
function face_normal(points, face) =
- let(count=len(face))
- unit(
- sum(
- [
- for(i=[0:1:count-1]) cross(
- points[face[(i+1)%count]]-points[face[0]],
- points[face[(i+2)%count]]-points[face[(i+1)%count]]
- )
- ]
- )
- )
+ let(count=len(face))
+ unit(
+ sum(
+ [
+ for(i=[0:1:count-1]) cross(
+ points[face[(i+1)%count]]-points[face[0]],
+ points[face[(i+2)%count]]-points[face[(i+1)%count]]
+ )
+ ]
+ )
+ )
;
@@ -42,16 +42,16 @@ function face_normal(points, face) =
// face = The face, given as a list of indices into the vertex array `points`.
// facenorm = The normal vector of the face.
function find_convex_vertex(points, face, facenorm, i=0) =
- let(count=len(face),
- p0=points[face[i]],
- p1=points[face[(i+1)%count]],
- p2=points[face[(i+2)%count]]
- )
- (len(face)>i)? (
- (cross(p1-p0, p2-p1)*facenorm>0)? (i+1)%count :
- find_convex_vertex(points, face, facenorm, i+1)
- ) : //This should never happen since there is at least 1 convex vertex.
- undef
+ let(count=len(face),
+ p0=points[face[i]],
+ p1=points[face[(i+1)%count]],
+ p2=points[face[(i+2)%count]]
+ )
+ (len(face)>i)? (
+ (cross(p1-p0, p2-p1)*facenorm>0)? (i+1)%count :
+ find_convex_vertex(points, face, facenorm, i+1)
+ ) : //This should never happen since there is at least 1 convex vertex.
+ undef
;
@@ -61,27 +61,27 @@ function find_convex_vertex(points, face, facenorm, i=0) =
// points = Array of vertices for the polyhedron.
// face = The face, given as a list of indices into the vertex array `points`.
function point_in_ear(points, face, tests, i=0) =
- (iprev[0])? [test, i] : prev
- :
- [_check_point_in_ear(points[face[i]], tests), i]
+ (iprev[0])? [test, i] : prev
+ :
+ [_check_point_in_ear(points[face[i]], tests), i]
;
// Internal non-exposed function.
function _check_point_in_ear(point, tests) =
- let(
- result=[
- (point*tests[0][0])-tests[0][1],
- (point*tests[1][0])-tests[1][1],
- (point*tests[2][0])-tests[2][1]
- ]
- )
- (result[0]>0 && result[1]>0 && result[2]>0)? result[0] : -1
+ let(
+ result=[
+ (point*tests[0][0])-tests[0][1],
+ (point*tests[1][0])-tests[1][1],
+ (point*tests[2][0])-tests[2][1]
+ ]
+ )
+ (result[0]>0 && result[1]>0 && result[2]>0)? result[0] : -1
;
@@ -90,10 +90,10 @@ function _check_point_in_ear(point, tests) =
// Arguments:
// v = The array to normalize.
function normalize_vertex_perimeter(v) =
- let(lv = len(v))
- (lv < 2)? v :
- (v[lv-1] != v[0])? v :
- [for (i=[0:1:lv-2]) v[i]]
+ let(lv = len(v))
+ (lv < 2)? v :
+ (v[lv-1] != v[0])? v :
+ [for (i=[0:1:lv-2]) v[i]]
;
@@ -106,20 +106,20 @@ function normalize_vertex_perimeter(v) =
// facelist = The face, given as a list of indices into the vertex array `points`.
// vertex = The index into `facelist`, of the vertex to test.
function is_only_noncolinear_vertex(points, facelist, vertex) =
- let(
- face=select(facelist, vertex+1, vertex-1),
- count=len(face)
- )
- 0==sum(
- [
- for(i=[0:1:count-1]) norm(
- cross(
- points[face[(i+1)%count]]-points[face[0]],
- points[face[(i+2)%count]]-points[face[(i+1)%count]]
- )
- )
- ]
- )
+ let(
+ face=select(facelist, vertex+1, vertex-1),
+ count=len(face)
+ )
+ 0==sum(
+ [
+ for(i=[0:1:count-1]) norm(
+ cross(
+ points[face[(i+1)%count]]-points[face[0]],
+ points[face[(i+2)%count]]-points[face[(i+1)%count]]
+ )
+ )
+ ]
+ )
;
@@ -131,50 +131,50 @@ function is_only_noncolinear_vertex(points, facelist, vertex) =
// points = Array of vertices for the polyhedron.
// face = The face, given as a list of indices into the vertex array `points`.
function triangulate_face(points, face) =
- let(
- face = deduplicate_indexed(points,face),
- count = len(face)
- )
- (count < 3)? [] :
- (count == 3)? [face] :
- let(
- facenorm=face_normal(points, face),
- cv=find_convex_vertex(points, face, facenorm)
- )
- assert(!is_undef(cv), "Cannot triangulate self-crossing face perimeters.")
- let(
- pv=(count+cv-1)%count,
- nv=(cv+1)%count,
- p0=points[face[pv]],
- p1=points[face[cv]],
- p2=points[face[nv]],
- tests=[
- [cross(facenorm, p0-p2), cross(facenorm, p0-p2)*p0],
- [cross(facenorm, p1-p0), cross(facenorm, p1-p0)*p1],
- [cross(facenorm, p2-p1), cross(facenorm, p2-p1)*p2]
- ],
- ear_test=point_in_ear(points, face, tests),
- clipable_ear=(ear_test[0]<0),
- diagonal_point=ear_test[1]
- )
- (clipable_ear)? // There is no point inside the ear.
- is_only_noncolinear_vertex(points, face, cv)?
- // In the point&line degeneracy clip to somewhere in the middle of the line.
- flatten([
- triangulate_face(points, select(face, cv, (cv+2)%count)),
- triangulate_face(points, select(face, (cv+2)%count, cv))
- ])
- :
- // Otherwise the ear is safe to clip.
- flatten([
- [select(face, pv, nv)],
- triangulate_face(points, select(face, nv, pv))
- ])
- : // If there is a point inside the ear, make a diagonal and clip along that.
- flatten([
- triangulate_face(points, select(face, cv, diagonal_point)),
- triangulate_face(points, select(face, diagonal_point, cv))
- ]);
+ let(
+ face = deduplicate_indexed(points,face),
+ count = len(face)
+ )
+ (count < 3)? [] :
+ (count == 3)? [face] :
+ let(
+ facenorm=face_normal(points, face),
+ cv=find_convex_vertex(points, face, facenorm)
+ )
+ assert(!is_undef(cv), "Cannot triangulate self-crossing face perimeters.")
+ let(
+ pv=(count+cv-1)%count,
+ nv=(cv+1)%count,
+ p0=points[face[pv]],
+ p1=points[face[cv]],
+ p2=points[face[nv]],
+ tests=[
+ [cross(facenorm, p0-p2), cross(facenorm, p0-p2)*p0],
+ [cross(facenorm, p1-p0), cross(facenorm, p1-p0)*p1],
+ [cross(facenorm, p2-p1), cross(facenorm, p2-p1)*p2]
+ ],
+ ear_test=point_in_ear(points, face, tests),
+ clipable_ear=(ear_test[0]<0),
+ diagonal_point=ear_test[1]
+ )
+ (clipable_ear)? // There is no point inside the ear.
+ is_only_noncolinear_vertex(points, face, cv)?
+ // In the point&line degeneracy clip to somewhere in the middle of the line.
+ flatten([
+ triangulate_face(points, select(face, cv, (cv+2)%count)),
+ triangulate_face(points, select(face, (cv+2)%count, cv))
+ ])
+ :
+ // Otherwise the ear is safe to clip.
+ flatten([
+ [select(face, pv, nv)],
+ triangulate_face(points, select(face, nv, pv))
+ ])
+ : // If there is a point inside the ear, make a diagonal and clip along that.
+ flatten([
+ triangulate_face(points, select(face, cv, diagonal_point)),
+ triangulate_face(points, select(face, diagonal_point, cv))
+ ]);
// Function: triangulate_faces()
@@ -185,11 +185,11 @@ function triangulate_face(points, face) =
// points = Array of vertices for the polyhedron.
// faces = Array of faces for the polyhedron. Each face is a list of 3 or more indices into the `points` array.
function triangulate_faces(points, faces) =
- [
- for (face=faces) each
- len(face)==3? [face] :
- triangulate_face(points, normalize_vertex_perimeter(face))
- ];
+ [
+ for (face=faces) each
+ len(face)==3? [face] :
+ triangulate_face(points, normalize_vertex_perimeter(face))
+ ];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/vectors.scad b/vectors.scad
index d0bf251..8a96590 100644
--- a/vectors.scad
+++ b/vectors.scad
@@ -31,8 +31,8 @@
// is_vector([]); // Returns false
// is_vector([3,undef,undef,true], fast=true); // Returns true
function is_vector(v,length,fast=false) =
- (fast? (is_list(v) && is_num(v[0])) : is_list_of(v,0)) &&
- len(v) && (is_undef(length) || length==len(v));
+ (fast? (is_list(v) && is_num(v[0])) : is_list_of(v,0)) &&
+ len(v) && (is_undef(length) || length==len(v));
// Function: add_scalar()
@@ -58,8 +58,8 @@ function add_scalar(v,s) = [for (x=v) is_list(x)? add_scalar(x,s) : x+s];
// Given a 2D vector, returns the angle in degrees counter-clockwise from X+ on the XY plane.
// Given a 3D vector, returns [THETA,PHI] where THETA is the number of degrees counter-clockwise from X+ on the XY plane, and PHI is the number of degrees up from the X+ axis along the XZ plane.
function vang(v) =
- len(v)==2? atan2(v.y,v.x) :
- let(res=xyz_to_spherical(v)) [res[1], 90-res[2]];
+ len(v)==2? atan2(v.y,v.x) :
+ let(res=xyz_to_spherical(v)) [res[1], 90-res[2]];
// Function: vmul()
@@ -144,22 +144,22 @@ function unit(v) = assert(is_vector(v),str(v)) norm(v)<=EPSILON? v : v/norm(v);
// vector_angle([10,0,10], [0,0,0], [-10,10,0]); // Returns: 120
// vector_angle([[10,0,10], [0,0,0], [-10,10,0]]); // Returns: 120
function vector_angle(v1,v2,v3) =
- let(
- vecs = !is_undef(v3)? [v1-v2,v3-v2] :
- !is_undef(v2)? [v1,v2] :
- len(v1) == 3? [v1[0]-v1[1],v1[2]-v1[1]] :
- len(v1) == 2? v1 :
- assert(false, "Bad arguments to vector_angle()"),
- is_valid = is_vector(vecs[0]) && is_vector(vecs[1]) && vecs[0]*0 == vecs[1]*0
- )
- assert(is_valid, "Bad arguments to vector_angle()")
- let(
- norm0 = norm(vecs[0]),
- norm1 = norm(vecs[1])
- )
- assert(norm0>0 && norm1>0,"Zero length vector given to vector_angle()")
- // NOTE: constrain() corrects crazy FP rounding errors that exceed acos()'s domain.
- acos(constrain((vecs[0]*vecs[1])/(norm0*norm1), -1, 1));
+ let(
+ vecs = !is_undef(v3)? [v1-v2,v3-v2] :
+ !is_undef(v2)? [v1,v2] :
+ len(v1) == 3? [v1[0]-v1[1],v1[2]-v1[1]] :
+ len(v1) == 2? v1 :
+ assert(false, "Bad arguments to vector_angle()"),
+ is_valid = is_vector(vecs[0]) && is_vector(vecs[1]) && vecs[0]*0 == vecs[1]*0
+ )
+ assert(is_valid, "Bad arguments to vector_angle()")
+ let(
+ norm0 = norm(vecs[0]),
+ norm1 = norm(vecs[1])
+ )
+ assert(norm0>0 && norm1>0,"Zero length vector given to vector_angle()")
+ // NOTE: constrain() corrects crazy FP rounding errors that exceed acos()'s domain.
+ acos(constrain((vecs[0]*vecs[1])/(norm0*norm1), -1, 1));
// Function: vector_axis()
@@ -184,22 +184,22 @@ function vector_angle(v1,v2,v3) =
// vector_axis([10,0,10], [0,0,0], [-10,10,0]); // Returns: [-0.57735, -0.57735, 0.57735]
// vector_axis([[10,0,10], [0,0,0], [-10,10,0]]); // Returns: [-0.57735, -0.57735, 0.57735]
function vector_axis(v1,v2=undef,v3=undef) =
- (is_list(v1) && is_list(v1[0]) && is_undef(v2) && is_undef(v3))? (
- assert(is_vector(v1.x))
- assert(is_vector(v1.y))
- len(v1)==3? assert(is_vector(v1.z)) vector_axis(v1.x, v1.y, v1.z) :
- len(v1)==2? vector_axis(v1.x, v1.y) :
- assert(false, "Bad arguments.")
- ) :
- (is_vector(v1) && is_vector(v2) && is_vector(v3))? vector_axis(v1-v2, v3-v2) :
- (is_vector(v1) && is_vector(v2) && is_undef(v3))? let(
- eps = 1e-6,
- v1 = point3d(v1/norm(v1)),
- v2 = point3d(v2/norm(v2)),
- v3 = (norm(v1-v2) > eps && norm(v1+v2) > eps)? v2 :
- (norm(vabs(v2)-UP) > eps)? UP :
- RIGHT
- ) unit(cross(v1,v3)) : assert(false, "Bad arguments.");
+ (is_list(v1) && is_list(v1[0]) && is_undef(v2) && is_undef(v3))? (
+ assert(is_vector(v1.x))
+ assert(is_vector(v1.y))
+ len(v1)==3? assert(is_vector(v1.z)) vector_axis(v1.x, v1.y, v1.z) :
+ len(v1)==2? vector_axis(v1.x, v1.y) :
+ assert(false, "Bad arguments.")
+ ) :
+ (is_vector(v1) && is_vector(v2) && is_vector(v3))? vector_axis(v1-v2, v3-v2) :
+ (is_vector(v1) && is_vector(v2) && is_undef(v3))? let(
+ eps = 1e-6,
+ v1 = point3d(v1/norm(v1)),
+ v2 = point3d(v2/norm(v2)),
+ v3 = (norm(v1-v2) > eps && norm(v1+v2) > eps)? v2 :
+ (norm(vabs(v2)-UP) > eps)? UP :
+ RIGHT
+ ) unit(cross(v1,v3)) : assert(false, "Bad arguments.");
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/version.scad b/version.scad
index 7847591..0f3004c 100644
--- a/version.scad
+++ b/version.scad
@@ -8,7 +8,7 @@
//////////////////////////////////////////////////////////////////////
-BOSL_VERSION = [2,0,331];
+BOSL_VERSION = [2,0,332];
// Section: BOSL Library Version Functions
@@ -49,27 +49,27 @@ function bosl_version_str() = version_to_str(BOSL_VERSION);
// Description:
// Given a version as a list, number, or string, asserts that the currently installed BOSL library is at least the given version.
module bosl_required(target) {
- assert(
- version_cmp(bosl_version(), target) >= 0,
- str(
- "BOSL ", bosl_version_str(), " is installed, but BOSL ",
- version_to_str(target), " or better is required."
- )
- );
+ assert(
+ version_cmp(bosl_version(), target) >= 0,
+ str(
+ "BOSL ", bosl_version_str(), " is installed, but BOSL ",
+ version_to_str(target), " or better is required."
+ )
+ );
}
// Section: Generic Version Functions
function _version_split_str(x, _i=0, _out=[], _num=0) =
- _i>=len(x)? concat(_out,[_num]) :
- let(
- cval = ord(x[_i]) - ord("0"),
- numend = cval<0 || cval>9,
- _out = numend? concat(_out, [_num]) : _out,
- _num = numend? 0 : (10*_num + cval)
- )
- _version_split_str(x, _i=_i+1, _out=_out, _num=_num);
+ _i>=len(x)? concat(_out,[_num]) :
+ let(
+ cval = ord(x[_i]) - ord("0"),
+ numend = cval<0 || cval>9,
+ _out = numend? concat(_out, [_num]) : _out,
+ _num = numend? 0 : (10*_num + cval)
+ )
+ _version_split_str(x, _i=_i+1, _out=_out, _num=_num);
// Function: version_to_list()
@@ -83,10 +83,10 @@ function _version_split_str(x, _i=0, _out=[], _num=0) =
// v3 = version_to_list([2,3,4]); // Returns: [2,3,4]
// v4 = version_to_list([2,3,4,5]); // Returns: [2,3,4]
function version_to_list(x) =
- is_list(x)? [default(x[0],0), default(x[1],0), default(x[2],0)] :
- is_string(x)? _version_split_str(x) :
- is_num(x)? [floor(x), floor(x*100%100), floor(x*1000000%10000+0.5)] :
- assert(is_num(x) || is_vector(x) || is_string(x)) 0;
+ is_list(x)? [default(x[0],0), default(x[1],0), default(x[2],0)] :
+ is_string(x)? _version_split_str(x) :
+ is_num(x)? [floor(x), floor(x*100%100), floor(x*1000000%10000+0.5)] :
+ assert(is_num(x) || is_vector(x) || is_string(x)) 0;
// Function: version_to_str()
@@ -100,8 +100,8 @@ function version_to_list(x) =
// v3 = version_to_str(2.340789); // Returns: "2.34.789"
// v4 = version_to_str("2.3.89"); // Returns: "2.3.89"
function version_to_str(x) =
- let(x = version_to_list(x))
- str(x[0],".",x[1],".",x[2]);
+ let(x = version_to_list(x))
+ str(x[0],".",x[1],".",x[2]);
// Function: version_to_num()
@@ -115,8 +115,8 @@ function version_to_str(x) =
// v3 = version_to_num(2.120567); // Returns: 2.120567
// v4 = version_to_num("2.6.79"); // Returns: 2.060079
function version_to_num(x) =
- let(x = version_to_list(x))
- (x[0]*1000000 + x[1]*10000 + x[2])/1000000;
+ let(x = version_to_list(x))
+ (x[0]*1000000 + x[1]*10000 + x[2])/1000000;
// Function: version_cmp()
@@ -130,11 +130,11 @@ function version_to_num(x) =
// cmp2 = version_cmp(2.010034, "2.1.34"); // Returns: 0
// cmp3 = version_cmp(2.010034, "2.1.35"); // Returns: <0
function version_cmp(a,b) =
- let(
- a = version_to_list(a),
- b = version_to_list(b),
- cmps = [for (i=[0:1:2]) if(a[i]!=b[i]) a[i]-b[i]]
- ) cmps==[]? 0 : cmps[0];
+ let(
+ a = version_to_list(a),
+ b = version_to_list(b),
+ cmps = [for (i=[0:1:2]) if(a[i]!=b[i]) a[i]-b[i]]
+ ) cmps==[]? 0 : cmps[0];
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/vnf.scad b/vnf.scad
index a6f716c..85858c4 100644
--- a/vnf.scad
+++ b/vnf.scad
@@ -29,12 +29,12 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
// Description:
// Returns true if the given value looks like a VNF structure.
function is_vnf(x) =
- is_list(x) &&
- len(x)==2 &&
- is_list(x[0]) &&
- is_list(x[1]) &&
- (x[0]==[] || (len(x[0])>=3 && is_vector(x[0][0]))) &&
- (x[1]==[] || is_vector(x[1][0]));
+ is_list(x) &&
+ len(x)==2 &&
+ is_list(x[0]) &&
+ is_list(x[1]) &&
+ (x[0]==[] || (len(x[0])>=3 && is_vector(x[0][0]))) &&
+ (x[1]==[] || is_vector(x[1][0]));
// Function: is_vnf_list()
@@ -61,7 +61,7 @@ function vnf_faces(vnf) = vnf[1];
// vnf = The VNF to quantize.
// q = The quanta to quantize the VNF coordinates to.
function vnf_quantize(vnf,q=pow(2,-12)) =
- [[for (pt = vnf[0]) quant(pt,q)], vnf[1]];
+ [[for (pt = vnf[0]) quant(pt,q)], vnf[1]];
// Function: vnf_get_vertex()
@@ -81,11 +81,11 @@ function vnf_quantize(vnf,q=pow(2,-12)) =
// vnf3 = vnf_get_vertex(vnf2, p=[3,5,8]); // Returns: [0, [[[3,5,8],[3,2,1]],[]]]
// vnf4 = vnf_get_vertex(vnf3, p=[[1,3,2],[3,2,1]]); // Returns: [[1,2], [[[3,5,8],[3,2,1],[1,3,2]],[]]]
function vnf_get_vertex(vnf=EMPTY_VNF, p) =
- let(
- p = is_vector(p)? [p] : p,
- res = set_union(vnf[0], p, get_indices=true)
- )
- [res[0], [res[1],vnf[1]]];
+ let(
+ p = is_vector(p)? [p] : p,
+ res = set_union(vnf[0], p, get_indices=true)
+ )
+ [res[0], [res[1],vnf[1]]];
// Function: vnf_add_face()
@@ -99,15 +99,15 @@ function vnf_get_vertex(vnf=EMPTY_VNF, p) =
// vnf = The VNF structure to add a face to.
// pts = The vertex points for the face.
function vnf_add_face(vnf=EMPTY_VNF, pts) =
- assert(is_vnf(vnf))
- assert(is_path(pts))
- let(
- res = set_union(vnf[0], pts, get_indices=true),
- face = deduplicate(res[0], closed=true)
- ) [
- res[1],
- concat(vnf[1], len(face)>2? [face] : [])
- ];
+ assert(is_vnf(vnf))
+ assert(is_path(pts))
+ let(
+ res = set_union(vnf[0], pts, get_indices=true),
+ face = deduplicate(res[0], closed=true)
+ ) [
+ res[1],
+ concat(vnf[1], len(face)>2? [face] : [])
+ ];
// Function: vnf_add_faces()
@@ -122,23 +122,23 @@ function vnf_add_face(vnf=EMPTY_VNF, pts) =
// vnf = The VNF structure to add a face to.
// faces = The list of faces, where each face is given as a list of vertex points.
function vnf_add_faces(vnf=EMPTY_VNF, faces) =
- assert(is_vnf(vnf))
- assert(is_list(faces))
- let(
- res = set_union(vnf[0], flatten(faces), get_indices=true),
- idxs = res[0],
- nverts = res[1],
- offs = cumsum([0, for (face=faces) len(face)]),
- ifaces = [
- for (i=idx(faces)) [
- for (j=idx(faces[i]))
- idxs[offs[i]+j]
- ]
- ]
- ) [
- nverts,
- concat(vnf[1],ifaces)
- ];
+ assert(is_vnf(vnf))
+ assert(is_list(faces))
+ let(
+ res = set_union(vnf[0], flatten(faces), get_indices=true),
+ idxs = res[0],
+ nverts = res[1],
+ offs = cumsum([0, for (face=faces) len(face)]),
+ ifaces = [
+ for (i=idx(faces)) [
+ for (j=idx(faces[i]))
+ idxs[offs[i]+j]
+ ]
+ ]
+ ) [
+ nverts,
+ concat(vnf[1],ifaces)
+ ];
// Function: vnf_merge()
@@ -147,14 +147,14 @@ function vnf_add_faces(vnf=EMPTY_VNF, faces) =
// Description:
// Given a list of VNF structures, merges them all into a single VNF structure.
function vnf_merge(vnfs=[],_i=0,_acc=EMPTY_VNF) =
- (assert(is_vnf_list(vnfs)) _i>=len(vnfs))? _acc :
- vnf_merge(
- vnfs, _i=_i+1,
- _acc = let(base=len(_acc[0])) [
- concat(_acc[0], vnfs[_i][0]),
- concat(_acc[1], [for (f=vnfs[_i][1]) [for (i=f) i+base]]),
- ]
- );
+ (assert(is_vnf_list(vnfs)) _i>=len(vnfs))? _acc :
+ vnf_merge(
+ vnfs, _i=_i+1,
+ _acc = let(base=len(_acc[0])) [
+ concat(_acc[0], vnfs[_i][0]),
+ concat(_acc[1], [for (f=vnfs[_i][1]) [for (i=f) i+base]]),
+ ]
+ );
// Function: vnf_compact()
// Usage:
@@ -162,15 +162,15 @@ function vnf_merge(vnfs=[],_i=0,_acc=EMPTY_VNF) =
// Description:
// Takes a VNF and consolidates all duplicate vertices, and drops unreferenced vertices.
function vnf_compact(vnf) =
- let(
- vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf,
- verts = vnf[0],
- faces = [
- for (face=vnf[1]) [
- for (i=face) verts[i]
- ]
- ]
- ) vnf_add_faces(faces=faces);
+ let(
+ vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf,
+ verts = vnf[0],
+ faces = [
+ for (face=vnf[1]) [
+ for (i=face) verts[i]
+ ]
+ ]
+ ) vnf_add_faces(faces=faces);
// Function: vnf_triangulate()
@@ -179,10 +179,10 @@ function vnf_compact(vnf) =
// Description:
// Forces triangulation of faces in the VNF that have more than 3 vertices.
function vnf_triangulate(vnf) =
- let(
- vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf,
- verts = vnf[0]
- ) [verts, triangulate_faces(verts, vnf[1])];
+ let(
+ vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf,
+ verts = vnf[0]
+ ) [verts, triangulate_faces(verts, vnf[1])];
// Function: vnf_vertex_array()
@@ -257,79 +257,79 @@ function vnf_triangulate(vnf) =
// vnf3 = vnf_vertex_array(points=cap2, col_wrap=true, reverse=true);
// vnf_polyhedron([vnf1, vnf2, vnf3]);
function vnf_vertex_array(
- points,
- caps, cap1, cap2,
- col_wrap=false,
- row_wrap=false,
- reverse=false,
- style="default",
- vnf=EMPTY_VNF
+ points,
+ caps, cap1, cap2,
+ col_wrap=false,
+ row_wrap=false,
+ reverse=false,
+ style="default",
+ vnf=EMPTY_VNF
) =
- assert((!caps)||(caps&&col_wrap))
- assert(in_list(style,["default","alt","quincunx"]))
+ assert((!caps)||(caps&&col_wrap))
+ assert(in_list(style,["default","alt","quincunx"]))
assert(is_consistent(points), "Non-rectangular or invalid point array")
- let(
- pts = flatten(points),
- pcnt = len(pts),
- rows = len(points),
- cols = len(points[0]),
- cap1 = first_defined([cap1,caps,false]),
- cap2 = first_defined([cap2,caps,false]),
- colcnt = cols - (col_wrap?0:1),
- rowcnt = rows - (row_wrap?0:1)
- )
- rows<=1 || cols<=1 ? vnf :
- vnf_merge([
- vnf, [
- concat(
- pts,
- style!="quincunx"? [] : [
- for (r = [0:1:rowcnt-1]) (
- for (c = [0:1:colcnt-1]) (
- let(
- i1 = ((r+0)%rows)*cols + ((c+0)%cols),
- i2 = ((r+1)%rows)*cols + ((c+0)%cols),
- i3 = ((r+1)%rows)*cols + ((c+1)%cols),
- i4 = ((r+0)%rows)*cols + ((c+1)%cols)
- ) mean([pts[i1], pts[i2], pts[i3], pts[i4]])
- )
- )
- ]
- ),
- concat(
- [
- for (r = [0:1:rowcnt-1]) (
- for (c = [0:1:colcnt-1]) each (
- let(
- i1 = ((r+0)%rows)*cols + ((c+0)%cols),
- i2 = ((r+1)%rows)*cols + ((c+0)%cols),
- i3 = ((r+1)%rows)*cols + ((c+1)%cols),
- i4 = ((r+0)%rows)*cols + ((c+1)%cols)
- )
- style=="quincunx"? (
- let(i5 = pcnt + r*colcnt + c)
- reverse? [[i1,i2,i5],[i2,i3,i5],[i3,i4,i5],[i4,i1,i5]] : [[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]]
- ) : style=="alt"? (
- reverse? [[i1,i2,i4],[i2,i3,i4]] : [[i1,i4,i2],[i2,i4,i3]]
- ) : (
- reverse? [[i1,i2,i3],[i1,i3,i4]] : [[i1,i3,i2],[i1,i4,i3]]
- )
- )
- )
- ],
- !cap1? [] : [
- reverse?
- [for (c = [0:1:cols-1]) c] :
- [for (c = [cols-1:-1:0]) c]
- ],
- !cap2? [] : [
- reverse?
- [for (c = [cols-1:-1:0]) (rows-1)*cols + c] :
- [for (c = [0:1:cols-1]) (rows-1)*cols + c]
- ]
- )
- ]
- ]);
+ let(
+ pts = flatten(points),
+ pcnt = len(pts),
+ rows = len(points),
+ cols = len(points[0]),
+ cap1 = first_defined([cap1,caps,false]),
+ cap2 = first_defined([cap2,caps,false]),
+ colcnt = cols - (col_wrap?0:1),
+ rowcnt = rows - (row_wrap?0:1)
+ )
+ rows<=1 || cols<=1 ? vnf :
+ vnf_merge([
+ vnf, [
+ concat(
+ pts,
+ style!="quincunx"? [] : [
+ for (r = [0:1:rowcnt-1]) (
+ for (c = [0:1:colcnt-1]) (
+ let(
+ i1 = ((r+0)%rows)*cols + ((c+0)%cols),
+ i2 = ((r+1)%rows)*cols + ((c+0)%cols),
+ i3 = ((r+1)%rows)*cols + ((c+1)%cols),
+ i4 = ((r+0)%rows)*cols + ((c+1)%cols)
+ ) mean([pts[i1], pts[i2], pts[i3], pts[i4]])
+ )
+ )
+ ]
+ ),
+ concat(
+ [
+ for (r = [0:1:rowcnt-1]) (
+ for (c = [0:1:colcnt-1]) each (
+ let(
+ i1 = ((r+0)%rows)*cols + ((c+0)%cols),
+ i2 = ((r+1)%rows)*cols + ((c+0)%cols),
+ i3 = ((r+1)%rows)*cols + ((c+1)%cols),
+ i4 = ((r+0)%rows)*cols + ((c+1)%cols)
+ )
+ style=="quincunx"? (
+ let(i5 = pcnt + r*colcnt + c)
+ reverse? [[i1,i2,i5],[i2,i3,i5],[i3,i4,i5],[i4,i1,i5]] : [[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]]
+ ) : style=="alt"? (
+ reverse? [[i1,i2,i4],[i2,i3,i4]] : [[i1,i4,i2],[i2,i4,i3]]
+ ) : (
+ reverse? [[i1,i2,i3],[i1,i3,i4]] : [[i1,i3,i2],[i1,i4,i3]]
+ )
+ )
+ )
+ ],
+ !cap1? [] : [
+ reverse?
+ [for (c = [0:1:cols-1]) c] :
+ [for (c = [cols-1:-1:0]) c]
+ ],
+ !cap2? [] : [
+ reverse?
+ [for (c = [cols-1:-1:0]) (rows-1)*cols + c] :
+ [for (c = [0:1:cols-1]) (rows-1)*cols + c]
+ ]
+ )
+ ]
+ ]);
// Module: vnf_polyhedron()
@@ -342,8 +342,8 @@ function vnf_vertex_array(
// vnf = A VNF structure, or list of VNF structures.
// convexity = Max number of times a line could intersect a wall of the shape.
module vnf_polyhedron(vnf, convexity=2) {
- vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf;
- polyhedron(vnf[0], vnf[1], convexity=convexity);
+ vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf;
+ polyhedron(vnf[0], vnf[1], convexity=convexity);
}
@@ -358,15 +358,15 @@ module vnf_polyhedron(vnf, convexity=2) {
// no holes; otherwise the results are undefined. Returns a positive volume if face direction is clockwise and a negative volume
// if face direction is counter-clockwise.
function vnf_volume(vnf) =
- let(
- vnf = vnf_triangulate(vnf),
- verts = vnf[0]
- ) sum([
- for(face_index=vnf[1]) let(
- face = select(verts, face_index),
- n = cross(face[2]-face[0],face[1]-face[0])
- ) face[0] * n
- ])/6;
+ let(
+ vnf = vnf_triangulate(vnf),
+ verts = vnf[0]
+ ) sum([
+ for(face_index=vnf[1]) let(
+ face = select(verts, face_index),
+ n = cross(face[2]-face[0],face[1]-face[0])
+ ) face[0] * n
+ ])/6;
// Function: vnf_centroid()
@@ -378,36 +378,36 @@ function vnf_volume(vnf) =
// Algorithm from: https://wwwf.imperial.ac.uk/~rn/centroid.pdf
function vnf_centroid(vnf) =
- let(
- vnf = vnf_triangulate(vnf),
- verts = vnf[0],
- val=sum([
- for(face_index=vnf[1])
- let(
- face = select(verts, face_index),
- n = cross(face[2]-face[0],face[1]-face[0])
- ) [
- face[0] * n,
- vmul(n,
- sqr(face[0] + face[1]) +
- sqr(face[0] + face[2]) +
- sqr(face[1] + face[2])
- )
- ]
- ])
- ) val[1]/val[0]/8;
+ let(
+ vnf = vnf_triangulate(vnf),
+ verts = vnf[0],
+ val=sum([
+ for(face_index=vnf[1])
+ let(
+ face = select(verts, face_index),
+ n = cross(face[2]-face[0],face[1]-face[0])
+ ) [
+ face[0] * n,
+ vmul(n,
+ sqr(face[0] + face[1]) +
+ sqr(face[0] + face[2]) +
+ sqr(face[1] + face[2])
+ )
+ ]
+ ])
+ ) val[1]/val[0]/8;
function _triangulate_planar_convex_polygons(polys) =
- polys==[]? [] :
- let(
- tris = [for (poly=polys) if (len(poly)==3) poly],
- bigs = [for (poly=polys) if (len(poly)>3) poly],
- newtris = [for (poly=bigs) select(poly,-2,0)],
- newbigs = [for (poly=bigs) select(poly,0,-2)],
- newtris2 = _triangulate_planar_convex_polygons(newbigs),
- outtris = concat(tris, newtris, newtris2)
- ) outtris;
+ polys==[]? [] :
+ let(
+ tris = [for (poly=polys) if (len(poly)==3) poly],
+ bigs = [for (poly=polys) if (len(poly)>3) poly],
+ newtris = [for (poly=bigs) select(poly,-2,0)],
+ newbigs = [for (poly=bigs) select(poly,0,-2)],
+ newtris2 = _triangulate_planar_convex_polygons(newbigs),
+ outtris = concat(tris, newtris, newtris2)
+ ) outtris;
// Function: vnf_bend()
@@ -482,49 +482,49 @@ function _triangulate_planar_convex_polygons(polys) =
// bent1 = vnf_bend(vnf1, axis="Z");
// vnf_polyhedron([bent1]);
function vnf_bend(vnf,r,d,axis="Z") =
- let(
- chk_axis = assert(in_list(axis,["X","Y","Z"])),
- vnf = vnf_triangulate(vnf),
- verts = vnf[0],
- bounds = pointlist_bounds(verts),
- bmin = bounds[0],
- bmax = bounds[1],
- dflt = axis=="Z"?
- max(abs(bmax.y), abs(bmin.y)) :
- max(abs(bmax.z), abs(bmin.z)),
- r = get_radius(r=r,d=d,dflt=dflt),
- width = axis=="X"? (bmax.y-bmin.y) : (bmax.x - bmin.x)
- )
- assert(width <= 2*PI*r, "Shape would wrap more than completely around the cylinder.")
- let(
- span_chk = axis=="Z"?
- assert(bmin.y > 0 || bmax.y < 0, "Entire shape MUST be completely in front of or behind y=0.") :
- assert(bmin.z > 0 || bmax.z < 0, "Entire shape MUST be completely above or below z=0."),
- min_ang = 180 * bmin.x / (PI * r),
- max_ang = 180 * bmax.x / (PI * r),
- ang_span = max_ang-min_ang,
- steps = ceil(segs(r) * ang_span/360),
- step = width / steps,
- bend_at = axis=="X"? [for(i = [1:1:steps-1]) i*step+bmin.y] :
- [for(i = [1:1:steps-1]) i*step+bmin.x],
- facepolys = [for (face=vnf[1]) select(verts,face)],
- splits = axis=="X"?
- split_polygons_at_each_y(facepolys, bend_at) :
- split_polygons_at_each_x(facepolys, bend_at),
- newtris = _triangulate_planar_convex_polygons(splits),
- bent_faces = [
- for (tri = newtris) [
- for (p = tri) let(
- a = axis=="X"? 180*p.y/(r*PI) * sign(bmax.z) :
- axis=="Y"? 180*p.x/(r*PI) * sign(bmax.z) :
- 180*p.x/(r*PI) * sign(bmax.y)
- )
- axis=="X"? [p.x, p.z*sin(a), p.z*cos(a)] :
- axis=="Y"? [p.z*sin(a), p.y, p.z*cos(a)] :
- [p.y*sin(a), p.y*cos(a), p.z]
- ]
- ]
- ) vnf_add_faces(faces=bent_faces);
+ let(
+ chk_axis = assert(in_list(axis,["X","Y","Z"])),
+ vnf = vnf_triangulate(vnf),
+ verts = vnf[0],
+ bounds = pointlist_bounds(verts),
+ bmin = bounds[0],
+ bmax = bounds[1],
+ dflt = axis=="Z"?
+ max(abs(bmax.y), abs(bmin.y)) :
+ max(abs(bmax.z), abs(bmin.z)),
+ r = get_radius(r=r,d=d,dflt=dflt),
+ width = axis=="X"? (bmax.y-bmin.y) : (bmax.x - bmin.x)
+ )
+ assert(width <= 2*PI*r, "Shape would wrap more than completely around the cylinder.")
+ let(
+ span_chk = axis=="Z"?
+ assert(bmin.y > 0 || bmax.y < 0, "Entire shape MUST be completely in front of or behind y=0.") :
+ assert(bmin.z > 0 || bmax.z < 0, "Entire shape MUST be completely above or below z=0."),
+ min_ang = 180 * bmin.x / (PI * r),
+ max_ang = 180 * bmax.x / (PI * r),
+ ang_span = max_ang-min_ang,
+ steps = ceil(segs(r) * ang_span/360),
+ step = width / steps,
+ bend_at = axis=="X"? [for(i = [1:1:steps-1]) i*step+bmin.y] :
+ [for(i = [1:1:steps-1]) i*step+bmin.x],
+ facepolys = [for (face=vnf[1]) select(verts,face)],
+ splits = axis=="X"?
+ split_polygons_at_each_y(facepolys, bend_at) :
+ split_polygons_at_each_x(facepolys, bend_at),
+ newtris = _triangulate_planar_convex_polygons(splits),
+ bent_faces = [
+ for (tri = newtris) [
+ for (p = tri) let(
+ a = axis=="X"? 180*p.y/(r*PI) * sign(bmax.z) :
+ axis=="Y"? 180*p.x/(r*PI) * sign(bmax.z) :
+ 180*p.x/(r*PI) * sign(bmax.y)
+ )
+ axis=="X"? [p.x, p.z*sin(a), p.z*cos(a)] :
+ axis=="Y"? [p.z*sin(a), p.y, p.z*cos(a)] :
+ [p.y*sin(a), p.y*cos(a), p.z]
+ ]
+ ]
+ ) vnf_add_faces(faces=bent_faces);
// Function&Module: vnf_validate()
@@ -614,198 +614,198 @@ function vnf_bend(vnf,r,d,axis="Z") =
// ], slices=0, caps=false);
// vnf_validate(vnf,size=2);
function vnf_validate(vnf, show_warns=true, check_isects=false) =
- assert(is_path(vnf[0]))
- let(
- vnf = vnf_compact(vnf),
- varr = vnf[0],
- faces = vnf[1],
- edges = sort([
- for (face=faces, edge=pair_wrap(face))
- edge[0] 3) [
- "WARNING",
- "BIG_FACE",
- "Face has more than 3 vertices, and may confuse CGAL",
- [for (i=face) varr[i]],
- "yellow"
- ]
- ],
- null_faces = !show_warns? [] : [
- for (face = faces) let(
- face = deduplicate(face,closed=true)
- )
- if (len(face)>=3) let(
- faceverts = [for (k=face) varr[k]],
- area = polygon_area(faceverts)
- ) if (is_num(area) && abs(area) < EPSILON) [
- "WARNING",
- "NULL_FACE",
- str("Face has zero area: ",fmt_float(abs(area),15)),
- faceverts,
- "brown"
- ]
- ],
- nonplanars = unique([
- for (face = faces) let(
- faceverts = [for (k=face) varr[k]]
- ) if (!points_are_coplanar(faceverts)) [
- "ERROR",
- "NONPLANAR",
- "Face vertices are not coplanar",
- faceverts,
- "cyan"
- ]
- ]),
- overpop_edges = unique([
- for (i=idx(uniq_edges))
- if (edgecnts[1][i]>2) [
- "ERROR",
- "OVRPOP_EDGE",
- "Too many faces attached at Edge",
- [for (i=uniq_edges[i]) varr[i]],
- "#f70"
- ]
- ]),
- reversals = unique([
- for(i = idx(faces), j = idx(faces)) if(i != j)
- if(len(deduplicate(faces[i],closed=true))>=3)
- if(len(deduplicate(faces[j],closed=true))>=3)
- for(edge1 = pair_wrap(faces[i]))
- for(edge2 = pair_wrap(faces[j]))
- if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering.
- if(_edge_not_reported(edge1, varr, overpop_edges))
- [
- "ERROR",
- "REVERSAL",
- "Faces Reverse Across Edge",
- [for (i=edge1) varr[i]],
- "violet"
- ]
- ]),
- t_juncts = unique([
- for (v=idx(varr), edge=uniq_edges)
- if (v!=edge[0] && v!=edge[1]) let(
- a = varr[edge[0]],
- b = varr[v],
- c = varr[edge[1]],
- pt = segment_closest_point([a,c],b)
- ) if (pt == b) [
- "ERROR",
- "T_JUNCTION",
- "Vertex is mid-edge on another Face",
- [b],
- "red"
- ]
- ]),
- isect_faces = !check_isects? [] : unique([
- for (i = [0:1:len(faces)-2])
- for (j = [i+1:1:len(faces)-1]) let(
- f1 = faces[i],
- f2 = faces[j],
- shared_edges = [
- for (edge1 = pair_wrap(f1), edge2 = pair_wrap(f2)) let(
- e1 = edge1[0]1) let(
- poly2 = select(varr,f2),
- isects2 = polygon_line_intersection(poly2,isect,bounded=true)
- )
- if (!is_undef(isects2))
- for (seg=isects2)
- if (seg[0] != seg[1]) [
- "ERROR",
- "FACE_ISECT",
- "Faces intersect",
- seg,
- "blue"
- ]
- ]),
- hole_edges = unique([
- for (i=idx(uniq_edges))
- if (edgecnts[1][i]<2)
- if (_pts_not_reported(uniq_edges[i], varr, t_juncts))
- if (_pts_not_reported(uniq_edges[i], varr, isect_faces))
- [
- "ERROR",
- "HOLE_EDGE",
- "Edge bounds Hole",
- [for (i=uniq_edges[i]) varr[i]],
- "magenta"
- ]
- ])
- ) concat(
- big_faces,
- null_faces,
- nonplanars,
- overpop_edges,
- reversals,
- t_juncts,
- isect_faces,
- hole_edges
- );
+ assert(is_path(vnf[0]))
+ let(
+ vnf = vnf_compact(vnf),
+ varr = vnf[0],
+ faces = vnf[1],
+ edges = sort([
+ for (face=faces, edge=pair_wrap(face))
+ edge[0] 3) [
+ "WARNING",
+ "BIG_FACE",
+ "Face has more than 3 vertices, and may confuse CGAL",
+ [for (i=face) varr[i]],
+ "yellow"
+ ]
+ ],
+ null_faces = !show_warns? [] : [
+ for (face = faces) let(
+ face = deduplicate(face,closed=true)
+ )
+ if (len(face)>=3) let(
+ faceverts = [for (k=face) varr[k]],
+ area = polygon_area(faceverts)
+ ) if (is_num(area) && abs(area) < EPSILON) [
+ "WARNING",
+ "NULL_FACE",
+ str("Face has zero area: ",fmt_float(abs(area),15)),
+ faceverts,
+ "brown"
+ ]
+ ],
+ nonplanars = unique([
+ for (face = faces) let(
+ faceverts = [for (k=face) varr[k]]
+ ) if (!points_are_coplanar(faceverts)) [
+ "ERROR",
+ "NONPLANAR",
+ "Face vertices are not coplanar",
+ faceverts,
+ "cyan"
+ ]
+ ]),
+ overpop_edges = unique([
+ for (i=idx(uniq_edges))
+ if (edgecnts[1][i]>2) [
+ "ERROR",
+ "OVRPOP_EDGE",
+ "Too many faces attached at Edge",
+ [for (i=uniq_edges[i]) varr[i]],
+ "#f70"
+ ]
+ ]),
+ reversals = unique([
+ for(i = idx(faces), j = idx(faces)) if(i != j)
+ if(len(deduplicate(faces[i],closed=true))>=3)
+ if(len(deduplicate(faces[j],closed=true))>=3)
+ for(edge1 = pair_wrap(faces[i]))
+ for(edge2 = pair_wrap(faces[j]))
+ if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering.
+ if(_edge_not_reported(edge1, varr, overpop_edges))
+ [
+ "ERROR",
+ "REVERSAL",
+ "Faces Reverse Across Edge",
+ [for (i=edge1) varr[i]],
+ "violet"
+ ]
+ ]),
+ t_juncts = unique([
+ for (v=idx(varr), edge=uniq_edges)
+ if (v!=edge[0] && v!=edge[1]) let(
+ a = varr[edge[0]],
+ b = varr[v],
+ c = varr[edge[1]],
+ pt = segment_closest_point([a,c],b)
+ ) if (pt == b) [
+ "ERROR",
+ "T_JUNCTION",
+ "Vertex is mid-edge on another Face",
+ [b],
+ "red"
+ ]
+ ]),
+ isect_faces = !check_isects? [] : unique([
+ for (i = [0:1:len(faces)-2])
+ for (j = [i+1:1:len(faces)-1]) let(
+ f1 = faces[i],
+ f2 = faces[j],
+ shared_edges = [
+ for (edge1 = pair_wrap(f1), edge2 = pair_wrap(f2)) let(
+ e1 = edge1[0]1) let(
+ poly2 = select(varr,f2),
+ isects2 = polygon_line_intersection(poly2,isect,bounded=true)
+ )
+ if (!is_undef(isects2))
+ for (seg=isects2)
+ if (seg[0] != seg[1]) [
+ "ERROR",
+ "FACE_ISECT",
+ "Faces intersect",
+ seg,
+ "blue"
+ ]
+ ]),
+ hole_edges = unique([
+ for (i=idx(uniq_edges))
+ if (edgecnts[1][i]<2)
+ if (_pts_not_reported(uniq_edges[i], varr, t_juncts))
+ if (_pts_not_reported(uniq_edges[i], varr, isect_faces))
+ [
+ "ERROR",
+ "HOLE_EDGE",
+ "Edge bounds Hole",
+ [for (i=uniq_edges[i]) varr[i]],
+ "magenta"
+ ]
+ ])
+ ) concat(
+ big_faces,
+ null_faces,
+ nonplanars,
+ overpop_edges,
+ reversals,
+ t_juncts,
+ isect_faces,
+ hole_edges
+ );
function _pts_not_reported(pts, varr, reports) =
- [
- for (i = pts, report = reports, pt = report[3])
- if (varr[i] == pt) 1
- ] == [];
+ [
+ for (i = pts, report = reports, pt = report[3])
+ if (varr[i] == pt) 1
+ ] == [];
function _edge_not_reported(edge, varr, reports) =
- let(
- edge = sort([for (i=edge) varr[i]])
- ) [
- for (report = reports) let(
- pts = sort(report[3])
- ) if (len(pts)==2 && edge == pts) 1
- ] == [];
+ let(
+ edge = sort([for (i=edge) varr[i]])
+ ) [
+ for (report = reports) let(
+ pts = sort(report[3])
+ ) if (len(pts)==2 && edge == pts) 1
+ ] == [];
module vnf_validate(vnf, size=1, show_warns=true, check_isects=false) {
- faults = vnf_validate(
- vnf, show_warns=show_warns,
- check_isects=check_isects
- );
- for (fault = faults) {
- typ = fault[0];
- err = fault[1];
- msg = fault[2];
- pts = fault[3];
- clr = fault[4];
- echo(str(typ, " ", err, ": ", msg, " at ", pts));
- color(clr) {
- if (len(pts)==2) {
- stroke(pts, width=size);
- } else if (len(pts)>2) {
- stroke(pts, width=size, closed=true);
- polyhedron(pts,[[for (i=idx(pts)) i]]);
- } else {
- move_copies(pts) sphere(d=size*3, $fn=18);
- }
- }
- }
- color([0.5,0.5,0.5,0.5]) vnf_polyhedron(vnf);
+ faults = vnf_validate(
+ vnf, show_warns=show_warns,
+ check_isects=check_isects
+ );
+ for (fault = faults) {
+ typ = fault[0];
+ err = fault[1];
+ msg = fault[2];
+ pts = fault[3];
+ clr = fault[4];
+ echo(str(typ, " ", err, ": ", msg, " at ", pts));
+ color(clr) {
+ if (len(pts)==2) {
+ stroke(pts, width=size);
+ } else if (len(pts)>2) {
+ stroke(pts, width=size, closed=true);
+ polyhedron(pts,[[for (i=idx(pts)) i]]);
+ } else {
+ move_copies(pts) sphere(d=size*3, $fn=18);
+ }
+ }
+ }
+ color([0.5,0.5,0.5,0.5]) vnf_polyhedron(vnf);
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/walls.scad b/walls.scad
index 10838a5..e87b6f6 100644
--- a/walls.scad
+++ b/walls.scad
@@ -36,25 +36,25 @@
// narrowing_strut(w=10, l=100, wall=5, ang=30);
module narrowing_strut(w=10, l=100, wall=5, ang=30, anchor=BOTTOM, spin=0, orient=UP)
{
- h = wall + w/2/tan(ang);
- size = [w, l, h];
- attachable(anchor,spin,orient, size=size) {
- xrot(90)
- fwd(h/2) {
- linear_extrude(height=l, center=true, slices=2) {
- back(wall/2) square([w, wall], center=true);
- back(wall-0.001) {
- yscale(1/tan(ang)) {
- difference() {
- zrot(45) square(w/sqrt(2), center=true);
- fwd(w/2) square(w, center=true);
- }
- }
- }
- }
- }
- children();
- }
+ h = wall + w/2/tan(ang);
+ size = [w, l, h];
+ attachable(anchor,spin,orient, size=size) {
+ xrot(90)
+ fwd(h/2) {
+ linear_extrude(height=l, center=true, slices=2) {
+ back(wall/2) square([w, wall], center=true);
+ back(wall-0.001) {
+ yscale(1/tan(ang)) {
+ difference() {
+ zrot(45) square(w/sqrt(2), center=true);
+ fwd(w/2) square(w, center=true);
+ }
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -87,152 +87,152 @@ module narrowing_strut(w=10, l=100, wall=5, ang=30, anchor=BOTTOM, spin=0, orien
// thinning_wall(h=50, l=[80,50], thick=4, strut=4, wall=2, braces=true);
module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, anchor=CENTER, spin=0, orient=UP)
{
- l1 = (l[0] == undef)? l : l[0];
- l2 = (l[1] == undef)? l : l[1];
- strut = is_num(strut)? strut : min(h,l1,l2,thick)/2;
- wall = is_num(wall)? wall : thick/2;
+ l1 = (l[0] == undef)? l : l[0];
+ l2 = (l[1] == undef)? l : l[1];
+ strut = is_num(strut)? strut : min(h,l1,l2,thick)/2;
+ wall = is_num(wall)? wall : thick/2;
- bevel_h = strut + (thick-wall)/2/tan(ang);
- cp1 = find_circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=strut)[0];
- cp2 = find_circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=bevel_h)[0];
- cp3 = find_circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=bevel_h)[0];
- cp4 = find_circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=strut)[0];
+ bevel_h = strut + (thick-wall)/2/tan(ang);
+ cp1 = find_circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=strut)[0];
+ cp2 = find_circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=bevel_h)[0];
+ cp3 = find_circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=bevel_h)[0];
+ cp4 = find_circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=strut)[0];
- z1 = h/2;
- z2 = cp1.z;
- z3 = cp2.z;
+ z1 = h/2;
+ z2 = cp1.z;
+ z3 = cp2.z;
- x1 = l2/2;
- x2 = cp1.x;
- x3 = cp2.x;
- x4 = l1/2;
- x5 = cp4.x;
- x6 = cp3.x;
+ x1 = l2/2;
+ x2 = cp1.x;
+ x3 = cp2.x;
+ x4 = l1/2;
+ x5 = cp4.x;
+ x6 = cp3.x;
- y1 = thick/2;
- y2 = wall/2;
+ y1 = thick/2;
+ y2 = wall/2;
- corner1 = [ x2, 0, z2];
- corner2 = [-x5, 0, -z2];
- brace_len = norm(corner1-corner2);
+ corner1 = [ x2, 0, z2];
+ corner2 = [-x5, 0, -z2];
+ brace_len = norm(corner1-corner2);
- size = [l1, thick, h];
- attachable(anchor,spin,orient, size=size, size2=[l2,thick]) {
- union() {
- polyhedron(
- points=[
- [-x4, -y1, -z1],
- [ x4, -y1, -z1],
- [ x1, -y1, z1],
- [-x1, -y1, z1],
+ size = [l1, thick, h];
+ attachable(anchor,spin,orient, size=size, size2=[l2,thick]) {
+ union() {
+ polyhedron(
+ points=[
+ [-x4, -y1, -z1],
+ [ x4, -y1, -z1],
+ [ x1, -y1, z1],
+ [-x1, -y1, z1],
- [-x5, -y1, -z2],
- [ x5, -y1, -z2],
- [ x2, -y1, z2],
- [-x2, -y1, z2],
+ [-x5, -y1, -z2],
+ [ x5, -y1, -z2],
+ [ x2, -y1, z2],
+ [-x2, -y1, z2],
- [-x6, -y2, -z3],
- [ x6, -y2, -z3],
- [ x3, -y2, z3],
- [-x3, -y2, z3],
+ [-x6, -y2, -z3],
+ [ x6, -y2, -z3],
+ [ x3, -y2, z3],
+ [-x3, -y2, z3],
- [-x4, y1, -z1],
- [ x4, y1, -z1],
- [ x1, y1, z1],
- [-x1, y1, z1],
+ [-x4, y1, -z1],
+ [ x4, y1, -z1],
+ [ x1, y1, z1],
+ [-x1, y1, z1],
- [-x5, y1, -z2],
- [ x5, y1, -z2],
- [ x2, y1, z2],
- [-x2, y1, z2],
+ [-x5, y1, -z2],
+ [ x5, y1, -z2],
+ [ x2, y1, z2],
+ [-x2, y1, z2],
- [-x6, y2, -z3],
- [ x6, y2, -z3],
- [ x3, y2, z3],
- [-x3, y2, z3],
- ],
- faces=[
- [ 4, 5, 1],
- [ 5, 6, 2],
- [ 6, 7, 3],
- [ 7, 4, 0],
+ [-x6, y2, -z3],
+ [ x6, y2, -z3],
+ [ x3, y2, z3],
+ [-x3, y2, z3],
+ ],
+ faces=[
+ [ 4, 5, 1],
+ [ 5, 6, 2],
+ [ 6, 7, 3],
+ [ 7, 4, 0],
- [ 4, 1, 0],
- [ 5, 2, 1],
- [ 6, 3, 2],
- [ 7, 0, 3],
+ [ 4, 1, 0],
+ [ 5, 2, 1],
+ [ 6, 3, 2],
+ [ 7, 0, 3],
- [ 8, 9, 5],
- [ 9, 10, 6],
- [10, 11, 7],
- [11, 8, 4],
+ [ 8, 9, 5],
+ [ 9, 10, 6],
+ [10, 11, 7],
+ [11, 8, 4],
- [ 8, 5, 4],
- [ 9, 6, 5],
- [10, 7, 6],
- [11, 4, 7],
+ [ 8, 5, 4],
+ [ 9, 6, 5],
+ [10, 7, 6],
+ [11, 4, 7],
- [11, 10, 9],
- [20, 21, 22],
+ [11, 10, 9],
+ [20, 21, 22],
- [11, 9, 8],
- [20, 22, 23],
+ [11, 9, 8],
+ [20, 22, 23],
- [16, 17, 21],
- [17, 18, 22],
- [18, 19, 23],
- [19, 16, 20],
+ [16, 17, 21],
+ [17, 18, 22],
+ [18, 19, 23],
+ [19, 16, 20],
- [16, 21, 20],
- [17, 22, 21],
- [18, 23, 22],
- [19, 20, 23],
+ [16, 21, 20],
+ [17, 22, 21],
+ [18, 23, 22],
+ [19, 20, 23],
- [12, 13, 17],
- [13, 14, 18],
- [14, 15, 19],
- [15, 12, 16],
+ [12, 13, 17],
+ [13, 14, 18],
+ [14, 15, 19],
+ [15, 12, 16],
- [12, 17, 16],
- [13, 18, 17],
- [14, 19, 18],
- [15, 16, 19],
+ [12, 17, 16],
+ [13, 18, 17],
+ [14, 19, 18],
+ [15, 16, 19],
- [ 0, 1, 13],
- [ 1, 2, 14],
- [ 2, 3, 15],
- [ 3, 0, 12],
+ [ 0, 1, 13],
+ [ 1, 2, 14],
+ [ 2, 3, 15],
+ [ 3, 0, 12],
- [ 0, 13, 12],
- [ 1, 14, 13],
- [ 2, 15, 14],
- [ 3, 12, 15],
- ],
- convexity=6
- );
- if(braces) {
- bracepath = [
- [-strut*0.33,thick/2],
- [ strut*0.33,thick/2],
- [ strut*0.33+(thick-wall)/2/tan(ang), wall/2],
- [ strut*0.33+(thick-wall)/2/tan(ang),-wall/2],
- [ strut*0.33,-thick/2],
- [-strut*0.33,-thick/2],
- [-strut*0.33-(thick-wall)/2/tan(ang),-wall/2],
- [-strut*0.33-(thick-wall)/2/tan(ang), wall/2]
- ];
- xflip_copy() {
- intersection() {
- extrude_from_to(corner1,corner2) {
- polygon(bracepath);
- }
- prismoid([l1,thick],[l2,thick],h=h,anchor=CENTER);
- }
- }
- }
- }
- children();
- }
+ [ 0, 13, 12],
+ [ 1, 14, 13],
+ [ 2, 15, 14],
+ [ 3, 12, 15],
+ ],
+ convexity=6
+ );
+ if(braces) {
+ bracepath = [
+ [-strut*0.33,thick/2],
+ [ strut*0.33,thick/2],
+ [ strut*0.33+(thick-wall)/2/tan(ang), wall/2],
+ [ strut*0.33+(thick-wall)/2/tan(ang),-wall/2],
+ [ strut*0.33,-thick/2],
+ [-strut*0.33,-thick/2],
+ [-strut*0.33-(thick-wall)/2/tan(ang),-wall/2],
+ [-strut*0.33-(thick-wall)/2/tan(ang), wall/2]
+ ];
+ xflip_copy() {
+ intersection() {
+ extrude_from_to(corner1,corner2) {
+ polygon(bracepath);
+ }
+ prismoid([l1,thick],[l2,thick],h=h,anchor=CENTER);
+ }
+ }
+ }
+ }
+ children();
+ }
}
@@ -266,35 +266,35 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, an
// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, diagonly=true, center=false);
module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly=false, center, anchor, spin=0, orient=UP)
{
- dang = atan(h/l);
- dlen = h/sin(dang);
- size = [thick, l, h];
- anchor = get_anchor(anchor, center, BOT+FRONT, CENTER);
- attachable(anchor,spin,orient, size=size) {
- difference() {
- union() {
- if (!diagonly) {
- translate([0, 0, -h/2])
- narrowing_strut(w=thick, l=l, wall=strut, ang=ang);
- translate([0, -l/2, 0])
- xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang);
- }
- intersection() {
- cube(size=[thick, l, h], center=true);
- xrot(-dang) yrot(180) {
- narrowing_strut(w=thick, l=dlen*1.2, wall=strut, ang=ang);
- }
- }
- cube(size=[wall, l-0.1, h-0.1], center=true);
- }
- xrot(-dang) {
- translate([0, 0, h/2]) {
- cube(size=[thick+0.1, l*2, h], center=true);
- }
- }
- }
- children();
- }
+ dang = atan(h/l);
+ dlen = h/sin(dang);
+ size = [thick, l, h];
+ anchor = get_anchor(anchor, center, BOT+FRONT, CENTER);
+ attachable(anchor,spin,orient, size=size) {
+ difference() {
+ union() {
+ if (!diagonly) {
+ translate([0, 0, -h/2])
+ narrowing_strut(w=thick, l=l, wall=strut, ang=ang);
+ translate([0, -l/2, 0])
+ xrot(-90) narrowing_strut(w=thick, l=h-0.1, wall=strut, ang=ang);
+ }
+ intersection() {
+ cube(size=[thick, l, h], center=true);
+ xrot(-dang) yrot(180) {
+ narrowing_strut(w=thick, l=dlen*1.2, wall=strut, ang=ang);
+ }
+ }
+ cube(size=[wall, l-0.1, h-0.1], center=true);
+ }
+ xrot(-dang) {
+ translate([0, 0, h/2]) {
+ cube(size=[thick+0.1, l*2, h], center=true);
+ }
+ }
+ }
+ children();
+ }
}
@@ -328,41 +328,41 @@ module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly
// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45, max_bridge=30);
module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, anchor=CENTER, spin=0, orient=UP)
{
- zoff = h/2 - strut/2;
- yoff = l/2 - strut/2;
+ zoff = h/2 - strut/2;
+ yoff = l/2 - strut/2;
- maxhyp = 1.5 * (max_bridge+strut)/2 / sin(maxang);
- maxz = 2 * maxhyp * cos(maxang);
+ maxhyp = 1.5 * (max_bridge+strut)/2 / sin(maxang);
+ maxz = 2 * maxhyp * cos(maxang);
- zreps = ceil(2*zoff/maxz);
- zstep = 2*zoff / zreps;
+ zreps = ceil(2*zoff/maxz);
+ zstep = 2*zoff / zreps;
- hyp = zstep/2 / cos(maxang);
- maxy = min(2 * hyp * sin(maxang), max_bridge+strut);
+ hyp = zstep/2 / cos(maxang);
+ maxy = min(2 * hyp * sin(maxang), max_bridge+strut);
- yreps = ceil(2*yoff/maxy);
- ystep = 2*yoff / yreps;
+ yreps = ceil(2*yoff/maxy);
+ ystep = 2*yoff / yreps;
- ang = atan(ystep/zstep);
- len = zstep / cos(ang);
+ ang = atan(ystep/zstep);
+ len = zstep / cos(ang);
- size = [thick, l, h];
- attachable(anchor,spin,orient, size=size) {
- yrot(90)
- linear_extrude(height=thick, convexity=4*yreps, center=true) {
- difference() {
- square([h, l], center=true);
- square([h-2*strut, l-2*strut], center=true);
- }
- ycopies(ystep, n=yreps) {
- xcopies(zstep, n=zreps) {
- skew(syx=tan(-ang)) square([(h-strut)/zreps, strut], center=true);
- skew(syx=tan( ang)) square([(h-strut)/zreps, strut], center=true);
- }
- }
- }
- children();
- }
+ size = [thick, l, h];
+ attachable(anchor,spin,orient, size=size) {
+ yrot(90)
+ linear_extrude(height=thick, convexity=4*yreps, center=true) {
+ difference() {
+ square([h, l], center=true);
+ square([h-2*strut, l-2*strut], center=true);
+ }
+ ycopies(ystep, n=yreps) {
+ xcopies(zstep, n=zreps) {
+ skew(syx=tan(-ang)) square([(h-strut)/zreps, strut], center=true);
+ skew(syx=tan( ang)) square([(h-strut)/zreps, strut], center=true);
+ }
+ }
+ }
+ children();
+ }
}
@@ -398,70 +398,70 @@ module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, anc
module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge=30, anchor=CENTER, spin=0, orient=UP)
{
- xoff = w - thick;
- yoff = l - thick;
- zoff = h - thick;
+ xoff = w - thick;
+ yoff = l - thick;
+ zoff = h - thick;
- xreps = ceil(xoff/yoff);
- yreps = ceil(yoff/xoff);
- zreps = ceil(zoff/min(xoff, yoff));
+ xreps = ceil(xoff/yoff);
+ yreps = ceil(yoff/xoff);
+ zreps = ceil(zoff/min(xoff, yoff));
- xstep = xoff / xreps;
- ystep = yoff / yreps;
- zstep = zoff / zreps;
+ xstep = xoff / xreps;
+ ystep = yoff / yreps;
+ zstep = zoff / zreps;
- cross_ang = atan2(xstep, ystep);
- cross_len = hypot(xstep, ystep);
+ cross_ang = atan2(xstep, ystep);
+ cross_len = hypot(xstep, ystep);
- supp_ang = min(maxang, min(atan2(max_bridge, zstep), atan2(cross_len/2, zstep)));
- supp_reps = floor(cross_len/2/(zstep*sin(supp_ang)));
- supp_step = cross_len/2/supp_reps;
+ supp_ang = min(maxang, min(atan2(max_bridge, zstep), atan2(cross_len/2, zstep)));
+ supp_reps = floor(cross_len/2/(zstep*sin(supp_ang)));
+ supp_step = cross_len/2/supp_reps;
- size = [w, l, h];
- attachable(anchor,spin,orient, size=size) {
- intersection() {
- union() {
- ybridge = (l - (yreps+1) * strut) / yreps;
- xcopies(xoff) sparse_strut(h=h, l=l, thick=thick, maxang=maxang, strut=strut, max_bridge=ybridge/ceil(ybridge/max_bridge));
- ycopies(yoff) zrot(90) sparse_strut(h=h, l=w, thick=thick, maxang=maxang, strut=strut, max_bridge=max_bridge);
- for(zs = [0:1:zreps-1]) {
- for(xs = [0:1:xreps-1]) {
- for(ys = [0:1:yreps-1]) {
- translate([(xs+0.5)*xstep-xoff/2, (ys+0.5)*ystep-yoff/2, (zs+0.5)*zstep-zoff/2]) {
- zflip_copy(offset=-(zstep-strut)/2) {
- xflip_copy() {
- zrot(cross_ang) {
- down(strut/2) {
- cube([strut, cross_len, strut], center=true);
- }
- if (zreps>1) {
- back(cross_len/2) {
- zrot(-cross_ang) {
- down(strut) cube([strut, strut, zstep+strut], anchor=BOTTOM);
- }
- }
- }
- for (soff = [0:1:supp_reps-1] ) {
- yflip_copy() {
- back(soff*supp_step) {
- skew(syz=tan(supp_ang)) {
- cube([strut, strut, zstep], anchor=BOTTOM);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- cube([w,l,h], center=true);
- }
- children();
- }
+ size = [w, l, h];
+ attachable(anchor,spin,orient, size=size) {
+ intersection() {
+ union() {
+ ybridge = (l - (yreps+1) * strut) / yreps;
+ xcopies(xoff) sparse_strut(h=h, l=l, thick=thick, maxang=maxang, strut=strut, max_bridge=ybridge/ceil(ybridge/max_bridge));
+ ycopies(yoff) zrot(90) sparse_strut(h=h, l=w, thick=thick, maxang=maxang, strut=strut, max_bridge=max_bridge);
+ for(zs = [0:1:zreps-1]) {
+ for(xs = [0:1:xreps-1]) {
+ for(ys = [0:1:yreps-1]) {
+ translate([(xs+0.5)*xstep-xoff/2, (ys+0.5)*ystep-yoff/2, (zs+0.5)*zstep-zoff/2]) {
+ zflip_copy(offset=-(zstep-strut)/2) {
+ xflip_copy() {
+ zrot(cross_ang) {
+ down(strut/2) {
+ cube([strut, cross_len, strut], center=true);
+ }
+ if (zreps>1) {
+ back(cross_len/2) {
+ zrot(-cross_ang) {
+ down(strut) cube([strut, strut, zstep+strut], anchor=BOTTOM);
+ }
+ }
+ }
+ for (soff = [0:1:supp_reps-1] ) {
+ yflip_copy() {
+ back(soff*supp_step) {
+ skew(syz=tan(supp_ang)) {
+ cube([strut, strut, zstep], anchor=BOTTOM);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ cube([w,l,h], center=true);
+ }
+ children();
+ }
}
@@ -492,31 +492,31 @@ module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge
// corrugated_wall(h=50, l=100, strut=8, wall=3);
module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, anchor=CENTER, spin=0, orient=UP)
{
- amplitude = (thick - wall) / 2;
- period = min(15, thick * 2);
- steps = quantup(segs(thick/2),4);
- step = period/steps;
- il = l - 2*strut + 2*step;
- size = [thick, l, h];
- attachable(anchor,spin,orient, size=size) {
- union() {
- linear_extrude(height=h-2*strut+0.1, slices=2, convexity=ceil(2*il/period), center=true) {
- polygon(
- points=concat(
- [for (y=[-il/2:step:il/2]) [amplitude*sin(y/period*360)-wall/2, y] ],
- [for (y=[il/2:-step:-il/2]) [amplitude*sin(y/period*360)+wall/2, y] ]
- )
- );
- }
- difference() {
- cube([thick, l, h], center=true);
- cube([thick+0.5, l-2*strut, h-2*strut], center=true);
- }
- }
- children();
- }
+ amplitude = (thick - wall) / 2;
+ period = min(15, thick * 2);
+ steps = quantup(segs(thick/2),4);
+ step = period/steps;
+ il = l - 2*strut + 2*step;
+ size = [thick, l, h];
+ attachable(anchor,spin,orient, size=size) {
+ union() {
+ linear_extrude(height=h-2*strut+0.1, slices=2, convexity=ceil(2*il/period), center=true) {
+ polygon(
+ points=concat(
+ [for (y=[-il/2:step:il/2]) [amplitude*sin(y/period*360)-wall/2, y] ],
+ [for (y=[il/2:-step:-il/2]) [amplitude*sin(y/period*360)+wall/2, y] ]
+ )
+ );
+ }
+ difference() {
+ cube([thick, l, h], center=true);
+ cube([thick+0.5, l-2*strut, h-2*strut], center=true);
+ }
+ }
+ children();
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/wiring.scad b/wiring.scad
index 8f7d1ee..bc970d2 100644
--- a/wiring.scad
+++ b/wiring.scad
@@ -28,15 +28,15 @@ include
// Example:
// hex_offset_ring(d=1, lev=3); // Returns a hex ring of 18 points.
function hex_offset_ring(d, lev=0) =
- (lev == 0)? [[0,0]] : [
- for (
- sideang = [0:60:359.999],
- sidenum = [1:1:lev]
- ) [
- lev*d*cos(sideang)+sidenum*d*cos(sideang+120),
- lev*d*sin(sideang)+sidenum*d*sin(sideang+120)
- ]
- ];
+ (lev == 0)? [[0,0]] : [
+ for (
+ sideang = [0:60:359.999],
+ sidenum = [1:1:lev]
+ ) [
+ lev*d*cos(sideang)+sidenum*d*cos(sideang+120),
+ lev*d*sin(sideang)+sidenum*d*sin(sideang+120)
+ ]
+ ];
// Function: hex_offsets()
@@ -51,13 +51,13 @@ function hex_offset_ring(d, lev=0) =
// n = Number of items to bundle.
// d = How far to space each point away from others.
function hex_offsets(n, d, lev=0, arr=[]) =
- (len(arr) >= n)? arr :
- hex_offsets(
- n=n,
- d=d,
- lev=lev+1,
- arr=concat(arr, hex_offset_ring(d, lev=lev))
- );
+ (len(arr) >= n)? arr :
+ hex_offsets(
+ n=n,
+ d=d,
+ lev=lev+1,
+ arr=concat(arr, hex_offset_ring(d, lev=lev))
+ );
@@ -81,26 +81,26 @@ function hex_offsets(n, d, lev=0, arr=[]) =
// Example:
// wiring([[50,0,-50], [50,50,-50], [0,50,-50], [0,0,-50], [0,0,0]], rounding=10, wires=13);
module wiring(path, wires, wirediam=2, rounding=10, wirenum=0, bezsteps=12) {
- colors = [
- [0.2, 0.2, 0.2], [1.0, 0.2, 0.2], [0.0, 0.8, 0.0], [1.0, 1.0, 0.2],
- [0.3, 0.3, 1.0], [1.0, 1.0, 1.0], [0.7, 0.5, 0.0], [0.5, 0.5, 0.5],
- [0.2, 0.9, 0.9], [0.8, 0.0, 0.8], [0.0, 0.6, 0.6], [1.0, 0.7, 0.7],
- [1.0, 0.5, 1.0], [0.5, 0.6, 0.0], [1.0, 0.7, 0.0], [0.7, 1.0, 0.5],
- [0.6, 0.6, 1.0],
- ];
- offsets = hex_offsets(wires, wirediam);
- bezpath = fillet_path(path, rounding);
- poly = simplify_path(path3d(bezier_polyline(bezpath, bezsteps)));
- n = max(segs(wirediam), 8);
- r = wirediam/2;
- for (i = [0:1:wires-1]) {
- extpath = [for (j = [0:1:n-1]) let(a=j*360/n) [r*cos(a)+offsets[i][0], r*sin(a)+offsets[i][1]]];
- color(colors[(i+wirenum)%len(colors)]) {
- path_sweep(extpath, poly);
- }
- }
+ colors = [
+ [0.2, 0.2, 0.2], [1.0, 0.2, 0.2], [0.0, 0.8, 0.0], [1.0, 1.0, 0.2],
+ [0.3, 0.3, 1.0], [1.0, 1.0, 1.0], [0.7, 0.5, 0.0], [0.5, 0.5, 0.5],
+ [0.2, 0.9, 0.9], [0.8, 0.0, 0.8], [0.0, 0.6, 0.6], [1.0, 0.7, 0.7],
+ [1.0, 0.5, 1.0], [0.5, 0.6, 0.0], [1.0, 0.7, 0.0], [0.7, 1.0, 0.5],
+ [0.6, 0.6, 1.0],
+ ];
+ offsets = hex_offsets(wires, wirediam);
+ bezpath = fillet_path(path, rounding);
+ poly = simplify_path(path3d(bezier_polyline(bezpath, bezsteps)));
+ n = max(segs(wirediam), 8);
+ r = wirediam/2;
+ for (i = [0:1:wires-1]) {
+ extpath = [for (j = [0:1:n-1]) let(a=j*360/n) [r*cos(a)+offsets[i][0], r*sin(a)+offsets[i][1]]];
+ color(colors[(i+wirenum)%len(colors)]) {
+ path_sweep(extpath, poly);
+ }
+ }
}
-// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
+// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap