Standardize indention on spaces, not tabs.

This commit is contained in:
Revar Desmera 2020-05-29 19:04:34 -07:00
parent 5fe35de963
commit 53c1e25395
89 changed files with 13618 additions and 13618 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,49 +26,49 @@ module offsetcube(size=[1,1,1],v=[0,0,0]) cuboid(size,anchor=-v);
module rrect(size=[1,1,1], r=0.25, center=false) cuboid(size,rounding=r,edges="Z",anchor=center?CENTER:BOT);
module rcube(size=[1,1,1], r=0.25, center=false) cuboid(size,rounding=r,anchor=center?CENTER:BOT);
module chamfcube(size=[1,1,1],chamfer=0.25,chamfaxes=[1,1,1],chamfcorners=false) {
cuboid(
size=size, chamfer=chamfer,
trimcorners=chamfcorners,
edges=concat(
chamfaxes[0]? ["X"] : [],
chamfaxes[1]? ["Y"] : [],
chamfaxes[2]? ["Z"] : []
)
);
cuboid(
size=size, chamfer=chamfer,
trimcorners=chamfcorners,
edges=concat(
chamfaxes[0]? ["X"] : [],
chamfaxes[1]? ["Y"] : [],
chamfaxes[2]? ["Z"] : []
)
);
}
module trapezoid(size1=[1,1], size2=[1,1], h=1, center=false)
prismoid(size1=size1, size2=size2, h=h, anchor=center?CENTER:BOT);
prismoid(size1=size1, size2=size2, h=h, anchor=center?CENTER:BOT);
module pyramid(n=4, h=1, l=1, r, d, circum=false) {
radius = get_radius(r=r, d=d, dflt=l/2/sin(180/n));
cyl(r1=radius, r2=0, l=h, circum=circum, $fn=n, realign=true, anchor=BOT);
radius = get_radius(r=r, d=d, dflt=l/2/sin(180/n));
cyl(r1=radius, r2=0, l=h, circum=circum, $fn=n, realign=true, anchor=BOT);
}
module prism(n=3, h=1, l=1, r=undef, d=undef, circum=false, center=false) {
radius = get_radius(r=r, d=d, dflt=l/2/sin(180/n));
cyl(r=radius, l=h, circum=circum, $fn=n, realign=true, anchor=center?CENTER:BOT);
radius = get_radius(r=r, d=d, dflt=l/2/sin(180/n));
cyl(r=radius, l=h, circum=circum, $fn=n, realign=true, anchor=center?CENTER:BOT);
}
module chamferred_cylinder(h,r,d,chamfer=0.25,chamfedge,angle=45,top=true,bottom=true,center=false) {
chamf = chamfedge!=undef? chamfedge*sin(angle) : chamfer;
cyl(h=h, r=r, d=d, chamfer1=(bottom?chamf:0), chamfer2=(top?chamf:0), chamfang=angle, anchor=center?CENTER:BOT);
chamf = chamfedge!=undef? chamfedge*sin(angle) : chamfer;
cyl(h=h, r=r, d=d, chamfer1=(bottom?chamf:0), chamfer2=(top?chamf:0), chamfang=angle, anchor=center?CENTER:BOT);
}
module chamf_cyl(h=1, r, d, chamfer=0.25, chamfedge, angle=45, center=false, top=true, bottom=true) {
chamf = chamfedge!=undef? chamfedge*sin(angle) : chamfer;
cyl(h=h, r=r, d=d, chamfer1=(bottom?chamf:0), chamfer2=(top?chamf:0), chamfang=angle, anchor=center?CENTER:BOT);
chamf = chamfedge!=undef? chamfedge*sin(angle) : chamfer;
cyl(h=h, r=r, d=d, chamfer1=(bottom?chamf:0), chamfer2=(top?chamf:0), chamfang=angle, anchor=center?CENTER:BOT);
}
module filleted_cylinder(h=1, r=undef, d=undef, r1, r2, d1, d2, fillet=0.25, center=false)
cyl(l=h, r=r, d=d, r1=r1, r2=r2, d1=d1, d2=d2, rounding=fillet, anchor=center?CENTER:BOT);
cyl(l=h, r=r, d=d, r1=r1, r2=r2, d1=d1, d2=d2, rounding=fillet, anchor=center?CENTER:BOT);
module rcylinder(h=1, r=1, r1, r2, d, d1, d2, fillet=0.25, center=false)
cyl(l=h, r=r, d=d, r1=r1, r2=r2, d1=d1, d2=d2, rounding=fillet, anchor=center?CENTER:BOT);
cyl(l=h, r=r, d=d, r1=r1, r2=r2, d1=d1, d2=d2, rounding=fillet, anchor=center?CENTER:BOT);
module thinning_brace(h=50, l=100, thick=5, ang=30, strut=5, wall=3, center=true)
thinning_triangle(h=h, l=l, thick=thick, ang=ang, strut=strut, wall=wall, diagonly=true, center=center);
thinning_triangle(h=h, l=l, thick=thick, ang=ang, strut=strut, wall=wall, diagonly=true, center=center);
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -33,97 +33,97 @@ include <knurling.scad>
// 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

View File

@ -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) =
_i<len(v) && (
is_undef(v[_i]) || (
recursive &&
is_list(v[_i]) &&
is_undef(first_defined(v[_i],recursive=recursive))
)
)? first_defined(v,recursive=recursive,_i=_i+1) : v[_i];
_i<len(v) && (
is_undef(v[_i]) || (
recursive &&
is_list(v[_i]) &&
is_undef(first_defined(v[_i],recursive=recursive))
)
)? first_defined(v,recursive=recursive,_i=_i+1) : v[_i];
// Function: one_defined()
@ -225,9 +225,9 @@ function all_defined(v,recursive=false) = max([for (x=v) is_undef(x)||(recursive
// uncentered = The value to return if `center` is not `undef` and evaluates as false. Default: ALLNEG
// dflt = The default value to return if both `anchor` and `center` are `undef`. Default: `CENTER`
function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) =
!is_undef(center)? (center? CENTER : uncentered) :
!is_undef(anchor)? anchor :
dflt;
!is_undef(center)? (center? CENTER : uncentered) :
!is_undef(anchor)? anchor :
dflt;
// Function: get_radius()
@ -251,13 +251,13 @@ function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) =
// d = Most general diameter.
// dflt = Value to return if all other values given are `undef`.
function get_radius(r1=undef, r2=undef, r=undef, d1=undef, d2=undef, d=undef, dflt=undef) = (
!is_undef(r1)? assert(is_undef(r2)&&is_undef(d1)&&is_undef(d2), "Conflicting or redundant radius/diameter arguments given.") r1 :
!is_undef(r2)? assert(is_undef(d1)&&is_undef(d2), "Conflicting or redundant radius/diameter arguments given.") r2 :
!is_undef(d1)? d1/2 :
!is_undef(d2)? d2/2 :
!is_undef(r)? assert(is_undef(d), "Conflicting or redundant radius/diameter arguments given.") r :
!is_undef(d)? d/2 :
dflt
!is_undef(r1)? assert(is_undef(r2)&&is_undef(d1)&&is_undef(d2), "Conflicting or redundant radius/diameter arguments given.") r1 :
!is_undef(r2)? assert(is_undef(d1)&&is_undef(d2), "Conflicting or redundant radius/diameter arguments given.") r2 :
!is_undef(d1)? d1/2 :
!is_undef(d2)? d2/2 :
!is_undef(r)? assert(is_undef(d), "Conflicting or redundant radius/diameter arguments given.") r :
!is_undef(d)? d/2 :
dflt
);
// Function: get_height()
@ -289,9 +289,9 @@ function get_height(h=undef,l=undef,height=undef,dflt=undef) =
// v = Value to return vector from.
// dflt = Default value to set empty vector parts from.
function scalar_vec3(v, dflt=undef) =
is_undef(v)? undef :
is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] :
!is_undef(dflt)? [v,dflt,dflt] : [v,v,v];
is_undef(v)? undef :
is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] :
!is_undef(dflt)? [v,dflt,dflt] : [v,v,v];
// Function: segs()
@ -302,8 +302,8 @@ function scalar_vec3(v, dflt=undef) =
// Arguments:
// r = Radius of circle to get the number of segments for.
function segs(r) =
$fn>0? ($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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -28,33 +28,33 @@ include <skin.scad>
// 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 = ($idx<count-1) || approx(length%scales[i],0) ? scales[i] : length % scales[i];
color(colors[$idx%2], alpha=alpha) {
w = i>0 ? 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 = ($idx<count-1) || approx(length%scales[i],0) ? scales[i] : length % scales[i];
color(colors[$idx%2], alpha=alpha) {
w = i>0 ? 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

View File

@ -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

View File

@ -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

View File

@ -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("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
echo(str("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
}
function echo_error(msg, pfx="ERROR") =
echo(str("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
echo(str("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
// 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("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
echo(str("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
}
function echo_warning(msg, pfx="WARNING") =
echo(str("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
echo(str("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
// 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(
"`<code>", name, "</code>` is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
)
);
echo_warning(pfx="DEPRECATED",
str(
"`<code>", name, "</code>` is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
)
);
}
function deprecate(name, suggest=undef) =
echo_warning(pfx="DEPRECATED",
str(
"`<code>", name, "</code>` is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
)
);
echo_warning(pfx="DEPRECATED",
str(
"`<code>", name, "</code>` is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` 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 `<code>", name, "</code>`, ",
"the argument `<code>", arg, "</code>` ",
"is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
));
echo_warning(pfx="DEPRECATED ARG", str(
"In `<code>", name, "</code>`, ",
"the argument `<code>", arg, "</code>` ",
"is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
));
}
function deprecate_argument(name, arg, suggest=undef) =
echo_warning(pfx="DEPRECATED ARG", str(
"In `<code>", name, "</code>`, ",
"the argument `<code>", arg, "</code>` ",
"is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
));
echo_warning(pfx="DEPRECATED ARG", str(
"In `<code>", name, "</code>`, ",
"the argument `<code>", arg, "</code>` ",
"is deprecated and should not be used.",
is_undef(suggest)? "" : str(
" You should use `<code>", suggest, "</code>` instead."
)
));
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -4,15 +4,15 @@ include <BOSL2/hull.scad>
$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

View File

@ -3,75 +3,75 @@ include <BOSL2/beziers.scad>
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

View File

@ -4,15 +4,15 @@ include <BOSL2/debug.scad>
$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

View File

@ -5,4 +5,4 @@ include <BOSL2/debug.scad>
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

View File

@ -5,4 +5,4 @@ include <BOSL2/debug.scad>
cube(40, center=true) show_anchors();
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -6,8 +6,8 @@ include <BOSL2/std.scad>
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

View File

@ -5,4 +5,4 @@ include <BOSL2/debug.scad>
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

View File

@ -1,17 +1,17 @@
include <BOSL2/std.scad>
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

View File

@ -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

View File

@ -1,46 +1,46 @@
include <BOSL2/std.scad>
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

View File

@ -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

View File

@ -5,4 +5,4 @@ include <BOSL2/debug.scad>
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

View File

@ -3,46 +3,46 @@ include <BOSL2/paths.scad>
include <BOSL2/beziers.scad>
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

View File

@ -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

View File

@ -5,4 +5,4 @@ include <BOSL2/debug.scad>
spheroid(d=30) show_anchors();
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -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

View File

@ -3,13 +3,13 @@ include <BOSL2/std.scad>
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

File diff suppressed because it is too large Load Diff

View File

@ -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

254
hull.scad
View File

@ -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

View File

@ -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 = r<b? k : -180/teeth,
isteps = 5,
pts = concat(
valleys? [
_gear_polar(r-1, -180.1/teeth),
_gear_polar(r, -180.1/teeth),
] : [
],
[_gear_polar(r, kk)],
[for (i=[0: 1:isteps]) _gear_q7(i/isteps,r,b,c,k, 1)],
[for (i=[isteps:-1:0]) _gear_q7(i/isteps,r,b,c,k,-1)],
[_gear_polar(r, -kk)],
valleys? [
_gear_polar(r, 180.1/teeth),
_gear_polar(r-1, 180.1/teeth),
] : [
]
)
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 = r<b? k : -180/teeth,
isteps = 5,
pts = concat(
valleys? [
_gear_polar(r-1, -180.1/teeth),
_gear_polar(r, -180.1/teeth),
] : [
],
[_gear_polar(r, kk)],
[for (i=[0: 1:isteps]) _gear_q7(i/isteps,r,b,c,k, 1)],
[for (i=[isteps:-1:0]) _gear_q7(i/isteps,r,b,c,k,-1)],
[_gear_polar(r, -kk)],
valleys? [
_gear_polar(r, 180.1/teeth),
_gear_polar(r-1, 180.1/teeth),
] : [
]
)
) reverse(pts);
module 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
) {
r = root_radius(pitch, teeth, clearance, interior);
translate([0,-r,0])
polygon(
points=gear_tooth_profile(
pitch = pitch,
teeth = teeth,
PA = PA,
backlash = backlash,
clearance = clearance,
interior = interior,
valleys = valleys
)
);
r = root_radius(pitch, teeth, clearance, interior);
translate([0,-r,0])
polygon(
points=gear_tooth_profile(
pitch = pitch,
teeth = teeth,
PA = PA,
backlash = backlash,
clearance = clearance,
interior = interior,
valleys = valleys
)
);
}
@ -250,62 +250,62 @@ module gear_tooth_profile(
// Example(2D): Partial Gear
// gear2d(pitch=5, teeth=20, hide=15, PA=20);
function 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
) = let(
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]] : []
)
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

View File

@ -34,29 +34,29 @@ include <skin.scad>
// 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

View File

@ -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

View File

@ -20,24 +20,24 @@ include <metric_screws.scad>
// 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

View File

@ -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 (r1<r2) {
zflip() {
linear_extrude(height=l, convexity=4, center=true, scale=r1/r2) {
difference() {
square(2*r2, center=true);
xcopies(2*r2) ycopies(2*r2) circle(r=r2, $fn=sides);
}
}
}
} else {
linear_extrude(height=l, convexity=4, center=true, scale=r2/r1) {
difference() {
square(2*r1, center=true);
xcopies(2*r1) ycopies(2*r1) circle(r=r1, $fn=sides);
}
}
}
children();
}
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 (r1<r2) {
zflip() {
linear_extrude(height=l, convexity=4, center=true, scale=r1/r2) {
difference() {
square(2*r2, center=true);
xcopies(2*r2) ycopies(2*r2) circle(r=r2, $fn=sides);
}
}
}
} else {
linear_extrude(height=l, convexity=4, center=true, scale=r2/r1) {
difference() {
square(2*r1, center=true);
xcopies(2*r1) ycopies(2*r1) circle(r=r1, $fn=sides);
}
}
}
children();
}
}
@ -460,11 +460,11 @@ module rounding_mask(l=undef, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0
// }
module rounding_mask_x(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0)
{
anchor = rot(p=anchor, from=RIGHT, to=TOP);
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=RIGHT) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
anchor = rot(p=anchor, from=RIGHT, to=TOP);
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=RIGHT) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
}
@ -495,11 +495,11 @@ module rounding_mask_x(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0
// }
module rounding_mask_y(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0)
{
anchor = rot(p=anchor, from=BACK, to=TOP);
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=BACK) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
anchor = rot(p=anchor, from=BACK, to=TOP);
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=BACK) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
}
@ -530,10 +530,10 @@ module rounding_mask_y(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0
// }
module rounding_mask_z(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0)
{
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=UP) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
rounding_mask(l=l, r=r, r1=r1, r2=r2, anchor=anchor, spin=spin, orient=UP) {
for (i=[0:1:$children-2]) children(i);
if ($children) children($children-1);
}
}
@ -557,13 +557,13 @@ module rounding_mask_z(l=1.0, r=undef, r1=undef, r2=undef, anchor=CENTER, spin=0
// }
module rounding(r=1, size=[1,1,1], edges=EDGES_ALL, except_edges=[])
{
difference() {
children();
difference() {
cube(size, center=true);
cuboid(size+[1,1,1]*0.01, rounding=r, edges=edges, except_edges=except_edges, trimcorners=true);
}
}
difference() {
children();
difference() {
cube(size, center=true);
cuboid(size+[1,1,1]*0.01, rounding=r, edges=edges, except_edges=except_edges, trimcorners=true);
}
}
}
@ -596,35 +596,35 @@ module rounding(r=1, size=[1,1,1], edges=EDGES_ALL, except_edges=[])
// }
module rounding_angled_edge_mask(h=1.0, r=undef, r1=undef, r2=undef, ang=90, anchor=CENTER, spin=0, orient=UP)
{
function _mask_shape(r) = [
for (i = [0:1:n]) let (a=90+ang+i*sweep/n) [r*cos(a)+x, r*sin(a)+r],
for (i = [0:1:n]) let (a=90+i*sweep/n) [r*cos(a)+x, r*sin(a)-r],
[min(-1, r*cos(270-ang)+x-1), r*sin(270-ang)-r],
[min(-1, r*cos(90+ang)+x-1), r*sin(90+ang)+r],
];
function _mask_shape(r) = [
for (i = [0:1:n]) let (a=90+ang+i*sweep/n) [r*cos(a)+x, r*sin(a)+r],
for (i = [0:1:n]) let (a=90+i*sweep/n) [r*cos(a)+x, r*sin(a)-r],
[min(-1, r*cos(270-ang)+x-1), r*sin(270-ang)-r],
[min(-1, r*cos(90+ang)+x-1), r*sin(90+ang)+r],
];
sweep = 180-ang;
r1 = get_radius(r1=r1, r=r, dflt=1);
r2 = get_radius(r1=r2, r=r, dflt=1);
n = ceil(segs(max(r1,r2))*sweep/360);
x = sin(90-(ang/2))/sin(ang/2) * (r1<r2? r2 : r1);
if(r1<r2) {
attachable(anchor,spin,orient, size=[2*x*r1/r2,2*r1,h], size2=[2*x,2*r2]) {
zflip() {
linear_extrude(height=h, convexity=4, center=true, scale=r1/r2) {
polygon(_mask_shape(r2));
}
}
children();
}
} else {
attachable(anchor,spin,orient, size=[2*x,2*r1,h], size2=[2*x*r2/r1,2*r2]) {
linear_extrude(height=h, convexity=4, center=true, scale=r2/r1) {
polygon(_mask_shape(r1));
}
children();
}
}
sweep = 180-ang;
r1 = get_radius(r1=r1, r=r, dflt=1);
r2 = get_radius(r1=r2, r=r, dflt=1);
n = ceil(segs(max(r1,r2))*sweep/360);
x = sin(90-(ang/2))/sin(ang/2) * (r1<r2? r2 : r1);
if(r1<r2) {
attachable(anchor,spin,orient, size=[2*x*r1/r2,2*r1,h], size2=[2*x,2*r2]) {
zflip() {
linear_extrude(height=h, convexity=4, center=true, scale=r1/r2) {
polygon(_mask_shape(r2));
}
}
children();
}
} else {
attachable(anchor,spin,orient, size=[2*x,2*r1,h], size2=[2*x*r2/r1,2*r2]) {
linear_extrude(height=h, convexity=4, center=true, scale=r2/r1) {
polygon(_mask_shape(r1));
}
children();
}
}
}
@ -653,26 +653,26 @@ module rounding_angled_edge_mask(h=1.0, r=undef, r1=undef, r2=undef, ang=90, anc
// }
module rounding_angled_corner_mask(r=1.0, ang=90, anchor=CENTER, spin=0, orient=UP)
{
dx = r / tan(ang/2);
dx2 = dx / cos(ang/2) + 1;
fn = quantup(segs(r), 4);
attachable(anchor,spin,orient, d=dx2, l=2*r) {
difference() {
down(r) cylinder(r=dx2, h=r+1, center=false);
yflip_copy() {
translate([dx, r, -r]) {
hull() {
sphere(r=r, $fn=fn);
down(r*3) sphere(r=r, $fn=fn);
zrot_copies([0,ang]) {
right(r*3) sphere(r=r, $fn=fn);
}
}
}
}
}
children();
}
dx = r / tan(ang/2);
dx2 = dx / cos(ang/2) + 1;
fn = quantup(segs(r), 4);
attachable(anchor,spin,orient, d=dx2, l=2*r) {
difference() {
down(r) cylinder(r=dx2, h=r+1, center=false);
yflip_copy() {
translate([dx, r, -r]) {
hull() {
sphere(r=r, $fn=fn);
down(r*3) sphere(r=r, $fn=fn);
zrot_copies([0,ang]) {
right(r*3) sphere(r=r, $fn=fn);
}
}
}
}
}
children();
}
}
@ -700,15 +700,15 @@ module rounding_angled_corner_mask(r=1.0, ang=90, anchor=CENTER, spin=0, orient=
// }
module rounding_corner_mask(r=1.0, anchor=CENTER, spin=0, orient=UP)
{
attachable(anchor,spin,orient, size=[2,2,2]*r) {
difference() {
cube(size=r*2, center=true);
grid3d(n=[2,2,2], spacing=r*2-0.05) {
sphere(r=r);
}
}
children();
}
attachable(anchor,spin,orient, size=[2,2,2]*r) {
difference() {
cube(size=r*2, center=true);
grid3d(n=[2,2,2], spacing=r*2-0.05) {
sphere(r=r);
}
}
children();
}
}
@ -735,7 +735,7 @@ module rounding_corner_mask(r=1.0, anchor=CENTER, spin=0, orient=UP)
// }
module rounding_cylinder_mask(r=1.0, rounding=0.25)
{
cylinder_mask(l=rounding*3, r=r, rounding2=rounding, overage=rounding, ends_only=true, anchor=TOP);
cylinder_mask(l=rounding*3, r=r, rounding2=rounding, overage=rounding, ends_only=true, anchor=TOP);
}
@ -772,16 +772,16 @@ module rounding_cylinder_mask(r=1.0, rounding=0.25)
// rounding_hole_mask(r=40, rounding=20, $fa=2, $fs=2);
module rounding_hole_mask(r=undef, d=undef, rounding=0.25, overage=0.1, anchor=CENTER, spin=0, orient=UP)
{
r = get_radius(r=r, d=d, dflt=1);
attachable(anchor,spin,orient, r=r+rounding, l=2*rounding) {
rotate_extrude(convexity=4) {
difference() {
right(r-overage) fwd(rounding) square(rounding+overage, center=false);
right(r+rounding) fwd(rounding) circle(r=rounding);
}
}
children();
}
r = get_radius(r=r, d=d, dflt=1);
attachable(anchor,spin,orient, r=r+rounding, l=2*rounding) {
rotate_extrude(convexity=4) {
difference() {
right(r-overage) fwd(rounding) square(rounding+overage, center=false);
right(r+rounding) fwd(rounding) circle(r=rounding);
}
}
children();
}
}
@ -803,21 +803,21 @@ module rounding_hole_mask(r=undef, d=undef, rounding=0.25, overage=0.1, anchor=C
// Example:
// diff("mask")
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
// edge_profile(BOT)
// mask2d_teardrop(r=10, angle=40);
// corner_profile(BOT,r=10)
// mask2d_teardrop(r=10, angle=40);
// edge_profile(BOT)
// mask2d_teardrop(r=10, angle=40);
// corner_profile(BOT,r=10)
// mask2d_teardrop(r=10, angle=40);
// }
module teardrop_corner_mask(r, d, angle, excess=0.1, anchor=CENTER, spin=0, orient=UP) {
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);
}
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

514
math.scad
View File

@ -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) : (a<b? b-m : b)
) [for (i=[a:step:c]) (i%m+m)%m];
let(
a = posmod(x, m),
b = posmod(y, m),
c = step>0? (a>b? b+m : b) : (a<b? b-m : b)
) [for (i=[a:step:c]) (i%m+m)%m];
@ -339,9 +339,9 @@ function modrange(x, y, m, step=1) =
// ints = rand_int(0,100,3);
// int = rand_int(-10,10,1)[0];
function rand_int(min, max, N, seed=undef) =
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)];
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 = m<n? qr_factor(transpose(A)) : qr_factor(A),
maxdim = max(n,m),
mindim = min(n,m),
Q = submatrix(qr[0],[0:maxdim-1], [0:mindim-1]),
R = submatrix(qr[1],[0:mindim-1], [0:mindim-1]),
zeros = [for(i=[0:mindim-1]) if (approx(R[i][i],0)) i]
)
zeros != [] ? undef :
m<n ? Q*back_substitute(R,b,transpose=true) :
back_substitute(R, transpose(Q)*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 = m<n? qr_factor(transpose(A)) : qr_factor(A),
maxdim = max(n,m),
mindim = min(n,m),
Q = submatrix(qr[0],[0:maxdim-1], [0:mindim-1]),
R = submatrix(qr[1],[0:mindim-1], [0:mindim-1]),
zeros = [for(i=[0:mindim-1]) if (approx(R[i][i],0)) i]
)
zeros != [] ? undef :
m<n ? Q*back_substitute(R,b,transpose=true) :
back_substitute(R, transpose(Q)*b);
// Function: matrix_inverse()
@ -593,8 +593,8 @@ function linear_solve(A,b) =
// use this function. Instead use linear_solve, or use qr_factor. The computation
// will be faster and more accurate.
function matrix_inverse(A) =
assert(is_matrix(A,square=true),"Input to matrix_inverse() must be a square matrix")
linear_solve(A,ident(len(A)));
assert(is_matrix(A,square=true),"Input to matrix_inverse() must be a square matrix")
linear_solve(A,ident(len(A)));
// Function: submatrix()
@ -610,32 +610,32 @@ function submatrix(M,ind1,ind2) = [for(i=ind1) [for(j=ind2) M[i][j] ] ];
// Calculates the QR factorization of the input matrix A and returns it as the list [Q,R]. This factorization can be
// used to solve linear systems of equations.
function qr_factor(A) =
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];
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<column || j<column ? (i==j ? 1 : 0) : Qc[i-column][j-column]]]
)
_qr_factor(Qf*A, Q*Qf, column+1, 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<column || j<column ? (i==j ? 1 : 0) : Qc[i-column][j-column]]]
)
_qr_factor(Qf*A, Q*Qf, column+1, m, n);
// Function: back_substitute()
@ -646,22 +646,22 @@ function _qr_factor(A,Q, column, m, n) =
// You can supply a compatible matrix b and it will produce the solution for every column of b. Note that if you want to
// solve Rx=b1 and Rx=b2 you must set b to transpose([b1,b2]) and then take the transpose of the result.
function back_substitute(R, b, x=[],transpose = false) =
assert(is_matrix(R, square=true))
let(n=len(R))
assert(is_vector(b,n) || is_matrix(b,n),"R and b are not compatible in back_substitute")
!is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) :
transpose?
reverse(back_substitute(
[for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]],
reverse(b), x, false
)) :
len(x) == n ? x :
let(
ind = n - len(x) - 1,
newvalue =
len(x)==0? b[ind]/R[ind][ind] :
(b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind]
) back_substitute(R, b, concat([newvalue],x));
assert(is_matrix(R, square=true))
let(n=len(R))
assert(is_vector(b,n) || is_matrix(b,n),"R and b are not compatible in back_substitute")
!is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) :
transpose?
reverse(back_substitute(
[for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]],
reverse(b), x, false
)) :
len(x) == n ? x :
let(
ind = n - len(x) - 1,
newvalue =
len(x)==0? b[ind]/R[ind][ind] :
(b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind]
) back_substitute(R, b, concat([newvalue],x));
// Function: det2()
@ -684,9 +684,9 @@ function det2(M) = M[0][0] * M[1][1] - M[0][1]*M[1][0];
// M = [ [6,4,-2], [1,-2,8], [1,5,7] ];
// det = det3(M); // Returns: -334
function det3(M) =
M[0][0] * (M[1][1]*M[2][2]-M[2][1]*M[1][2]) -
M[1][0] * (M[0][1]*M[2][2]-M[2][1]*M[0][2]) +
M[2][0] * (M[0][1]*M[1][2]-M[1][1]*M[0][2]);
M[0][0] * (M[1][1]*M[2][2]-M[2][1]*M[1][2]) -
M[1][0] * (M[0][1]*M[2][2]-M[2][1]*M[0][2]) +
M[2][0] * (M[0][1]*M[1][2]-M[1][1]*M[0][2]);
// Function: determinant()
@ -698,23 +698,23 @@ function det3(M) =
// M = [ [6,4,-2,9], [1,-2,8,3], [1,5,7,6], [4,2,5,1] ];
// det = determinant(M); // Returns: 2267
function determinant(M) =
assert(len(M)==len(M[0]))
len(M)==1? M[0][0] :
len(M)==2? det2(M) :
len(M)==3? det3(M) :
sum(
[for (col=[0:1:len(M)-1])
((col%2==0)? 1 : -1) *
M[col][0] *
determinant(
[for (r=[1:1:len(M)-1])
[for (c=[0:1:len(M)-1])
if (c!=col) M[c][r]
]
]
)
]
);
assert(len(M)==len(M[0]))
len(M)==1? M[0][0] :
len(M)==2? det2(M) :
len(M)==3? det3(M) :
sum(
[for (col=[0:1:len(M)-1])
((col%2==0)? 1 : -1) *
M[col][0] *
determinant(
[for (r=[1:1:len(M)-1])
[for (c=[0:1:len(M)-1])
if (c!=col) M[c][r]
]
]
)
]
);
// Function: is_matrix()
@ -731,12 +731,12 @@ function determinant(M) =
// n = optional width of matrix
// square = set to true to require a square matrix. Default: false
function is_matrix(A,m,n, square=false) =
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);
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) :
(a<b)? -1 : (a>b)? 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) :
(a<b)? -1 : (a>b)? 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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

1136
paths.scad

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -22,9 +22,9 @@ include <hull.scad>
// 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 && index<len(indexlist)))
assert(validindex, str(
len(indexlist),
" polyhedra meet specifications, so 'index' must be in [0,",
len(indexlist)-1,
"], but 'index' is ",
index
))
let(
entry = (
name == "trapezohedron"? (
trapezohedron(faces=faces, side=side, longside=longside, h=h, r=r)
) : (
_polyhedra_[!is_undef(index)?
indexlist[index] :
indexlist[0]]
)
),
valid_facedown = is_bool(facedown) || in_list(facedown, entry[facevertices])
)
assert(valid_facedown,str("'facedown' set to ",facedown," but selected polygon only has faces with size(s) ",entry[facevertices]))
let(
scalefactor = (
name=="trapezohedron" ? 1 : (
argcount == 0? side :
!is_undef(ir)? ir/entry[in_radius] :
!is_undef(mr)? mr/entry[mid_radius] : or/entry[out_radius]
) / entry[edgelen]
),
face_triangles = hull(entry[vertices]),
faces_normals_vertices = stellate_faces(
entry[edgelen], stellate, entry[vertices],
entry[facevertices]==[3]?
[face_triangles, [for(face=face_triangles) _facenormal(entry[vertices],face)]] :
_full_faces(entry[vertices], face_triangles)
),
faces = faces_normals_vertices[0],
faces_vertex_count = [for(face=faces) len(face)],
facedown = facedown == true ? (stellate==false? entry[facevertices][0] : 3) : facedown,
down_direction = facedown == false? [0,0,-1] :
faces_normals_vertices[1][search(facedown, faces_vertex_count)[0]],
scaled_points = scalefactor * rot(p=faces_normals_vertices[2], from=down_direction, to=[0,0,-1]),
bounds = pointlist_bounds(scaled_points),
boundtable = [bounds[0], [0,0,0], bounds[1]],
translation = [for(i=[0:2]) -boundtable[1+anchor[i]][i]],
face_normals = rot(p=faces_normals_vertices[1], from=down_direction, to=[0,0,-1]),
side_length = scalefactor * entry[edgelen]
)
info == "fullentry" ? [
scaled_points,
translation,
stellate ? faces : face_triangles,
faces,
face_normals,
side_length*entry[in_radius]
] :
info == "vnf" ? [move(translation,p=scaled_points), stellate ? faces : face_triangles] :
info == "vertices" ? move(translation,p=scaled_points) :
info == "faces" ? faces :
info == "face normals" ? face_normals :
info == "in_radius" ? side_length * entry[in_radius] :
info == "mid_radius" ? side_length * entry[mid_radius] :
info == "out_radius" ? side_length * entry[out_radius] :
info == "index set" ? indexlist :
info == "face vertices" ? (stellate==false? entry[facevertices] : [3]) :
info == "edge length" ? scalefactor * entry[edgelen] :
info == "center" ? translation :
info == "type" ? entry[class] :
info == "name" ? entry[pname] :
echo_warning(str("Unknown info type '",info,"' requested"));
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 && index<len(indexlist)))
assert(validindex, str(
len(indexlist),
" polyhedra meet specifications, so 'index' must be in [0,",
len(indexlist)-1,
"], but 'index' is ",
index
))
let(
entry = (
name == "trapezohedron"? (
trapezohedron(faces=faces, side=side, longside=longside, h=h, r=r)
) : (
_polyhedra_[!is_undef(index)?
indexlist[index] :
indexlist[0]]
)
),
valid_facedown = is_bool(facedown) || in_list(facedown, entry[facevertices])
)
assert(valid_facedown,str("'facedown' set to ",facedown," but selected polygon only has faces with size(s) ",entry[facevertices]))
let(
scalefactor = (
name=="trapezohedron" ? 1 : (
argcount == 0? side :
!is_undef(ir)? ir/entry[in_radius] :
!is_undef(mr)? mr/entry[mid_radius] : or/entry[out_radius]
) / entry[edgelen]
),
face_triangles = hull(entry[vertices]),
faces_normals_vertices = stellate_faces(
entry[edgelen], stellate, entry[vertices],
entry[facevertices]==[3]?
[face_triangles, [for(face=face_triangles) _facenormal(entry[vertices],face)]] :
_full_faces(entry[vertices], face_triangles)
),
faces = faces_normals_vertices[0],
faces_vertex_count = [for(face=faces) len(face)],
facedown = facedown == true ? (stellate==false? entry[facevertices][0] : 3) : facedown,
down_direction = facedown == false? [0,0,-1] :
faces_normals_vertices[1][search(facedown, faces_vertex_count)[0]],
scaled_points = scalefactor * rot(p=faces_normals_vertices[2], from=down_direction, to=[0,0,-1]),
bounds = pointlist_bounds(scaled_points),
boundtable = [bounds[0], [0,0,0], bounds[1]],
translation = [for(i=[0:2]) -boundtable[1+anchor[i]][i]],
face_normals = rot(p=faces_normals_vertices[1], from=down_direction, to=[0,0,-1]),
side_length = scalefactor * entry[edgelen]
)
info == "fullentry" ? [
scaled_points,
translation,
stellate ? faces : face_triangles,
faces,
face_normals,
side_length*entry[in_radius]
] :
info == "vnf" ? [move(translation,p=scaled_points), stellate ? faces : face_triangles] :
info == "vertices" ? move(translation,p=scaled_points) :
info == "faces" ? faces :
info == "face normals" ? face_normals :
info == "in_radius" ? side_length * entry[in_radius] :
info == "mid_radius" ? side_length * entry[mid_radius] :
info == "out_radius" ? side_length * entry[out_radius] :
info == "index set" ? indexlist :
info == "face vertices" ? (stellate==false? entry[facevertices] : [3]) :
info == "edge length" ? scalefactor * entry[edgelen] :
info == "center" ? translation :
info == "type" ? entry[class] :
info == "name" ? entry[pname] :
echo_warning(str("Unknown info type '",info,"' requested"));
@ -718,68 +718,68 @@ function regular_polyhedron_info(
/// either cross product or just rotate to
///
function stellate_faces(scalefactor,stellate,vertices,faces_normals) =
(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];
(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

View File

@ -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

View File

@ -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

View File

@ -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<queuesize-pos)
[for (i=[0:1:n-1]) queue[pos+i]]
);
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<queuesize-pos)
[for (i=[0:1:n-1]) queue[pos+i]]
);
// Function: queue_add()
@ -166,8 +166,8 @@ function queue_peek(queue,pos=0,n=undef) =
// val = queue_head(q2);
// q3 = queue_pop(q2);
function queue_add(queue,items) =
assert(is_list(queue))
is_list(items)? concat(queue, items) : concat(queue, [items]);
assert(is_list(queue))
is_list(items)? concat(queue, items) : concat(queue, [items]);
// Function: queue_pop()
@ -188,13 +188,13 @@ function queue_add(queue,items) =
// val = queue_head(q2);
// q3 = queue_pop(q2);
function queue_pop(queue,n=1) =
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]];
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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

122
skin.scad
View File

@ -163,26 +163,26 @@ include <vnf.scad>
// 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 <vnf.scad>
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<j ? 1 : 0) ,
p1 = voff + (i%plen1),
p2 = voff + (j%plen2) + plen1,
p3 = voff + (side? ((i+1)%plen1) : (((j+1)%plen2) + plen1)),
face = [p1, p3, p2],
i = i + (side? 1 : 0),
j = j + (side? 0 : 1),
first = false,
finished = finishing,
finishing = 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<j ? 1 : 0) ,
p1 = voff + (i%plen1),
p2 = voff + (j%plen2) + plen1,
p3 = voff + (side? ((i+1)%plen1) : (((j+1)%plen2) + plen1)),
face = [p1, p3, p2],
i = i + (side? 1 : 0),
j = j + (side? 0 : 1),
first = false,
finished = finishing,
finishing = 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

View File

@ -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

View File

@ -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

View File

@ -39,5 +39,5 @@ include <masks.scad>
include <paths.scad>
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -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 <len(pattern)? false :
_str_cmp_recurse(str,sindex,pattern,len(pattern));
len(str)-sindex <len(pattern)? false :
_str_cmp_recurse(str,sindex,pattern,len(pattern));
function _str_cmp_recurse(str,sindex,pattern,plen,pindex=0,) =
pindex < plen && pattern[pindex]==str[sindex] ? _str_cmp_recurse(str,sindex+1,pattern,plen,pindex+1): (pindex==plen);
pindex < plen && pattern[pindex]==str[sindex] ? _str_cmp_recurse(str,sindex+1,pattern,plen,pindex+1): (pindex==plen);
// Function: str_find()
@ -315,25 +315,25 @@ function _str_cmp_recurse(str,sindex,pattern,plen,pindex=0,) =
// str_find("abc123def123abc","1234",all=true); // Returns []
// str_find("abc","",all=true); // Returns [0,1,2]
function str_find(str,pattern,start=undef,last=false,all=false) =
all? _str_find_all(str,pattern) :
let( start = first_defined([start,last?len(str)-len(pattern):0]) )
pattern==""? start :
last? _str_find_last(str,pattern,start) :
_str_find_first(str,pattern,len(str)-len(pattern),start);
all? _str_find_all(str,pattern) :
let( start = first_defined([start,last?len(str)-len(pattern):0]) )
pattern==""? start :
last? _str_find_last(str,pattern,start) :
_str_find_first(str,pattern,len(str)-len(pattern),start);
function _str_find_first(str,pattern,max_sindex,sindex) =
sindex<=max_sindex && !_str_cmp(str,sindex, pattern)?
_str_find_first(str,pattern,max_sindex,sindex+1) :
(sindex <= max_sindex ? sindex : undef);
sindex<=max_sindex && !_str_cmp(str,sindex, pattern)?
_str_find_first(str,pattern,max_sindex,sindex+1) :
(sindex <= max_sindex ? sindex : undef);
function _str_find_last(str,pattern,sindex) =
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=="<"? "&lt;" :
c==">"? "&gt;" :
c=="&"? "&amp;" :
c=="\""? "&quot;" :
c
]);
str_join([
for (c=s)
c=="<"? "&lt;" :
c==">"? "&gt;" :
c=="&"? "&amp;" :
c=="\""? "&quot;" :
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<len(vals)) vals[num],
unpad = typ=="s"? (
let( sval = str(val) )
is_undef(prec)? sval :
substr(sval, 0, min(len(sval)-1, prec))
) :
(typ=="d" || typ=="i")? fmt_int(val) :
typ=="b"? (val? "true" : "false") :
typ=="B"? (val? "TRUE" : "FALSE") :
typ=="f"? downcase(fmt_fixed(val,default(prec,6))) :
typ=="F"? upcase(fmt_fixed(val,default(prec,6))) :
typ=="g"? downcase(fmt_float(val,default(prec,6))) :
typ=="G"? upcase(fmt_float(val,default(prec,6))) :
assert(false,str("Unknown format type: ",typ)),
padlen = max(0,wid-len(unpad)),
padfill = str_join([for (i=[0:1:padlen-1]) zero? "0" : use_nbsp? "&nbsp;" : " "]),
out = left? str(unpad, padfill) : str(padfill, unpad)
)
out, raw
]
]);
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<len(vals)) vals[num],
unpad = typ=="s"? (
let( sval = str(val) )
is_undef(prec)? sval :
substr(sval, 0, min(len(sval)-1, prec))
) :
(typ=="d" || typ=="i")? fmt_int(val) :
typ=="b"? (val? "true" : "false") :
typ=="B"? (val? "TRUE" : "FALSE") :
typ=="f"? downcase(fmt_fixed(val,default(prec,6))) :
typ=="F"? upcase(fmt_fixed(val,default(prec,6))) :
typ=="g"? downcase(fmt_float(val,default(prec,6))) :
typ=="G"? upcase(fmt_float(val,default(prec,6))) :
assert(false,str("Unknown format type: ",typ)),
padlen = max(0,wid-len(unpad)),
padfill = str_join([for (i=[0:1:padlen-1]) zero? "0" : use_nbsp? "&nbsp;" : " "]),
out = left? str(unpad, padfill) : str(padfill, unpad)
)
out, raw
]
]);
// Function&Module: echofmt()
// Usage:
@ -699,4 +699,4 @@ function echofmt(fmt, vals, use_nbsp=false) = echo(str_format(fmt,vals,use_nbsp)
module echofmt(fmt, vals, use_nbsp=false) echo(str_format(fmt,vals,use_nbsp));
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -32,20 +32,20 @@
// value = Value to set the keyword to.
// grow = Set to true to allow structure to grow, or false for new keywords to generate an error. Default: true
function struct_set(struct, keyword, value=undef, grow=true) =
!is_list(keyword)? (
let( ind=search([keyword],struct,1,0)[0] )
ind==[]? (
assert(grow,str("Unknown keyword \"",keyword))
concat(struct, [[keyword,value]])
) : list_set(struct, [ind], [[keyword,value]])
) : _parse_pairs(struct,keyword,grow);
!is_list(keyword)? (
let( ind=search([keyword],struct,1,0)[0] )
ind==[]? (
assert(grow,str("Unknown keyword \"",keyword))
concat(struct, [[keyword,value]])
) : list_set(struct, [ind], [[keyword,value]])
) : _parse_pairs(struct,keyword,grow);
function _parse_pairs(spec, input, grow=true, index=0, result=undef) =
assert(len(input)%2==0,"Odd number of entries in [keyword,value] pair list")
let( result = result==undef ? spec : result)
index == len(input) ? result :
_parse_pairs(spec,input,grow,index+2,struct_set(result, input[index], input[index+1],grow));
assert(len(input)%2==0,"Odd number of entries in [keyword,value] pair list")
let( result = result==undef ? spec : result)
index == len(input) ? result :
_parse_pairs(spec,input,grow,index+2,struct_set(result, input[index], input[index+1],grow));
// Function: struct_remove()
@ -57,9 +57,9 @@ function _parse_pairs(spec, input, grow=true, index=0, result=undef) =
// struct = input structure
// keyword = a single string (keyword) or list of strings (keywords) to remove
function struct_remove(struct, keyword) =
is_string(keyword)? struct_remove(struct, [keyword]) :
let(ind = search(keyword, struct))
list_remove(struct, ind);
is_string(keyword)? struct_remove(struct, [keyword]) :
let(ind = search(keyword, struct))
list_remove(struct, ind);
// Function: struct_val()
@ -71,9 +71,9 @@ function struct_remove(struct, keyword) =
// struct = input structure
// keyword = keyword whose value to return
function struct_val(struct,keyword) =
assert(is_def(keyword),"keyword is missing")
let(ind = search([keyword],struct)[0])
ind == [] ? undef : struct[ind][1];
assert(is_def(keyword),"keyword is missing")
let(ind = search([keyword],struct)[0])
ind == [] ? undef : struct[ind][1];
// Function: struct_keys()
@ -84,7 +84,7 @@ function struct_val(struct,keyword) =
// Arguments:
// struct = input structure
function struct_keys(struct) =
[for(entry=struct) entry[0]];
[for(entry=struct) entry[0]];
// Function&Module: struct_echo()
@ -96,12 +96,12 @@ function struct_keys(struct) =
// struct = input structure
// name = optional structure name to list at the top of the output. Default: ""
function struct_echo(struct,name="") =
let( keylist = [for(entry=struct) str("&nbsp;&nbsp;",entry[0],": ",entry[1],"\n")])
echo(str("\nStructure ",name,"\n",str_join(keylist)))
undef;
let( keylist = [for(entry=struct) str("&nbsp;&nbsp;",entry[0],": ",entry[1],"\n")])
echo(str("\nStructure ",name,"\n",str_join(keylist)))
undef;
module struct_echo(struct,name="") {
dummy = struct_echo(struct,name);
dummy = struct_echo(struct,name);
}
@ -111,14 +111,14 @@ module struct_echo(struct,name="") {
// Description:
// Returns true if the input has the form of a structure, false otherwise.
function is_struct(x) =
is_list(x) && [
for (xx=x) if(
!is_list(xx) ||
len(xx) != 2 ||
!is_string(xx[0])
) 1
] == [];
is_list(x) && [
for (xx=x) if(
!is_list(xx) ||
len(xx) != 2 ||
!is_string(xx[0])
) 1
] == [];
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -3,12 +3,12 @@ include <BOSL2/hull.scad>
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

View File

@ -4,259 +4,259 @@ include <BOSL2/std.scad>
// 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

View File

@ -2,254 +2,254 @@ include <BOSL2/std.scad>
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

View File

@ -2,208 +2,208 @@ include <BOSL2/std.scad>
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

View File

@ -3,12 +3,12 @@ include <BOSL2/cubetruss.scad>
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

View File

@ -2,103 +2,103 @@ include <BOSL2/std.scad>
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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -3,377 +3,377 @@ include <BOSL2/std.scad>
// 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

View File

@ -2,27 +2,27 @@ include <BOSL2/std.scad>
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

View File

@ -3,283 +3,283 @@ include <BOSL2/strings.scad>
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

View File

@ -3,75 +3,75 @@ include <BOSL2/queues.scad>
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

View File

@ -3,17 +3,17 @@ include <BOSL2/skin.scad>
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

View File

@ -3,77 +3,77 @@ include <BOSL2/stacks.scad>
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

View File

@ -3,57 +3,57 @@ include <BOSL2/structs.scad>
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

View File

@ -1,159 +1,159 @@
include <BOSL2/std.scad>
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

View File

@ -2,121 +2,121 @@ include <BOSL2/std.scad>
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 <BOSL2/strings.scad>
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

View File

@ -2,116 +2,116 @@ include <BOSL2/std.scad>
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

View File

@ -3,101 +3,101 @@ include <BOSL2/vnf.scad>
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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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) =
(i<len(face)-1)?
let(
prev=point_in_ear(points, face, tests, i+1),
test=_check_point_in_ear(points[face[i]], tests)
)
(test>prev[0])? [test, i] : prev
:
[_check_point_in_ear(points[face[i]], tests), i]
(i<len(face)-1)?
let(
prev=point_in_ear(points, face, tests, i+1),
test=_check_point_in_ear(points[face[i]], tests)
)
(test>prev[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

View File

@ -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

View File

@ -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

788
vnf.scad
View File

@ -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]<edge[1]? edge : [edge[1],edge[0]]
]),
edgecnts = unique_count(edges),
uniq_edges = edgecnts[0],
big_faces = !show_warns? [] : [
for (face = faces)
if (len(face) > 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]<edge1[1]? edge1 : [edge1[1],edge1[0]],
e2 = edge2[0]<edge2[1]? edge2 : [edge2[1],edge2[0]]
) if (e1==e2) 1
]
)
if (!shared_edges) let(
plane1 = plane3pt_indexed(varr, f1[0], f1[1], f1[2]),
plane2 = plane3pt_indexed(varr, f2[0], f2[1], f2[2]),
line = plane_intersection(plane1, plane2)
)
if (!is_undef(line)) let(
poly1 = select(varr,f1),
isects = polygon_line_intersection(poly1,line)
)
if (!is_undef(isects))
for (isect=isects)
if (len(isect)>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]<edge[1]? edge : [edge[1],edge[0]]
]),
edgecnts = unique_count(edges),
uniq_edges = edgecnts[0],
big_faces = !show_warns? [] : [
for (face = faces)
if (len(face) > 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]<edge1[1]? edge1 : [edge1[1],edge1[0]],
e2 = edge2[0]<edge2[1]? edge2 : [edge2[1],edge2[0]]
) if (e1==e2) 1
]
)
if (!shared_edges) let(
plane1 = plane3pt_indexed(varr, f1[0], f1[1], f1[2]),
plane2 = plane3pt_indexed(varr, f2[0], f2[1], f2[2]),
line = plane_intersection(plane1, plane2)
)
if (!is_undef(line)) let(
poly1 = select(varr,f1),
isects = polygon_line_intersection(poly1,line)
)
if (!is_undef(isects))
for (isect=isects)
if (len(isect)>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

View File

@ -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

View File

@ -28,15 +28,15 @@ include <beziers.scad>
// 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