mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
commit
4e170bb3e5
30 changed files with 1139 additions and 1094 deletions
36
arrays.scad
36
arrays.scad
|
@ -161,12 +161,12 @@ function last(list) =
|
|||
// Arguments:
|
||||
// list = The list to get the head of.
|
||||
// to = The last index to include. If negative, adds the list length to it. ie: -1 is the last list item.
|
||||
// Examples:
|
||||
// hlist = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
||||
// hlist = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"]
|
||||
// hlist = list_head(["foo", "bar", "baz"], 2); // Returns: ["foo","bar"]
|
||||
// hlist = list_head(["foo", "bar", "baz"], -5); // Returns: []
|
||||
// hlist = list_head(["foo", "bar", "baz"], 5); // Returns: ["foo","bar","baz"]
|
||||
// Example:
|
||||
// hlist1 = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
||||
// hlist2 = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"]
|
||||
// hlist3 = list_head(["foo", "bar", "baz"], 2); // Returns: ["foo","bar"]
|
||||
// hlist4 = list_head(["foo", "bar", "baz"], -5); // Returns: []
|
||||
// hlist5 = list_head(["foo", "bar", "baz"], 5); // Returns: ["foo","bar","baz"]
|
||||
function list_head(list, to=-2) =
|
||||
assert(is_list(list))
|
||||
assert(is_finite(to))
|
||||
|
@ -188,12 +188,12 @@ function list_head(list, to=-2) =
|
|||
// Arguments:
|
||||
// list = The list to get the tail of.
|
||||
// from = The first index to include. If negative, adds the list length to it. ie: -1 is the last list item.
|
||||
// Examples:
|
||||
// tlist = list_tail(["foo", "bar", "baz"]); // Returns: ["bar", "baz"]
|
||||
// tlist = list_tail(["foo", "bar", "baz"], -1); // Returns: ["baz"]
|
||||
// tlist = list_tail(["foo", "bar", "baz"], 2); // Returns: ["baz"]
|
||||
// tlist = list_tail(["foo", "bar", "baz"], -5); // Returns: ["foo","bar","baz"]
|
||||
// tlist = list_tail(["foo", "bar", "baz"], 5); // Returns: []
|
||||
// Example:
|
||||
// tlist1 = list_tail(["foo", "bar", "baz"]); // Returns: ["bar", "baz"]
|
||||
// tlist2 = list_tail(["foo", "bar", "baz"], -1); // Returns: ["baz"]
|
||||
// tlist3 = list_tail(["foo", "bar", "baz"], 2); // Returns: ["baz"]
|
||||
// tlist4 = list_tail(["foo", "bar", "baz"], -5); // Returns: ["foo","bar","baz"]
|
||||
// tlist5 = list_tail(["foo", "bar", "baz"], 5); // Returns: []
|
||||
function list_tail(list, from=1) =
|
||||
assert(is_list(list))
|
||||
assert(is_finite(from))
|
||||
|
@ -236,7 +236,7 @@ function list(l) = is_list(l)? l : [for (x=l) x];
|
|||
// value = The value or list to coerce into a list.
|
||||
// n = The number of items in the coerced list. Default: 1
|
||||
// fill = The value to pad the coerced list with, after the firt value. Default: undef (pad with copies of `value`)
|
||||
// Examples:
|
||||
// Example:
|
||||
// x = force_list([3,4,5]); // Returns: [3,4,5]
|
||||
// y = force_list(5); // Returns: [5]
|
||||
// z = force_list(7, n=3); // Returns: [7,7,7]
|
||||
|
@ -509,7 +509,7 @@ function list_rotate(list,n=1) =
|
|||
// list = The list to deduplicate.
|
||||
// closed = If true, drops trailing items if they match the first list item.
|
||||
// eps = The maximum tolerance between items.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = deduplicate([8,3,4,4,4,8,2,3,3,8,8]); // Returns: [8,3,4,8,2,3,8]
|
||||
// b = deduplicate(closed=true, [8,3,4,4,4,8,2,3,3,8,8]); // Returns: [8,3,4,8,2,3]
|
||||
// c = deduplicate("Hello"); // Returns: "Helo"
|
||||
|
@ -539,7 +539,7 @@ function deduplicate(list, closed=false, eps=EPSILON) =
|
|||
// indices = The list of indices to deduplicate.
|
||||
// closed = If true, drops trailing indices if what they index matches what the first index indexes.
|
||||
// eps = The maximum difference to allow between numbers or vectors.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1]); // Returns: [1,4,3,2,0,1]
|
||||
// b = deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1], closed=true); // Returns: [1,4,3,2,0]
|
||||
// c = deduplicate_indexed([[7,undef],[7,undef],[1,4],[1,4],[1,4+1e-12]],eps=0); // Returns: [0,2,4]
|
||||
|
@ -592,7 +592,7 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) =
|
|||
// list = list whose entries will be repeated
|
||||
// N = scalar total number of points desired or vector requesting N[i] copies of vertex i.
|
||||
// exact = if true return exactly the requested number of points, possibly sacrificing uniformity. If false, return uniform points that may not match the number of points requested. Default: True
|
||||
// Examples:
|
||||
// Example:
|
||||
// list = [0,1,2,3];
|
||||
// a = repeat_entries(list, 6); // Returns: [0,0,1,2,2,3]
|
||||
// b = repeat_entries(list, 6, exact=false); // Returns: [0,0,1,1,2,2,3,3]
|
||||
|
@ -629,7 +629,7 @@ function repeat_entries(list, N, exact=true) =
|
|||
// values = List of values to set.
|
||||
// dflt = Default value to store in sparse skipped indices.
|
||||
// minlen = Minimum length to expand list to.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = list_set([2,3,4,5], 2, 21); // Returns: [2,3,21,5]
|
||||
// b = list_set([2,3,4,5], [1,3], [81,47]); // Returns: [2,81,4,47]
|
||||
function list_set(list=[],indices,values,dflt=0,minlen=0) =
|
||||
|
@ -1890,7 +1890,7 @@ function _array_dim_recurse(v) =
|
|||
// Arguments:
|
||||
// v = Array to get dimensions of.
|
||||
// depth = Dimension to get size of. If not given, returns a list of dimension lengths.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]); // Returns [2,2,3]
|
||||
// b = array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 0); // Returns 2
|
||||
// c = array_dim([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]], 2); // Returns 3
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// Default values for attachment code.
|
||||
$tags = "";
|
||||
$overlap = 0;
|
||||
$color = undef;
|
||||
$color = "yellow";
|
||||
|
||||
$attach_to = undef;
|
||||
$attach_anchor = [CENTER, CENTER, UP, 0];
|
||||
|
@ -1008,9 +1008,9 @@ module attachable(
|
|||
|
||||
|
||||
|
||||
// Function: anchorpt()
|
||||
// Function: named_anchor()
|
||||
// Usage:
|
||||
// a = anchorpt(name, pos, [orient], [spin]);
|
||||
// a = named_anchor(name, pos, [orient], [spin]);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
|
@ -1021,7 +1021,7 @@ module attachable(
|
|||
// pos = The [X,Y,Z] position of the anchor.
|
||||
// orient = A vector pointing in the direction parts should project from the anchor position.
|
||||
// spin = If needed, the angle to rotate the part around the direction vector.
|
||||
function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
|
||||
function named_anchor(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
|
||||
|
||||
|
||||
// Function: reorient()
|
||||
|
@ -1759,94 +1759,5 @@ function _attachment_is_shown(tags) =
|
|||
) shown && !hidden;
|
||||
|
||||
|
||||
// Section: Attachable Text
|
||||
|
||||
// Module: atext()
|
||||
// Topics: Attachments, Text
|
||||
// Usage:
|
||||
// atext(text, [h], [size], [font]);
|
||||
// Description:
|
||||
// Creates a 3D text block that can be attached to other attachable objects.
|
||||
// NOTE: This cannot have children attached to it.
|
||||
// Arguments:
|
||||
// text = The text string to instantiate as an object.
|
||||
// h = The height to which the text should be extruded. Default: 1
|
||||
// size = The font size used to create the text block. Default: 10
|
||||
// font = The name of the font used to create the text block. Default: "Courier"
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `"baseline"`
|
||||
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// See Also: attachable()
|
||||
// Extra Anchors:
|
||||
// "baseline" = Anchors at the baseline of the text, at the start of the string.
|
||||
// str("baseline",VECTOR) = Anchors at the baseline of the text, modified by the X and Z components of the appended vector.
|
||||
// Examples:
|
||||
// atext("Foobar", h=3, size=10);
|
||||
// atext("Foobar", h=2, size=12, font="Helvetica");
|
||||
// atext("Foobar", h=2, anchor=CENTER);
|
||||
// atext("Foobar", h=2, anchor=str("baseline",CENTER));
|
||||
// atext("Foobar", h=2, anchor=str("baseline",BOTTOM+RIGHT));
|
||||
// Example: Using line_of() distributor
|
||||
// txt = "This is the string.";
|
||||
// line_of(spacing=[10,-5],n=len(txt))
|
||||
// atext(txt[$idx], size=10, anchor=CENTER);
|
||||
// Example: Using arc_of() distributor
|
||||
// txt = "This is the string";
|
||||
// arc_of(r=50, n=len(txt), sa=0, ea=180)
|
||||
// atext(select(txt,-1-$idx), size=10, anchor=str("baseline",CENTER), spin=-90);
|
||||
module atext(text, h=1, size=9, font="Courier", anchor="baseline", spin=0, orient=UP) {
|
||||
no_children($children);
|
||||
dummy1 =
|
||||
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Got: ",anchor))
|
||||
assert(is_undef(spin) || is_vector(spin,3) || is_num(spin), str("Got: ",spin))
|
||||
assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient));
|
||||
anchor = default(anchor, CENTER);
|
||||
spin = default(spin, 0);
|
||||
orient = default(orient, UP);
|
||||
geom = _attach_geom(size=[size,size,h]);
|
||||
anch = !any([for (c=anchor) c=="["])? anchor :
|
||||
let(
|
||||
parts = str_split(str_split(str_split(anchor,"]")[0],"[")[1],","),
|
||||
vec = [for (p=parts) str_float(str_strip_leading(p," "))]
|
||||
) vec;
|
||||
ha = anchor=="baseline"? "left" :
|
||||
anchor==anch && is_string(anchor)? "center" :
|
||||
anch.x<0? "left" :
|
||||
anch.x>0? "right" :
|
||||
"center";
|
||||
va = starts_with(anchor,"baseline")? "baseline" :
|
||||
anchor==anch && is_string(anchor)? "center" :
|
||||
anch.y<0? "bottom" :
|
||||
anch.y>0? "top" :
|
||||
"center";
|
||||
base = anchor=="baseline"? CENTER :
|
||||
anchor==anch && is_string(anchor)? CENTER :
|
||||
anch.z<0? BOTTOM :
|
||||
anch.z>0? TOP :
|
||||
CENTER;
|
||||
m = _attach_transform(base,spin,orient,geom);
|
||||
multmatrix(m) {
|
||||
$parent_anchor = anchor;
|
||||
$parent_spin = spin;
|
||||
$parent_orient = orient;
|
||||
$parent_geom = geom;
|
||||
$parent_size = _attach_geom_size(geom);
|
||||
$attach_to = undef;
|
||||
do_show = _attachment_is_shown($tags);
|
||||
if (do_show) {
|
||||
if (is_undef($color)) {
|
||||
linear_extrude(height=h, center=true)
|
||||
text(text=text, size=size, halign=ha, valign=va, font=font);
|
||||
} else color($color) {
|
||||
$color = undef;
|
||||
linear_extrude(height=h, center=true)
|
||||
text(text=text, size=size, halign=ha, valign=va, font=font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
|
@ -67,8 +67,8 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
|
|||
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])
|
||||
named_anchor("support-ring", [0,0,neck_h-h/2]),
|
||||
named_anchor("tamper-ring", [0,0,h/2-tamper_base_h])
|
||||
];
|
||||
attachable(anchor,spin,orient, d1=neck_d, d2=lip_recess_d+2*lip_leadin_r, l=h, anchors=anchors) {
|
||||
down(h/2) {
|
||||
|
@ -173,7 +173,7 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
|
|||
w = cap_id + 2*wall;
|
||||
h = tamper_ring_h + wall;
|
||||
anchors = [
|
||||
anchorpt("inside-top", [0,0,-(h/2-wall)])
|
||||
named_anchor("inside-top", [0,0,-(h/2-wall)])
|
||||
];
|
||||
attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
|
||||
down(h/2) zrot(45) {
|
||||
|
@ -260,8 +260,8 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
|
|||
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])
|
||||
named_anchor("support-ring", [0,0,neck_h-h/2]),
|
||||
named_anchor("tamper-ring", [0,0,h/2-tamper_base_h])
|
||||
];
|
||||
attachable(anchor,spin,orient, d1=neck_d, d2=lip_recess_d+2*lip_leadin_r, l=h, anchors=anchors) {
|
||||
down(h/2) {
|
||||
|
@ -357,7 +357,7 @@ module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
|
|||
w = 28.58 + 2*wall;
|
||||
h = 11.2 + wall;
|
||||
anchors = [
|
||||
anchorpt("inside-top", [0,0,-(h/2-wall)])
|
||||
named_anchor("inside-top", [0,0,-(h/2-wall)])
|
||||
];
|
||||
attachable(anchor,spin,orient, d=w, l=h, anchors=anchors) {
|
||||
down(h/2) zrot(45) {
|
||||
|
@ -448,7 +448,7 @@ module generic_bottle_neck(
|
|||
$fn = segs(33 / 2);
|
||||
thread_h = (thread_od - threadbase_d) / 2;
|
||||
anchors = [
|
||||
anchorpt("support-ring", [0, 0, 0 - h / 2])
|
||||
named_anchor("support-ring", [0, 0, 0 - h / 2])
|
||||
];
|
||||
attachable(anchor, spin, orient, d1 = neck_d, d2 = 0, l = h, anchors = anchors) {
|
||||
down(h / 2) {
|
||||
|
@ -563,7 +563,7 @@ module generic_bottle_cap(
|
|||
heightMagMult = (height > 11.2) ? height / 11.2 : 1;
|
||||
|
||||
anchors = [
|
||||
anchorpt("inside-top", [0, 0, -(h / 2 - wall)])
|
||||
named_anchor("inside-top", [0, 0, -(h / 2 - wall)])
|
||||
];
|
||||
attachable(anchor, spin, orient, d = w, l = h, anchors = anchors) {
|
||||
down(h / 2) {
|
||||
|
|
25
coords.scad
25
coords.scad
|
@ -18,7 +18,7 @@
|
|||
// Arguments:
|
||||
// p = The coordinates to force into a 2D vector/point.
|
||||
// fill = Value to fill missing values in vector with.
|
||||
function point2d(p, fill=0) = [for (i=[0:1]) (p[i]==undef)? fill : p[i]];
|
||||
function point2d(p, fill=0) = assert(is_list(p)) [for (i=[0:1]) (p[i]==undef)? fill : p[i]];
|
||||
|
||||
|
||||
// Function: path2d()
|
||||
|
@ -49,7 +49,9 @@ function path2d(points) =
|
|||
// Arguments:
|
||||
// p = The coordinates to force into a 3D vector/point.
|
||||
// fill = Value to fill missing values in vector with.
|
||||
function point3d(p, fill=0) = [for (i=[0:2]) (p[i]==undef)? fill : p[i]];
|
||||
function point3d(p, fill=0) =
|
||||
assert(is_list(p))
|
||||
[for (i=[0:2]) (p[i]==undef)? fill : p[i]];
|
||||
|
||||
|
||||
// Function: path3d()
|
||||
|
@ -86,7 +88,8 @@ function path3d(points, fill=0) =
|
|||
// Arguments:
|
||||
// p = The coordinates to force into a 4D vector/point.
|
||||
// fill = Value to fill missing values in vector with.
|
||||
function point4d(p, fill=0) = [for (i=[0:3]) (p[i]==undef)? fill : p[i]];
|
||||
function point4d(p, fill=0) = assert(is_list(p))
|
||||
[for (i=[0:3]) (p[i]==undef)? fill : p[i]];
|
||||
|
||||
|
||||
// Function: path4d()
|
||||
|
@ -133,7 +136,7 @@ function path4d(points, fill=0) =
|
|||
// Arguments:
|
||||
// r = distance from the origin.
|
||||
// theta = angle in degrees, counter-clockwise of X+.
|
||||
// Examples:
|
||||
// Example:
|
||||
// xy = polar_to_xy(20,45); // Returns: ~[14.1421365, 14.1421365]
|
||||
// xy = polar_to_xy(40,30); // Returns: ~[34.6410162, 15]
|
||||
// xy = polar_to_xy([40,30]); // Returns: ~[34.6410162, 15]
|
||||
|
@ -162,7 +165,7 @@ function polar_to_xy(r,theta=undef) = let(
|
|||
// Arguments:
|
||||
// x = X coordinate.
|
||||
// y = Y coordinate.
|
||||
// Examples:
|
||||
// Example:
|
||||
// plr = xy_to_polar(20,30);
|
||||
// plr = xy_to_polar([40,60]);
|
||||
// Example(2D):
|
||||
|
@ -317,7 +320,7 @@ function lift_plane(plane, p) =
|
|||
// r = distance from the Z axis.
|
||||
// theta = angle in degrees, counter-clockwise of X+ on the XY plane.
|
||||
// z = Height above XY plane.
|
||||
// Examples:
|
||||
// Example:
|
||||
// xyz = cylindrical_to_xyz(20,30,40);
|
||||
// xyz = cylindrical_to_xyz([40,60,50]);
|
||||
function cylindrical_to_xyz(r,theta=undef,z=undef) = let(
|
||||
|
@ -340,7 +343,7 @@ function cylindrical_to_xyz(r,theta=undef,z=undef) = let(
|
|||
// x = X coordinate.
|
||||
// y = Y coordinate.
|
||||
// z = Z coordinate.
|
||||
// Examples:
|
||||
// Example:
|
||||
// cyl = xyz_to_cylindrical(20,30,40);
|
||||
// cyl = xyz_to_cylindrical([40,50,70]);
|
||||
function xyz_to_cylindrical(x,y=undef,z=undef) = let(
|
||||
|
@ -360,7 +363,7 @@ function xyz_to_cylindrical(x,y=undef,z=undef) = let(
|
|||
// r = distance from origin.
|
||||
// theta = angle in degrees, counter-clockwise of X+ on the XY plane.
|
||||
// phi = angle in degrees from the vertical Z+ axis.
|
||||
// Examples:
|
||||
// Example:
|
||||
// xyz = spherical_to_xyz(20,30,40);
|
||||
// xyz = spherical_to_xyz([40,60,50]);
|
||||
function spherical_to_xyz(r,theta=undef,phi=undef) = let(
|
||||
|
@ -383,7 +386,7 @@ function spherical_to_xyz(r,theta=undef,phi=undef) = let(
|
|||
// x = X coordinate.
|
||||
// y = Y coordinate.
|
||||
// z = Z coordinate.
|
||||
// Examples:
|
||||
// Example:
|
||||
// sph = xyz_to_spherical(20,30,40);
|
||||
// sph = xyz_to_spherical([40,50,70]);
|
||||
function xyz_to_spherical(x,y=undef,z=undef) = let(
|
||||
|
@ -404,7 +407,7 @@ function xyz_to_spherical(x,y=undef,z=undef) = let(
|
|||
// alt = altitude angle in degrees above the XY plane.
|
||||
// az = azimuth angle in degrees clockwise of Y+ on the XY plane.
|
||||
// r = distance from origin.
|
||||
// Examples:
|
||||
// Example:
|
||||
// xyz = altaz_to_xyz(20,30,40);
|
||||
// xyz = altaz_to_xyz([40,60,50]);
|
||||
function altaz_to_xyz(alt,az=undef,r=undef) = let(
|
||||
|
@ -429,7 +432,7 @@ function altaz_to_xyz(alt,az=undef,r=undef) = let(
|
|||
// x = X coordinate.
|
||||
// y = Y coordinate.
|
||||
// z = Z coordinate.
|
||||
// Examples:
|
||||
// Example:
|
||||
// aa = xyz_to_altaz(20,30,40);
|
||||
// aa = xyz_to_altaz([40,50,70]);
|
||||
function xyz_to_altaz(x,y=undef,z=undef) = let(
|
||||
|
|
76
gears.scad
76
gears.scad
|
@ -579,12 +579,12 @@ function rack2d(
|
|||
xd = d * sin(pressure_angle),
|
||||
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("dedendum", [ 0,-d,0], BACK),
|
||||
anchorpt("dedendum-left", [-l/2,-d,0], LEFT),
|
||||
anchorpt("dedendum-right", [ l/2,-d,0], RIGHT),
|
||||
named_anchor("adendum", [ 0, a,0], BACK),
|
||||
named_anchor("adendum-left", [-l/2, a,0], LEFT),
|
||||
named_anchor("adendum-right", [ l/2, a,0], RIGHT),
|
||||
named_anchor("dedendum", [ 0,-d,0], BACK),
|
||||
named_anchor("dedendum-left", [-l/2,-d,0], LEFT),
|
||||
named_anchor("dedendum-right", [ l/2,-d,0], RIGHT),
|
||||
],
|
||||
path = [
|
||||
[-(teeth-1)/2 * pitch + -1/2 * pitch, a-height],
|
||||
|
@ -619,12 +619,12 @@ module rack2d(
|
|||
d = dedendum(pitch, clearance);
|
||||
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("dedendum", [ 0,-d,0], BACK),
|
||||
anchorpt("dedendum-left", [-l/2,-d,0], LEFT),
|
||||
anchorpt("dedendum-right", [ l/2,-d,0], RIGHT),
|
||||
named_anchor("adendum", [ 0, a,0], BACK),
|
||||
named_anchor("adendum-left", [-l/2, a,0], LEFT),
|
||||
named_anchor("adendum-right", [ l/2, a,0], RIGHT),
|
||||
named_anchor("dedendum", [ 0,-d,0], BACK),
|
||||
named_anchor("dedendum-left", [-l/2,-d,0], LEFT),
|
||||
named_anchor("dedendum-right", [ l/2,-d,0], RIGHT),
|
||||
];
|
||||
path = rack2d(
|
||||
pitch = pitch,
|
||||
|
@ -994,9 +994,9 @@ function bevel_gear(
|
|||
lvnf = left_handed? vnf1 : xflip(p=vnf1),
|
||||
vnf = down(cpz, p=lvnf),
|
||||
anchors = [
|
||||
anchorpt("pitchbase", [0,0,pitchoff-thickness/2]),
|
||||
anchorpt("flattop", [0,0,thickness/2]),
|
||||
anchorpt("apex", [0,0,hyp_ang_to_opp(ocone_rad,90-pitch_angle)+pitchoff-thickness/2])
|
||||
named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
|
||||
named_anchor("flattop", [0,0,thickness/2]),
|
||||
named_anchor("apex", [0,0,hyp_ang_to_opp(ocone_rad,90-pitch_angle)+pitchoff-thickness/2])
|
||||
]
|
||||
) reorient(anchor,spin,orient, vnf=vnf, extent=true, anchors=anchors, p=vnf);
|
||||
|
||||
|
@ -1048,9 +1048,9 @@ module bevel_gear(
|
|||
axis_zs = [for (p=vnf[0]) if(norm(point2d(p)) < EPSILON) p.z];
|
||||
thickness = max(axis_zs) - min(axis_zs);
|
||||
anchors = [
|
||||
anchorpt("pitchbase", [0,0,pitchoff-thickness/2]),
|
||||
anchorpt("flattop", [0,0,thickness/2]),
|
||||
anchorpt("apex", [0,0,adj_ang_to_opp(pr,90-pitch_angle)+pitchoff-thickness/2])
|
||||
named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
|
||||
named_anchor("flattop", [0,0,thickness/2]),
|
||||
named_anchor("apex", [0,0,adj_ang_to_opp(pr,90-pitch_angle)+pitchoff-thickness/2])
|
||||
];
|
||||
attachable(anchor,spin,orient, r1=pr, r2=ipr, h=thickness, anchors=anchors) {
|
||||
difference() {
|
||||
|
@ -1137,16 +1137,16 @@ module rack(
|
|||
d = dedendum(pitch, clearance);
|
||||
l = teeth * pitch;
|
||||
anchors = [
|
||||
anchorpt("adendum", [0,0,a], BACK),
|
||||
anchorpt("adendum-left", [-l/2,0,a], LEFT),
|
||||
anchorpt("adendum-right", [ l/2,0,a], RIGHT),
|
||||
anchorpt("adendum-front", [0,-thickness/2,a], DOWN),
|
||||
anchorpt("adendum-back", [0, thickness/2,a], UP),
|
||||
anchorpt("dedendum", [0,0,-d], BACK),
|
||||
anchorpt("dedendum-left", [-l/2,0,-d], LEFT),
|
||||
anchorpt("dedendum-right", [ l/2,0,-d], RIGHT),
|
||||
anchorpt("dedendum-front", [0,-thickness/2,-d], DOWN),
|
||||
anchorpt("dedendum-back", [0, thickness/2,-d], UP),
|
||||
named_anchor("adendum", [0,0,a], BACK),
|
||||
named_anchor("adendum-left", [-l/2,0,a], LEFT),
|
||||
named_anchor("adendum-right", [ l/2,0,a], RIGHT),
|
||||
named_anchor("adendum-front", [0,-thickness/2,a], DOWN),
|
||||
named_anchor("adendum-back", [0, thickness/2,a], UP),
|
||||
named_anchor("dedendum", [0,0,-d], BACK),
|
||||
named_anchor("dedendum-left", [-l/2,0,-d], LEFT),
|
||||
named_anchor("dedendum-right", [ l/2,0,-d], RIGHT),
|
||||
named_anchor("dedendum-front", [0,-thickness/2,-d], DOWN),
|
||||
named_anchor("dedendum-back", [0, thickness/2,-d], UP),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[l, thickness, 2*abs(a-height)], anchors=anchors) {
|
||||
skew(sxy=tan(helical)) xrot(90) {
|
||||
|
@ -1186,16 +1186,16 @@ function rack(
|
|||
d = dedendum(pitch, clearance),
|
||||
l = teeth * pitch,
|
||||
anchors = [
|
||||
anchorpt("adendum", [0,0,a], BACK),
|
||||
anchorpt("adendum-left", [-l/2,0,a], LEFT),
|
||||
anchorpt("adendum-right", [ l/2,0,a], RIGHT),
|
||||
anchorpt("adendum-front", [0,-thickness/2,a], DOWN),
|
||||
anchorpt("adendum-back", [0, thickness/2,a], UP),
|
||||
anchorpt("dedendum", [0,0,-d], BACK),
|
||||
anchorpt("dedendum-left", [-l/2,0,-d], LEFT),
|
||||
anchorpt("dedendum-right", [ l/2,0,-d], RIGHT),
|
||||
anchorpt("dedendum-front", [0,-thickness/2,-d], DOWN),
|
||||
anchorpt("dedendum-back", [0, thickness/2,-d], UP),
|
||||
named_anchor("adendum", [0,0,a], BACK),
|
||||
named_anchor("adendum-left", [-l/2,0,a], LEFT),
|
||||
named_anchor("adendum-right", [ l/2,0,a], RIGHT),
|
||||
named_anchor("adendum-front", [0,-thickness/2,a], DOWN),
|
||||
named_anchor("adendum-back", [0, thickness/2,a], UP),
|
||||
named_anchor("dedendum", [0,0,-d], BACK),
|
||||
named_anchor("dedendum-left", [-l/2,0,-d], LEFT),
|
||||
named_anchor("dedendum-right", [ l/2,0,-d], RIGHT),
|
||||
named_anchor("dedendum-front", [0,-thickness/2,-d], DOWN),
|
||||
named_anchor("dedendum-back", [0, thickness/2,-d], UP),
|
||||
],
|
||||
path = rack2d(
|
||||
pitch = pitch,
|
||||
|
|
|
@ -943,10 +943,10 @@ function are_points_on_plane(points, plane, eps=EPSILON) =
|
|||
_pointlist_greatest_distance(points,plane) < eps;
|
||||
|
||||
|
||||
// Function: is_above_plane()
|
||||
/// Internal Function: is_point_above_plane()
|
||||
// Usage:
|
||||
// test = in_front_of_plane(plane, point);
|
||||
// Topics: Geometry, Planes
|
||||
// test = _is_point_above_plane(plane, point);
|
||||
/// Topics: Geometry, Planes
|
||||
// Description:
|
||||
// Given a plane as [A,B,C,D] where the cartesian equation for that plane
|
||||
// is Ax+By+Cz=D, determines if the given 3D point is on the side of that
|
||||
|
@ -955,7 +955,7 @@ function are_points_on_plane(points, plane, eps=EPSILON) =
|
|||
// Arguments:
|
||||
// plane = The [A,B,C,D] coefficients for the first plane equation `Ax+By+Cz=D`.
|
||||
// point = The 3D point to test.
|
||||
function is_above_plane(plane, point) =
|
||||
function _is_point_above_plane(plane, point) =
|
||||
point_plane_distance(plane, point) > EPSILON;
|
||||
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ function hull3d_faces(points) =
|
|||
remaining = [for (i = [0:1:len(points)-1]) if (i!=a && i!=b && i!=c && i!=d) i],
|
||||
// Build an initial tetrahedron.
|
||||
// Swap b, c if d is in front of triangle t.
|
||||
ifop = is_above_plane(plane, points[d]),
|
||||
ifop = _is_point_above_plane(plane, points[d]),
|
||||
bc = ifop? [c,b] : [b,c],
|
||||
b = bc[0],
|
||||
c = bc[1],
|
||||
|
|
|
@ -86,9 +86,9 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw
|
|||
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)
|
||||
named_anchor("axis", [0,0,-tab/2/2]),
|
||||
named_anchor("screw", [0,2-ogap/2,tabh-tab/2/2],FWD),
|
||||
named_anchor("nut", [0,ogap/2-2,tabh-tab/2/2],FWD)
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[l, od, h], anchors=anchors) {
|
||||
down(tab/2/2)
|
||||
|
|
14
math.scad
14
math.scad
|
@ -35,7 +35,7 @@ NAN = acos(2);
|
|||
// If given a number, returns the square of that number,
|
||||
// If given a vector, returns the sum-of-squares/dot product of the vector elements.
|
||||
// If given a matrix, returns the matrix multiplication of the matrix with itself.
|
||||
// Examples:
|
||||
// Example:
|
||||
// sqr(3); // Returns: 9
|
||||
// sqr(-4); // Returns: 16
|
||||
// sqr([2,3,4]); // Returns: 29
|
||||
|
@ -50,7 +50,7 @@ function sqr(x) =
|
|||
// foo = log2(x);
|
||||
// Description:
|
||||
// Returns the logarithm base 2 of the value given.
|
||||
// Examples:
|
||||
// Example:
|
||||
// log2(0.125); // Returns: -3
|
||||
// log2(16); // Returns: 4
|
||||
// log2(256); // Returns: 8
|
||||
|
@ -187,7 +187,7 @@ function lerp(a,b,u) =
|
|||
// b = Second value or vector.
|
||||
// n = The number of values to return.
|
||||
// endpoint = If true, the last value will be exactly `b`. If false, the last value will be one step less.
|
||||
// Examples:
|
||||
// Example:
|
||||
// l = lerpn(-4,4,9); // Returns: [-4,-3,-2,-1,0,1,2,3,4]
|
||||
// l = lerpn(-4,4,8,false); // Returns: [-4,-3,-2,-1,0,1,2,3]
|
||||
// l = lerpn(0,1,6); // Returns: [0, 0.2, 0.4, 0.6, 0.8, 1]
|
||||
|
@ -350,7 +350,7 @@ function quant(x,y) =
|
|||
// Arguments:
|
||||
// x = The value to quantize.
|
||||
// y = The non-zero integer quantum of the quantization.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = quantdn(12,4); // Returns: 12
|
||||
// b = quantdn(13,4); // Returns: 12
|
||||
// c = quantdn(13.1,4); // Returns: 12
|
||||
|
@ -387,7 +387,7 @@ function quantdn(x,y) =
|
|||
// Arguments:
|
||||
// x = The value to quantize.
|
||||
// y = The non-zero integer quantum of the quantization.
|
||||
// Examples:
|
||||
// Example:
|
||||
// a = quantup(12,4); // Returns: 12
|
||||
// b = quantup(13,4); // Returns: 16
|
||||
// c = quantup(13.1,4); // Returns: 16
|
||||
|
@ -639,7 +639,7 @@ function _cumsum(v,_i=0,_acc=[]) =
|
|||
// Arguments:
|
||||
// a = Angle to get the value for.
|
||||
// sines = List of [amplitude, frequency, offset] items, where the frequency is the number of times the cycle repeats around the circle.
|
||||
// Examples:
|
||||
// Example:
|
||||
// v = sum_of_sines(30, [[10,3,0], [5,5.5,60]]);
|
||||
function sum_of_sines(a, sines) =
|
||||
assert( is_finite(a) && is_matrix(sines,undef,3), "Invalid input.")
|
||||
|
@ -1225,7 +1225,7 @@ function all_equal(vec,eps=0) =
|
|||
// true if every item of the list is an integer. Otherwise, returns false.
|
||||
// Arguments:
|
||||
// x = The value to check.
|
||||
// Examples:
|
||||
// Example:
|
||||
// b = all_integer(true); // Returns: false
|
||||
// b = all_integer("foo"); // Returns: false
|
||||
// b = all_integer(4); // Returns: true
|
||||
|
|
|
@ -395,8 +395,8 @@ module generic_screw(
|
|||
) {
|
||||
sides = max(12, segs(screwsize/2));
|
||||
anchors = [
|
||||
anchorpt("countersunk", [0,0,(headlen+screwlen)/2-0.01]),
|
||||
anchorpt("base", [0,0,-headlen/2+screwlen/2])
|
||||
named_anchor("countersunk", [0,0,(headlen+screwlen)/2-0.01]),
|
||||
named_anchor("base", [0,0,-headlen/2+screwlen/2])
|
||||
];
|
||||
attachable(anchor,spin,orient, d=screwsize, l=headlen+screwlen, anchors=anchors) {
|
||||
down(headlen/2-screwlen/2) {
|
||||
|
@ -517,9 +517,9 @@ module metric_bolt(
|
|||
);
|
||||
|
||||
anchors = [
|
||||
anchorpt("countersunk", [0,0,base+sunklen]),
|
||||
anchorpt("base", [0,0,base]),
|
||||
anchorpt("shank", [0,0,base-shank])
|
||||
named_anchor("countersunk", [0,0,base+sunklen]),
|
||||
named_anchor("base", [0,0,base]),
|
||||
named_anchor("shank", [0,0,base-shank])
|
||||
];
|
||||
|
||||
//color("silver")
|
||||
|
|
|
@ -122,14 +122,14 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
|
|||
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]),
|
||||
named_anchor("shaft-top", [0,0,h/2+shaft_len]),
|
||||
named_anchor("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
|
||||
named_anchor("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
|
||||
named_anchor("plinth-top", [0,0,h/2+plinth_height]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
named_anchor("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
|
||||
up(h/2)
|
||||
|
@ -187,14 +187,14 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, anchor=TOP, spin=0, orient=UP
|
|||
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]),
|
||||
named_anchor("shaft-top", [0,0,h/2+shaft_len]),
|
||||
named_anchor("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
|
||||
named_anchor("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
|
||||
named_anchor("plinth-top", [0,0,h/2+plinth_height]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
named_anchor("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
|
||||
up(h/2)
|
||||
|
@ -252,14 +252,14 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
|
|||
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]),
|
||||
named_anchor("shaft-top", [0,0,h/2+shaft_len]),
|
||||
named_anchor("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
|
||||
named_anchor("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
|
||||
named_anchor("plinth-top", [0,0,h/2+plinth_height]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
named_anchor("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
|
||||
up(h/2)
|
||||
|
@ -337,14 +337,14 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, anchor=TOP, spin=0, orient
|
|||
|
||||
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]),
|
||||
named_anchor("shaft-top", [0,0,h/2+shaft_len]),
|
||||
named_anchor("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
|
||||
named_anchor("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
|
||||
named_anchor("plinth-top", [0,0,h/2+plinth_height]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
named_anchor("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
|
||||
up(h/2)
|
||||
|
@ -404,14 +404,14 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, anchor=TOP, spin=0, orient
|
|||
|
||||
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]),
|
||||
named_anchor("shaft-top", [0,0,h/2+shaft_len]),
|
||||
named_anchor("shaft-middle", [0,0,h/2+plinth_height+(shaft_len-plinth_height)/2]),
|
||||
named_anchor("shaft-bottom", [0,0,h/2+plinth_height+0.1]),
|
||||
named_anchor("plinth-top", [0,0,h/2+plinth_height]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, h/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
named_anchor("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]),
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[motor_width, motor_width, h], anchors=anchors) {
|
||||
up(h/2)
|
||||
|
@ -472,10 +472,10 @@ module nema_mount_holes(size=17, depth=5, l=5, anchor=CENTER, spin=0, orient=UP)
|
|||
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]),
|
||||
named_anchor("screw1", [+screw_spacing/2, +screw_spacing/2, depth/2]),
|
||||
named_anchor("screw2", [-screw_spacing/2, +screw_spacing/2, depth/2]),
|
||||
named_anchor("screw3", [-screw_spacing/2, -screw_spacing/2, depth/2]),
|
||||
named_anchor("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);
|
||||
|
|
|
@ -106,6 +106,8 @@ module partition_mask(l=100, w=100, h=100, cutsize=10, cutpath="jigsaw", gap=0,
|
|||
// partition_cut_mask(l, w, h, [cutsize], [cutpath], [gap], [inverse], [spin], [orient]);
|
||||
// Description:
|
||||
// Creates a mask that you can use to difference with an object to cut it into two sub-parts that can be assembled.
|
||||
// The `$slop` value is important to get the proper fit and should probably be smaller than 0.2. The examples below
|
||||
// use larger values to make the mask easier to see.
|
||||
// Arguments:
|
||||
// l = The length of the cut axis.
|
||||
// w = The width of the part to be masked, back from the cut plane.
|
||||
|
@ -115,20 +117,20 @@ module partition_mask(l=100, w=100, h=100, cutsize=10, cutpath="jigsaw", gap=0,
|
|||
// gap = Empty gaps between cutpath iterations. Default: 0
|
||||
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// $slop = The width of the cut mask, to correct for printer-specific fitting. Min: 0.1.
|
||||
// $slop = The width of the cut mask, to correct for printer-specific fitting. Min: 0.05.
|
||||
// Examples:
|
||||
// partition_cut_mask(gap=0, cutpath="dovetail");
|
||||
// partition_cut_mask(gap=30, cutpath="dovetail");
|
||||
// partition_cut_mask(gap=30, cutsize=15, cutpath="dovetail");
|
||||
// partition_cut_mask(gap=30, cutsize=[20,20], cutpath="dovetail");
|
||||
// Examples(2DMed):
|
||||
// partition_cut_mask(cutpath="sawtooth");
|
||||
// partition_cut_mask(cutpath="sinewave");
|
||||
// partition_cut_mask(cutpath="comb");
|
||||
// partition_cut_mask(cutpath="finger");
|
||||
// partition_cut_mask(cutpath="dovetail");
|
||||
// partition_cut_mask(cutpath="hammerhead");
|
||||
// partition_cut_mask(cutpath="jigsaw");
|
||||
// partition_cut_mask(cutpath="sawtooth",$slop=0.5);
|
||||
// partition_cut_mask(cutpath="sinewave",$slop=0.5);
|
||||
// partition_cut_mask(cutpath="comb",$slop=0.5);
|
||||
// partition_cut_mask(cutpath="finger",$slop=0.5);
|
||||
// partition_cut_mask(cutpath="dovetail",$slop=1);
|
||||
// partition_cut_mask(cutpath="hammerhead",$slop=1);
|
||||
// partition_cut_mask(cutpath="jigsaw",$slop=0.5);
|
||||
module partition_cut_mask(l=100, h=100, cutsize=10, cutpath="jigsaw", gap=0, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
cutsize = is_vector(cutsize)? cutsize : [cutsize*2, cutsize];
|
||||
|
|
208
paths.scad
208
paths.scad
|
@ -17,22 +17,22 @@
|
|||
// All vectors must of the same size, and may only contain numbers that are not inf or nan.
|
||||
// By default the vectors in a path must be 2d or 3d. Set the `dim` parameter to specify a list
|
||||
// of allowed dimensions, or set it to `undef` to allow any dimension.
|
||||
// Examples:
|
||||
// is_path([[3,4],[5,6]]); // Returns true
|
||||
// is_path([[3,4]]); // Returns false
|
||||
// is_path([[3,4],[4,5]],2); // Returns true
|
||||
// is_path([[3,4,3],[5,4,5]],2); // Returns false
|
||||
// is_path([[3,4,3],[5,4,5]],2); // Returns false
|
||||
// is_path([[3,4,5],undef,[4,5,6]]); // Returns false
|
||||
// is_path([[3,5],[undef,undef],[4,5]]); // Returns false
|
||||
// is_path([[3,4],[5,6],[5,3]]); // Returns true
|
||||
// is_path([3,4,5,6,7,8]); // Returns false
|
||||
// is_path([[3,4],[5,6]], dim=[2,3]);// Returns true
|
||||
// is_path([[3,4],[5,6]], dim=[1,3]);// Returns false
|
||||
// is_path([[3,4],"hello"], fast=true); // Returns true
|
||||
// is_path([[3,4],[3,4,5]]); // Returns false
|
||||
// is_path([[1,2,3,4],[2,3,4,5]]); // Returns false
|
||||
// is_path([[1,2,3,4],[2,3,4,5]],undef);// Returns true
|
||||
// Example:
|
||||
// bool1 = is_path([[3,4],[5,6]]); // Returns true
|
||||
// bool2 = is_path([[3,4]]); // Returns false
|
||||
// bool3 = is_path([[3,4],[4,5]],2); // Returns true
|
||||
// bool4 = is_path([[3,4,3],[5,4,5]],2); // Returns false
|
||||
// bool5 = is_path([[3,4,3],[5,4,5]],2); // Returns false
|
||||
// bool6 = is_path([[3,4,5],undef,[4,5,6]]); // Returns false
|
||||
// bool7 = is_path([[3,5],[undef,undef],[4,5]]); // Returns false
|
||||
// bool8 = is_path([[3,4],[5,6],[5,3]]); // Returns true
|
||||
// bool9 = is_path([3,4,5,6,7,8]); // Returns false
|
||||
// bool10 = is_path([[3,4],[5,6]], dim=[2,3]);// Returns true
|
||||
// bool11 = is_path([[3,4],[5,6]], dim=[1,3]);// Returns false
|
||||
// bool12 = is_path([[3,4],"hello"], fast=true); // Returns true
|
||||
// bool13 = is_path([[3,4],[3,4,5]]); // Returns false
|
||||
// bool14 = is_path([[1,2,3,4],[2,3,4,5]]); // Returns false
|
||||
// bool15 = is_path([[1,2,3,4],[2,3,4,5]],undef);// Returns true
|
||||
// Arguments:
|
||||
// list = list to check
|
||||
// dim = list of allowed dimensions of the vectors in the path. Default: [2,3]
|
||||
|
@ -1399,182 +1399,6 @@ module path_extrude(path, convexity=10, clipsize=100) {
|
|||
}
|
||||
|
||||
|
||||
function _cut_interp(pathcut, path, data) =
|
||||
[for(entry=pathcut)
|
||||
let(
|
||||
a = path[entry[1]-1],
|
||||
b = path[entry[1]],
|
||||
c = entry[0],
|
||||
i = max_index(v_abs(b-a)),
|
||||
factor = (c[i]-a[i])/(b[i]-a[i])
|
||||
)
|
||||
(1-factor)*data[entry[1]-1]+ factor * data[entry[1]]
|
||||
];
|
||||
|
||||
|
||||
// Module: path_text()
|
||||
// Usage:
|
||||
// path_text(path, text, [size], [thickness], [font], [lettersize], [offset], [reverse], [normal], [top], [textmetrics])
|
||||
// Description:
|
||||
// Place the text letter by letter onto the specified path using textmetrics (if available and requested)
|
||||
// or user specified letter spacing. The path can be 2D or 3D. In 2D the text appears along the path with letters upright
|
||||
// as determined by the path direction. In 3D by default letters are positioned on the tangent line to the path with the path normal
|
||||
// pointing toward the reader. The path normal points away from the center of curvature (the opposite of the normal produced
|
||||
// by path_normals()). Note that this means that if the center of curvature switches sides the text will flip upside down.
|
||||
// If you want text on such a path you must supply your own normal or top vector.
|
||||
// .
|
||||
// Text appears starting at the beginning of the path, so if the 3D path moves right to left
|
||||
// then a left-to-right reading language will display in the wrong order. (For a 2D path text will appear upside down.)
|
||||
// The text for a 3D path appears positioned to be read from "outside" of the curve (from a point on the other side of the
|
||||
// curve from the center of curvature). If you need the text to read properly from the inside, you can set reverse to
|
||||
// true to flip the text, or supply your own normal.
|
||||
// .
|
||||
// If you do not have the experimental textmetrics feature enabled then you must specify the space for the letters
|
||||
// using lettersize, which can be a scalar or array. You will have the easiest time getting good results by using
|
||||
// a monospace font such as Courier. Note that even with text metrics, spacing may be different because path_text()
|
||||
// doesn't do kerning to adjust positions of individual glyphs. Also if your font has ligatures they won't be used.
|
||||
// .
|
||||
// By default letters appear centered on the path. The offset can be specified to shift letters toward the reader (in
|
||||
// the direction of the normal).
|
||||
// .
|
||||
// You can specify your own normal by setting `normal` to a direction or a list of directions. Your normal vector should
|
||||
// point toward the reader. You can also specify
|
||||
// top, which directs the top of the letters in a desired direction. If you specify your own directions and they
|
||||
// are not perpendicular to the path then the direction you specify will take priority and the
|
||||
// letters will not rest on the tangent line of the path. Note that the normal or top directions that you
|
||||
// specify must not be parallel to the path.
|
||||
// Arguments:
|
||||
// path = path to place the text on
|
||||
// text = text to create
|
||||
// size = font size
|
||||
// thickness = thickness of letters (not allowed for 2D path)
|
||||
// font = font to use
|
||||
// ---
|
||||
// lettersize = scalar or array giving size of letters
|
||||
// offset = distance to shift letters "up" (towards the reader). Not allowed for 2D path. Default: 0
|
||||
// normal = direction or list of directions pointing towards the reader of the text. Not allowed for 2D path.
|
||||
// top = direction or list of directions pointing toward the top of the text
|
||||
// reverse = reverse the letters if true. Not allowed for 2D path. Default: false
|
||||
// textmetrics = if set to true and lettersize is not given then use the experimental textmetrics feature. You must be running a dev snapshot that includes this feature and have the feature turned on in your preferences. Default: false
|
||||
// Example: The examples use Courier, a monospaced font. The width is 1/1.2 times the specified size for this font. This text could wrap around a cylinder.
|
||||
// path = path3d(arc(100, r=25, angle=[245, 370]));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2);
|
||||
// Example: By setting the normal to UP we can get text that lies flat, for writing around the edge of a disk:
|
||||
// path = path3d(arc(100, r=25, angle=[245, 370]));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, normal=UP);
|
||||
// Example: If we want text that reads from the other side we can use reverse. Note we have to reverse the direction of the path and also set the reverse option.
|
||||
// path = reverse(path3d(arc(100, r=25, angle=[65, 190])));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, reverse=true);
|
||||
// Example: text debossed onto a cylinder in a spiral. The text is 1 unit deep because it is half in, half out.
|
||||
// text = ("A long text example to wrap around a cylinder, possibly for a few times.");
|
||||
// L = 5*len(text);
|
||||
// maxang = 360*L/(PI*50);
|
||||
// spiral = [for(a=[0:1:maxang]) [25*cos(a), 25*sin(a), 10-30/maxang*a]];
|
||||
// difference(){
|
||||
// cyl(d=50, l=50, $fn=120);
|
||||
// path_text(spiral, text, size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// }
|
||||
// Example: Same example but text embossed. Make sure you have enough depth for the letters to fully overlap the object.
|
||||
// text = ("A long text example to wrap around a cylinder, possibly for a few times.");
|
||||
// L = 5*len(text);
|
||||
// maxang = 360*L/(PI*50);
|
||||
// spiral = [for(a=[0:1:maxang]) [25*cos(a), 25*sin(a), 10-30/maxang*a]];
|
||||
// cyl(d=50, l=50, $fn=120);
|
||||
// path_text(spiral, text, size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// Example: Here the text baseline sits on the path. (Note the default orientation makes text readable from below, so we specify the normal.)
|
||||
// path = arc(100, points = [[-20, 0, 20], [0,0,5], [20,0,20]]);
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "Example Text", size=5, lettersize=5/1.2, font="Courier", normal=FRONT);
|
||||
// Example: If we use top to orient the text upward, the text baseline is no longer aligned with the path.
|
||||
// path = arc(100, points = [[-20, 0, 20], [0,0,5], [20,0,20]]);
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "Example Text", size=5, lettersize=5/1.2, font="Courier", top=UP);
|
||||
// Example: This sine wave wrapped around the cylinder has a twisting normal that produces wild letter layout. We fix it with a custom normal which is different at every path point.
|
||||
// path = [for(theta = [0:360]) [25*cos(theta), 25*sin(theta), 4*cos(theta*4)]];
|
||||
// normal = [for(theta = [0:360]) [cos(theta), sin(theta),0]];
|
||||
// zrot(-120)
|
||||
// difference(){
|
||||
// cyl(r=25, h=20, $fn=120);
|
||||
// path_text(path, "A sine wave wiggles", font="Courier", lettersize=5/1.2, size=5, normal=normal);
|
||||
// }
|
||||
// Example: The path center of curvature changes, and the text flips.
|
||||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// Example: We can fix it with top:
|
||||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier", thickness=2, top=UP);
|
||||
// Example(2D): With a 2D path instead of 3D there's no ambiguity about direction and it works by default:
|
||||
// path = zrot(-120,p=concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180]))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier");
|
||||
module path_text(path, text, font, size, thickness, lettersize, offset=0, reverse=false, normal, top, textmetrics=false)
|
||||
{
|
||||
dummy2=assert(is_path(path,[2,3]),"Must supply a 2d or 3d path")
|
||||
assert(num_defined([normal,top])<=1, "Cannot define both \"normal\" and \"top\"");
|
||||
dim = len(path[0]);
|
||||
normalok = is_undef(normal) || is_vector(normal,3) || (is_path(normal,3) && len(normal)==len(path));
|
||||
topok = is_undef(top) || is_vector(top,dim) || (dim==2 && is_vector(top,3) && top[2]==0)
|
||||
|| (is_path(top,dim) && len(top)==len(path));
|
||||
dummy4 = assert(dim==3 || is_undef(thickness), "Cannot give a thickness with 2d path")
|
||||
assert(dim==3 || !reverse, "Reverse not allowed with 2d path")
|
||||
assert(dim==3 || offset==0, "Cannot give offset with 2d path")
|
||||
assert(dim==3 || is_undef(normal), "Cannot define \"normal\" for a 2d path, only \"top\"")
|
||||
assert(normalok,"\"normal\" must be a vector or path compatible with the given path")
|
||||
assert(topok,"\"top\" must be a vector or path compatible with the given path");
|
||||
thickness = first_defined([thickness,1]);
|
||||
normal = is_vector(normal) ? repeat(normal, len(path))
|
||||
: is_def(normal) ? normal
|
||||
: undef;
|
||||
|
||||
top = is_vector(top) ? repeat(dim==2?point2d(top):top, len(path))
|
||||
: is_def(top) ? top
|
||||
: undef;
|
||||
|
||||
lsize = is_def(lettersize) ? force_list(lettersize, len(text))
|
||||
: textmetrics ? [for(letter=text) let(t=textmetrics(letter, font=font, size=size)) t.advance[0]]
|
||||
: assert(false, "textmetrics disabled: Must specify letter size");
|
||||
|
||||
dummy1 = assert(sum(lsize)<=path_length(path),"Path is too short for the text");
|
||||
|
||||
pts = path_cut_points(path, add_scalar([0, each cumsum(lsize)],lsize[0]/2), direction=true);
|
||||
|
||||
usernorm = is_def(normal);
|
||||
usetop = is_def(top);
|
||||
|
||||
normpts = is_undef(normal) ? (reverse?1:-1)*subindex(pts,3) : _cut_interp(pts,path, normal);
|
||||
toppts = is_undef(top) ? undef : _cut_interp(pts,path,top);
|
||||
for(i=idx(text))
|
||||
let( tangent = pts[i][2] )
|
||||
assert(!usetop || !approx(tangent*toppts[i],norm(top[i])*norm(tangent)),
|
||||
str("Specified top direction parallel to path at character ",i))
|
||||
assert(usetop || !approx(tangent*normpts[i],norm(normpts[i])*norm(tangent)),
|
||||
str("Specified normal direction parallel to path at character ",i))
|
||||
let(
|
||||
adjustment = usetop ? (tangent*toppts[i])*toppts[i]/(toppts[i]*toppts[i])
|
||||
: usernorm ? (tangent*normpts[i])*normpts[i]/(normpts[i]*normpts[i])
|
||||
: [0,0,0]
|
||||
)
|
||||
move(pts[i][0])
|
||||
if(dim==3){
|
||||
frame_map(x=tangent-adjustment,
|
||||
z=usetop ? undef : normpts[i],
|
||||
y=usetop ? toppts[i] : undef)
|
||||
up(offset-thickness/2)
|
||||
linear_extrude(height=thickness)
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
} else {
|
||||
frame_map(x=point3d(tangent-adjustment), y=point3d(usetop ? toppts[i] : -normpts[i]))
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
307
primitives.scad
307
primitives.scad
|
@ -1,307 +0,0 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: primitives.scad
|
||||
// The basic built-in shapes, reworked to integrate better with
|
||||
// other BOSL2 library shapes and utilities.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: 2D Primitives
|
||||
|
||||
|
||||
// Function&Module: square()
|
||||
// Topics: Shapes (2D), Path Generators (2D)
|
||||
// Usage: As a Built-in Module
|
||||
// square(size, [center]);
|
||||
// Usage: As a Function
|
||||
// path = square(size, [center]);
|
||||
// See Also: rect()
|
||||
// Description:
|
||||
// When called as the builtin module, creates a 2D square or rectangle of the given size.
|
||||
// When called as a function, returns a 2D path/list of points for a square/rectangle of the given size.
|
||||
// Arguments:
|
||||
// size = The size of the square to create. If given as a scalar, both X and Y will be the same size.
|
||||
// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`.
|
||||
// ---
|
||||
// anchor = (Function only) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// Example(2D):
|
||||
// square(40);
|
||||
// Example(2D): Centered
|
||||
// square([40,30], center=true);
|
||||
// Example(2D): Called as Function
|
||||
// path = square([40,30], anchor=FRONT, spin=30);
|
||||
// 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);
|
||||
|
||||
|
||||
// Function&Module: circle()
|
||||
// Topics: Shapes (2D), Path Generators (2D)
|
||||
// Usage: As a Built-in Module
|
||||
// circle(r|d=, ...);
|
||||
// Usage: As a Function
|
||||
// path = circle(r|d=, ...);
|
||||
// See Also: oval()
|
||||
// Description:
|
||||
// When called as the builtin module, creates a 2D polygon that approximates a circle of the given size.
|
||||
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle of the given size.
|
||||
// Arguments:
|
||||
// r = The radius of the circle to create.
|
||||
// d = The diameter of the circle to create.
|
||||
// ---
|
||||
// anchor = (Function only) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// Example(2D): By Radius
|
||||
// circle(r=25);
|
||||
// Example(2D): By Diameter
|
||||
// circle(d=50);
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
// Section: Primitive 3D Shapes
|
||||
|
||||
|
||||
// Function&Module: cube()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// cube(size, [center], ...);
|
||||
// Usage: With Attachments
|
||||
// cube(size, [center], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// vnf = cube(size, [center], ...);
|
||||
// See Also: cuboid(), prismoid()
|
||||
// Description:
|
||||
// Creates a 3D cubic object with support for anchoring and attachments.
|
||||
// This can be used as a drop-in replacement for the built-in `cube()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a cube.
|
||||
// Arguments:
|
||||
// size = The size of the cube.
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=ALLNEG`.
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example: Simple cube.
|
||||
// cube(40);
|
||||
// Example: Rectangular cube.
|
||||
// cube([20,40,50]);
|
||||
// Example: Anchoring.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT);
|
||||
// Example: Spin.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT, spin=30);
|
||||
// Example: Orientation.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT, spin=30, orient=FWD);
|
||||
// Example: Standard Connectors.
|
||||
// cube(40, center=true) show_anchors();
|
||||
// Example: Called as Function
|
||||
// vnf = cube([20,40,50]);
|
||||
// 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) {
|
||||
if (size.z > 0) {
|
||||
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) v_mul(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()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// cylinder(h, r=/d=, [center=], ...);
|
||||
// cylinder(h, r1/d1=, r2/d2=, [center=], ...);
|
||||
// Usage: With Attachments
|
||||
// cylinder(h, r=/d=, [center=]) {attachments}
|
||||
// Usage: As Function
|
||||
// vnf = cylinder(h, r=/d=, [center=], ...);
|
||||
// vnf = cylinder(h, r1/d1=, r2/d2=, [center=], ...);
|
||||
// See Also: cyl()
|
||||
// Description:
|
||||
// Creates a 3D cylinder or conic object with support for anchoring and attachments.
|
||||
// This can be used as a drop-in replacement for the built-in `cylinder()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a cylinder.
|
||||
// Arguments:
|
||||
// l / h = The height of the cylinder.
|
||||
// r1 = The bottom radius of the cylinder. (Before orientation.)
|
||||
// r2 = The top radius of the cylinder. (Before orientation.)
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`.
|
||||
// ---
|
||||
// d1 = The bottom diameter of the cylinder. (Before orientation.)
|
||||
// d2 = The top diameter of the cylinder. (Before orientation.)
|
||||
// r = The radius of the cylinder.
|
||||
// d = The diameter of the cylinder.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example: By Radius
|
||||
// xdistribute(30) {
|
||||
// cylinder(h=40, r=10);
|
||||
// cylinder(h=40, r1=10, r2=5);
|
||||
// }
|
||||
// Example: By Diameter
|
||||
// xdistribute(30) {
|
||||
// cylinder(h=40, d=25);
|
||||
// cylinder(h=40, d1=25, d2=10);
|
||||
// }
|
||||
// Example(Med): Anchoring
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT);
|
||||
// Example(Med): Spin
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT, spin=45);
|
||||
// Example(Med): Orient
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT, spin=45, orient=FWD);
|
||||
// Example(Big): Standard Connectors
|
||||
// xdistribute(40) {
|
||||
// cylinder(h=30, d=25) show_anchors();
|
||||
// cylinder(h=30, d1=25, d2=10) show_anchors();
|
||||
// }
|
||||
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) {
|
||||
if (l > 0) {
|
||||
linear_extrude(height=l, center=true, convexity=2, scale=r2/r1) {
|
||||
circle(r=r1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zflip() {
|
||||
if (l > 0) {
|
||||
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];
|
||||
|
||||
|
||||
|
||||
// Function&Module: sphere()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// sphere(r|d=, [circum=], [style=], ...);
|
||||
// Usage: With Attachments
|
||||
// sphere(r|d=, ...) { attachments }
|
||||
// Usage: As Function
|
||||
// vnf = sphere(r|d=, [circum=], [style=], ...);
|
||||
// See Also: spheroid()
|
||||
// Description:
|
||||
// Creates a sphere object, with support for anchoring and attachments.
|
||||
// This is a drop-in replacement for the built-in `sphere()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a sphere.
|
||||
// Arguments:
|
||||
// r = Radius of the sphere.
|
||||
// ---
|
||||
// d = Diameter of the sphere.
|
||||
// circum = If true, the sphere is made large enough to circumscribe the sphere of the ideal side. Otherwise inscribes. Default: false (inscribes)
|
||||
// style = The style of the sphere's construction. One of "orig", "aligned", "stagger", "octa", or "icosa". Default: "orig"
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example: By Radius
|
||||
// sphere(r=50);
|
||||
// Example: By Diameter
|
||||
// sphere(d=100);
|
||||
// Example: style="orig"
|
||||
// sphere(d=100, style="orig", $fn=10);
|
||||
// Example: style="aligned"
|
||||
// sphere(d=100, style="aligned", $fn=10);
|
||||
// Example: style="stagger"
|
||||
// sphere(d=100, style="stagger", $fn=10);
|
||||
// Example: style="icosa"
|
||||
// sphere(d=100, style="icosa", $fn=10);
|
||||
// // In "icosa" style, $fn is quantized
|
||||
// // to the nearest multiple of 5.
|
||||
// Example: Anchoring
|
||||
// sphere(d=100, anchor=FRONT);
|
||||
// Example: Spin
|
||||
// sphere(d=100, anchor=FRONT, spin=45);
|
||||
// Example: Orientation
|
||||
// sphere(d=100, anchor=FRONT, spin=45, orient=FWD);
|
||||
// Example: Standard Connectors
|
||||
// sphere(d=50) show_anchors();
|
||||
// Example: Called as Function
|
||||
// vnf = sphere(d=100, style="icosa");
|
||||
// vnf_polyhedron(vnf);
|
||||
module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP)
|
||||
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient) children();
|
||||
|
||||
|
||||
function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) =
|
||||
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
100
shapes2d.scad
100
shapes2d.scad
|
@ -1,13 +1,15 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: shapes2d.scad
|
||||
// This file lets you create regular polygons
|
||||
// This file includes redefinitions of the core modules to
|
||||
// work with attachment. You can also create regular polygons
|
||||
// with optional rounded corners and alignment features not
|
||||
// available with circle(). The file also provides teardrop2d,
|
||||
// which is useful for 3d printable holes. Lastly you can use the
|
||||
// masks to produce edge treatments common in furniture from the
|
||||
// simple roundover or cove molding to the more elaborate ogee.
|
||||
// Many of the commands have module forms that produce geometry and
|
||||
// function forms that produce a path.
|
||||
// function forms that produce a path. This file defines function
|
||||
// forms of the core OpenSCAD modules that produce paths.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -15,6 +17,44 @@
|
|||
|
||||
// Section: 2D Primitives
|
||||
|
||||
// Function&Module: square()
|
||||
// Topics: Shapes (2D), Path Generators (2D)
|
||||
// Usage: As a Built-in Module
|
||||
// square(size, [center]);
|
||||
// Usage: As a Function
|
||||
// path = square(size, [center]);
|
||||
// See Also: rect()
|
||||
// Description:
|
||||
// When called as the builtin module, creates a 2D square or rectangle of the given size.
|
||||
// When called as a function, returns a 2D path/list of points for a square/rectangle of the given size.
|
||||
// Arguments:
|
||||
// size = The size of the square to create. If given as a scalar, both X and Y will be the same size.
|
||||
// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`.
|
||||
// ---
|
||||
// anchor = (Function only) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// Example(2D):
|
||||
// square(40);
|
||||
// Example(2D): Centered
|
||||
// square([40,30], center=true);
|
||||
// Example(2D): Called as Function
|
||||
// path = square([40,30], anchor=FRONT, spin=30);
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
// Function&Module: rect()
|
||||
// Usage: As Module
|
||||
// rect(size, [center], [rounding], [chamfer], ...);
|
||||
|
@ -119,6 +159,38 @@ function rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
|
|||
reorient(anchor,spin, two_d=true, size=size, p=path);
|
||||
|
||||
|
||||
// Function&Module: circle()
|
||||
// Topics: Shapes (2D), Path Generators (2D)
|
||||
// Usage: As a Built-in Module
|
||||
// circle(r|d=, ...);
|
||||
// Usage: As a Function
|
||||
// path = circle(r|d=, ...);
|
||||
// See Also: oval()
|
||||
// Description:
|
||||
// When called as the builtin module, creates a 2D polygon that approximates a circle of the given size.
|
||||
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle of the given size.
|
||||
// Arguments:
|
||||
// r = The radius of the circle to create.
|
||||
// d = The diameter of the circle to create.
|
||||
// ---
|
||||
// anchor = (Function only) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// Example(2D): By Radius
|
||||
// circle(r=25);
|
||||
// Example(2D): By Diameter
|
||||
// circle(d=50);
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
|
||||
// Function&Module: oval()
|
||||
// Usage:
|
||||
// oval(r|d=, [realign=], [circum=])
|
||||
|
@ -279,8 +351,8 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
|
|||
tipp = apply(mat, polar_to_xy(r-inset+rounding,a1)),
|
||||
pos = (p1+p2)/2
|
||||
) each [
|
||||
anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0),
|
||||
anchorpt(str("side",i), pos, unit(pos,BACK), 0),
|
||||
named_anchor(str("tip",i), tipp, unit(tipp,BACK), 0),
|
||||
named_anchor(str("side",i), pos, unit(pos,BACK), 0),
|
||||
]
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path, anchors=anchors);
|
||||
|
@ -308,8 +380,8 @@ module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false,
|
|||
tipp = apply(mat, polar_to_xy(r-inset+rounding,a1)),
|
||||
pos = (p1+p2)/2
|
||||
) each [
|
||||
anchorpt(str("tip",i), tipp, unit(tipp,BACK), 0),
|
||||
anchorpt(str("side",i), pos, unit(pos,BACK), 0),
|
||||
named_anchor(str("tip",i), tipp, unit(tipp,BACK), 0),
|
||||
named_anchor(str("side",i), pos, unit(pos,BACK), 0),
|
||||
]
|
||||
];
|
||||
path = regular_ngon(n=n, r=r, rounding=rounding, _mat=mat, _anchs=anchors);
|
||||
|
@ -694,9 +766,9 @@ function star(n, r, ir, d, or, od, id, step, realign=false, align_tip, align_pit
|
|||
p3 = apply(mat, polar_to_xy(r,a3)),
|
||||
pos = (p1+p3)/2
|
||||
) each [
|
||||
anchorpt(str("tip",i), p1, unit(p1,BACK), 0),
|
||||
anchorpt(str("pit",i), p2, unit(p2,BACK), 0),
|
||||
anchorpt(str("midpt",i), pos, unit(pos,BACK), 0),
|
||||
named_anchor(str("tip",i), p1, unit(p1,BACK), 0),
|
||||
named_anchor(str("pit",i), p2, unit(p2,BACK), 0),
|
||||
named_anchor(str("midpt",i), pos, unit(pos,BACK), 0),
|
||||
]
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path, anchors=anchors);
|
||||
|
@ -724,9 +796,9 @@ module star(n, r, ir, d, or, od, id, step, realign=false, align_tip, align_pit,
|
|||
p3 = apply(mat, polar_to_xy(r,a3)),
|
||||
pos = (p1+p3)/2
|
||||
) each [
|
||||
anchorpt(str("tip",i), p1, unit(p1,BACK), 0),
|
||||
anchorpt(str("pit",i), p2, unit(p2,BACK), 0),
|
||||
anchorpt(str("midpt",i), pos, unit(pos,BACK), 0),
|
||||
named_anchor(str("tip",i), p1, unit(p1,BACK), 0),
|
||||
named_anchor(str("pit",i), p2, unit(p2,BACK), 0),
|
||||
named_anchor(str("midpt",i), pos, unit(pos,BACK), 0),
|
||||
]
|
||||
];
|
||||
path = star(n=n, r=r, ir=ir, realign=realign, _mat=mat, _anchs=anchors);
|
||||
|
@ -1007,7 +1079,7 @@ module reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) {
|
|||
for (i = [0:1:N-1]) let(
|
||||
ca = 360 - i * 360/N,
|
||||
cp = polar_to_xy(r, ca)
|
||||
) anchorpt(str("tip",i), cp, unit(cp,BACK), 0),
|
||||
) named_anchor(str("tip",i), cp, unit(cp,BACK), 0),
|
||||
];
|
||||
attachable(anchor,spin, two_d=true, path=path, anchors=anchors) {
|
||||
polygon(path);
|
||||
|
@ -1034,7 +1106,7 @@ function reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) =
|
|||
for (i = [0:1:N-1]) let(
|
||||
ca = 360 - i * 360/N,
|
||||
cp = polar_to_xy(r, ca)
|
||||
) anchorpt(str("tip",i), cp, unit(cp,BACK), 0),
|
||||
) named_anchor(str("tip",i), cp, unit(cp,BACK), 0),
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, anchors=anchors, p=path);
|
||||
|
||||
|
|
688
shapes3d.scad
688
shapes3d.scad
|
@ -6,7 +6,79 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: Cuboids
|
||||
// Section: Cuboids, Prismoids and Pyramids
|
||||
|
||||
// Function&Module: cube()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// cube(size, [center], ...);
|
||||
// Usage: With Attachments
|
||||
// cube(size, [center], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// vnf = cube(size, [center], ...);
|
||||
// See Also: cuboid(), prismoid()
|
||||
// Description:
|
||||
// Creates a 3D cubic object with support for anchoring and attachments.
|
||||
// This can be used as a drop-in replacement for the built-in `cube()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a cube.
|
||||
// Arguments:
|
||||
// size = The size of the cube.
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=ALLNEG`.
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example: Simple cube.
|
||||
// cube(40);
|
||||
// Example: Rectangular cube.
|
||||
// cube([20,40,50]);
|
||||
// Example: Anchoring.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT);
|
||||
// Example: Spin.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT, spin=30);
|
||||
// Example: Orientation.
|
||||
// cube([20,40,50], anchor=BOTTOM+FRONT, spin=30, orient=FWD);
|
||||
// Example: Standard Connectors.
|
||||
// cube(40, center=true) show_anchors();
|
||||
// Example: Called as Function
|
||||
// vnf = cube([20,40,50]);
|
||||
// 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) {
|
||||
if (size.z > 0) {
|
||||
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) v_mul(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];
|
||||
|
||||
|
||||
|
||||
// Module: cuboid()
|
||||
//
|
||||
|
@ -365,9 +437,6 @@ function cuboid(
|
|||
|
||||
|
||||
|
||||
// Section: Prismoids
|
||||
|
||||
|
||||
// Function&Module: prismoid()
|
||||
//
|
||||
// Usage: Typical Prismoids
|
||||
|
@ -804,7 +873,104 @@ function right_triangle(size=[1,1,1], center, anchor, spin=0, orient=UP) =
|
|||
no_function("right_triangle");
|
||||
|
||||
|
||||
// Section: Cylindroids
|
||||
// Section: Cylinders
|
||||
|
||||
|
||||
// Function&Module: cylinder()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// cylinder(h, r=/d=, [center=], ...);
|
||||
// cylinder(h, r1/d1=, r2/d2=, [center=], ...);
|
||||
// Usage: With Attachments
|
||||
// cylinder(h, r=/d=, [center=]) {attachments}
|
||||
// Usage: As Function
|
||||
// vnf = cylinder(h, r=/d=, [center=], ...);
|
||||
// vnf = cylinder(h, r1/d1=, r2/d2=, [center=], ...);
|
||||
// See Also: cyl()
|
||||
// Description:
|
||||
// Creates a 3D cylinder or conic object with support for anchoring and attachments.
|
||||
// This can be used as a drop-in replacement for the built-in `cylinder()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a cylinder.
|
||||
// Arguments:
|
||||
// l / h = The height of the cylinder.
|
||||
// r1 = The bottom radius of the cylinder. (Before orientation.)
|
||||
// r2 = The top radius of the cylinder. (Before orientation.)
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`.
|
||||
// ---
|
||||
// d1 = The bottom diameter of the cylinder. (Before orientation.)
|
||||
// d2 = The top diameter of the cylinder. (Before orientation.)
|
||||
// r = The radius of the cylinder.
|
||||
// d = The diameter of the cylinder.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// Example: By Radius
|
||||
// xdistribute(30) {
|
||||
// cylinder(h=40, r=10);
|
||||
// cylinder(h=40, r1=10, r2=5);
|
||||
// }
|
||||
// Example: By Diameter
|
||||
// xdistribute(30) {
|
||||
// cylinder(h=40, d=25);
|
||||
// cylinder(h=40, d1=25, d2=10);
|
||||
// }
|
||||
// Example(Med): Anchoring
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT);
|
||||
// Example(Med): Spin
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT, spin=45);
|
||||
// Example(Med): Orient
|
||||
// cylinder(h=40, r1=10, r2=5, anchor=BOTTOM+FRONT, spin=45, orient=FWD);
|
||||
// Example(Big): Standard Connectors
|
||||
// xdistribute(40) {
|
||||
// cylinder(h=30, d=25) show_anchors();
|
||||
// cylinder(h=30, d1=25, d2=10) show_anchors();
|
||||
// }
|
||||
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) {
|
||||
if (l > 0) {
|
||||
linear_extrude(height=l, center=true, convexity=2, scale=r2/r1) {
|
||||
circle(r=r1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zflip() {
|
||||
if (l > 0) {
|
||||
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];
|
||||
|
||||
|
||||
|
||||
// Module: cyl()
|
||||
|
@ -1229,106 +1395,64 @@ module tube(
|
|||
}
|
||||
|
||||
|
||||
// Module: torus()
|
||||
//
|
||||
// Usage: Typical
|
||||
// torus(r_maj|d_maj, r_min|d_min, [center], ...);
|
||||
// torus(or|od, ir|id, ...);
|
||||
// torus(r_maj|d_maj, or|od, ...);
|
||||
// torus(r_maj|d_maj, ir|id, ...);
|
||||
// torus(r_min|d_min, or|od, ...);
|
||||
// torus(r_min|d_min, ir|id, ...);
|
||||
// Usage: Attaching Children
|
||||
// torus(or|od, ir|id, ...) [attachments];
|
||||
//
|
||||
|
||||
|
||||
// Section: Other Round Objects
|
||||
|
||||
|
||||
// Function&Module: sphere()
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// Usage: As Module
|
||||
// sphere(r|d=, [circum=], [style=], ...);
|
||||
// Usage: With Attachments
|
||||
// sphere(r|d=, ...) { attachments }
|
||||
// Usage: As Function
|
||||
// vnf = sphere(r|d=, [circum=], [style=], ...);
|
||||
// See Also: spheroid()
|
||||
// Description:
|
||||
// Creates a torus shape.
|
||||
//
|
||||
// Figure(2D,Med):
|
||||
// module text3d(t,size=8) text(text=t,size=size,font="Helvetica", halign="center",valign="center");
|
||||
// module dashcirc(r,start=0,angle=359.9,dashlen=5) let(step=360*dashlen/(2*r*PI)) for(a=[start:step:start+angle]) stroke(arc(r=r,start=a,angle=step/2));
|
||||
// r = 75; r2 = 30;
|
||||
// down(r2+0.1) #torus(r_maj=r, r_min=r2, $fn=72);
|
||||
// color("blue") linear_extrude(height=0.01) {
|
||||
// dashcirc(r=r,start=15,angle=45);
|
||||
// dashcirc(r=r-r2, start=90+15, angle=60);
|
||||
// dashcirc(r=r+r2, start=180+45, angle=30);
|
||||
// dashcirc(r=r+r2, start=15, angle=30);
|
||||
// }
|
||||
// rot(240) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r+r2,0]], endcaps="arrow2",width=2);
|
||||
// right(r) fwd(9) rot(-240) text3d("or",size=10);
|
||||
// }
|
||||
// rot(135) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r-r2,0]], endcaps="arrow2",width=2);
|
||||
// right((r-r2)/2) back(8) rot(-135) text3d("ir",size=10);
|
||||
// }
|
||||
// rot(45) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r,0]], endcaps="arrow2",width=2);
|
||||
// right(r/2) back(8) text3d("r_maj",size=9);
|
||||
// }
|
||||
// rot(30) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[r,0],[r+r2,0]], endcaps="arrow2",width=2);
|
||||
// right(r+r2/2) fwd(8) text3d("r_min",size=7);
|
||||
// }
|
||||
//
|
||||
// Creates a sphere object, with support for anchoring and attachments.
|
||||
// This is a drop-in replacement for the built-in `sphere()` module.
|
||||
// When called as a function, returns a [VNF](vnf.scad) for a sphere.
|
||||
// Arguments:
|
||||
// r_maj = major radius of torus ring. (use with 'r_min', or 'd_min')
|
||||
// r_min = minor radius of torus ring. (use with 'r_maj', or 'd_maj')
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=DOWN`.
|
||||
// r = Radius of the sphere.
|
||||
// ---
|
||||
// d_maj = major diameter of torus ring. (use with 'r_min', or 'd_min')
|
||||
// d_min = minor diameter of torus ring. (use with 'r_maj', or 'd_maj')
|
||||
// or = outer radius of the torus. (use with 'ir', or 'id')
|
||||
// ir = inside radius of the torus. (use with 'or', or 'od')
|
||||
// od = outer diameter of the torus. (use with 'ir' or 'id')
|
||||
// id = inside diameter of the torus. (use with 'or' or 'od')
|
||||
// d = Diameter of the sphere.
|
||||
// circum = If true, the sphere is made large enough to circumscribe the sphere of the ideal side. Otherwise inscribes. Default: false (inscribes)
|
||||
// style = The style of the sphere's construction. One of "orig", "aligned", "stagger", "octa", or "icosa". Default: "orig"
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
//
|
||||
// Example:
|
||||
// // These all produce the same torus.
|
||||
// torus(r_maj=22.5, r_min=7.5);
|
||||
// torus(d_maj=45, d_min=15);
|
||||
// torus(or=30, ir=15);
|
||||
// torus(od=60, id=30);
|
||||
// torus(d_maj=45, id=30);
|
||||
// torus(d_maj=45, od=60);
|
||||
// torus(d_min=15, id=30);
|
||||
// torus(d_min=15, od=60);
|
||||
// Example: By Radius
|
||||
// sphere(r=50);
|
||||
// Example: By Diameter
|
||||
// sphere(d=100);
|
||||
// Example: style="orig"
|
||||
// sphere(d=100, style="orig", $fn=10);
|
||||
// Example: style="aligned"
|
||||
// sphere(d=100, style="aligned", $fn=10);
|
||||
// Example: style="stagger"
|
||||
// sphere(d=100, style="stagger", $fn=10);
|
||||
// Example: style="icosa"
|
||||
// sphere(d=100, style="icosa", $fn=10);
|
||||
// // In "icosa" style, $fn is quantized
|
||||
// // to the nearest multiple of 5.
|
||||
// Example: Anchoring
|
||||
// sphere(d=100, anchor=FRONT);
|
||||
// Example: Spin
|
||||
// sphere(d=100, anchor=FRONT, spin=45);
|
||||
// Example: Orientation
|
||||
// sphere(d=100, anchor=FRONT, spin=45, orient=FWD);
|
||||
// Example: Standard Connectors
|
||||
// torus(od=60, id=30) show_anchors();
|
||||
module torus(
|
||||
r_maj, r_min, center,
|
||||
d_maj, d_min,
|
||||
or, od, ir, id,
|
||||
anchor, spin=0, orient=UP
|
||||
) {
|
||||
_or = get_radius(r=or, d=od, dflt=undef);
|
||||
_ir = get_radius(r=ir, d=id, dflt=undef);
|
||||
_r_maj = get_radius(r=r_maj, d=d_maj, dflt=undef);
|
||||
_r_min = get_radius(r=r_min, d=d_min, dflt=undef);
|
||||
majrad = is_finite(_r_maj)? _r_maj :
|
||||
is_finite(_ir) && is_finite(_or)? (_or + _ir)/2 :
|
||||
is_finite(_ir) && is_finite(_r_min)? (_ir + _r_min) :
|
||||
is_finite(_or) && is_finite(_r_min)? (_or - _r_min) :
|
||||
assert(false, "Bad Parameters");
|
||||
minrad = is_finite(_r_min)? _r_min :
|
||||
is_finite(_ir)? (majrad - _ir) :
|
||||
is_finite(_or)? (_or - majrad) :
|
||||
assert(false, "Bad Parameters");
|
||||
anchor = get_anchor(anchor, center, BOT, CENTER);
|
||||
attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
|
||||
rotate_extrude(convexity=4) {
|
||||
right(majrad) circle(r=minrad);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
// sphere(d=50) show_anchors();
|
||||
// Example: Called as Function
|
||||
// vnf = sphere(d=100, style="icosa");
|
||||
// vnf_polyhedron(vnf);
|
||||
module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP)
|
||||
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient) children();
|
||||
|
||||
|
||||
|
||||
// Section: Spheroid
|
||||
function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) =
|
||||
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
|
||||
|
||||
|
||||
// Function&Module: spheroid()
|
||||
|
@ -1550,7 +1674,102 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
|
|||
|
||||
|
||||
|
||||
// Section: 3D Printing Shapes
|
||||
// Module: torus()
|
||||
//
|
||||
// Usage: Typical
|
||||
// torus(r_maj|d_maj, r_min|d_min, [center], ...);
|
||||
// torus(or|od, ir|id, ...);
|
||||
// torus(r_maj|d_maj, or|od, ...);
|
||||
// torus(r_maj|d_maj, ir|id, ...);
|
||||
// torus(r_min|d_min, or|od, ...);
|
||||
// torus(r_min|d_min, ir|id, ...);
|
||||
// Usage: Attaching Children
|
||||
// torus(or|od, ir|id, ...) [attachments];
|
||||
//
|
||||
// Description:
|
||||
// Creates a torus shape.
|
||||
//
|
||||
// Figure(2D,Med):
|
||||
// module text3d(t,size=8) text(text=t,size=size,font="Helvetica", halign="center",valign="center");
|
||||
// module dashcirc(r,start=0,angle=359.9,dashlen=5) let(step=360*dashlen/(2*r*PI)) for(a=[start:step:start+angle]) stroke(arc(r=r,start=a,angle=step/2));
|
||||
// r = 75; r2 = 30;
|
||||
// down(r2+0.1) #torus(r_maj=r, r_min=r2, $fn=72);
|
||||
// color("blue") linear_extrude(height=0.01) {
|
||||
// dashcirc(r=r,start=15,angle=45);
|
||||
// dashcirc(r=r-r2, start=90+15, angle=60);
|
||||
// dashcirc(r=r+r2, start=180+45, angle=30);
|
||||
// dashcirc(r=r+r2, start=15, angle=30);
|
||||
// }
|
||||
// rot(240) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r+r2,0]], endcaps="arrow2",width=2);
|
||||
// right(r) fwd(9) rot(-240) text3d("or",size=10);
|
||||
// }
|
||||
// rot(135) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r-r2,0]], endcaps="arrow2",width=2);
|
||||
// right((r-r2)/2) back(8) rot(-135) text3d("ir",size=10);
|
||||
// }
|
||||
// rot(45) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[0,0],[r,0]], endcaps="arrow2",width=2);
|
||||
// right(r/2) back(8) text3d("r_maj",size=9);
|
||||
// }
|
||||
// rot(30) color("blue") linear_extrude(height=0.01) {
|
||||
// stroke([[r,0],[r+r2,0]], endcaps="arrow2",width=2);
|
||||
// right(r+r2/2) fwd(8) text3d("r_min",size=7);
|
||||
// }
|
||||
//
|
||||
// Arguments:
|
||||
// r_maj = major radius of torus ring. (use with 'r_min', or 'd_min')
|
||||
// r_min = minor radius of torus ring. (use with 'r_maj', or 'd_maj')
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=DOWN`.
|
||||
// ---
|
||||
// d_maj = major diameter of torus ring. (use with 'r_min', or 'd_min')
|
||||
// d_min = minor diameter of torus ring. (use with 'r_maj', or 'd_maj')
|
||||
// or = outer radius of the torus. (use with 'ir', or 'id')
|
||||
// ir = inside radius of the torus. (use with 'or', or 'od')
|
||||
// od = outer diameter of the torus. (use with 'ir' or 'id')
|
||||
// id = inside diameter of the torus. (use with 'or' or 'od')
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||
//
|
||||
// Example:
|
||||
// // These all produce the same torus.
|
||||
// torus(r_maj=22.5, r_min=7.5);
|
||||
// torus(d_maj=45, d_min=15);
|
||||
// torus(or=30, ir=15);
|
||||
// torus(od=60, id=30);
|
||||
// torus(d_maj=45, id=30);
|
||||
// torus(d_maj=45, od=60);
|
||||
// torus(d_min=15, id=30);
|
||||
// torus(d_min=15, od=60);
|
||||
// Example: Standard Connectors
|
||||
// torus(od=60, id=30) show_anchors();
|
||||
module torus(
|
||||
r_maj, r_min, center,
|
||||
d_maj, d_min,
|
||||
or, od, ir, id,
|
||||
anchor, spin=0, orient=UP
|
||||
) {
|
||||
_or = get_radius(r=or, d=od, dflt=undef);
|
||||
_ir = get_radius(r=ir, d=id, dflt=undef);
|
||||
_r_maj = get_radius(r=r_maj, d=d_maj, dflt=undef);
|
||||
_r_min = get_radius(r=r_min, d=d_min, dflt=undef);
|
||||
majrad = is_finite(_r_maj)? _r_maj :
|
||||
is_finite(_ir) && is_finite(_or)? (_or + _ir)/2 :
|
||||
is_finite(_ir) && is_finite(_r_min)? (_ir + _r_min) :
|
||||
is_finite(_or) && is_finite(_r_min)? (_or - _r_min) :
|
||||
assert(false, "Bad Parameters");
|
||||
minrad = is_finite(_r_min)? _r_min :
|
||||
is_finite(_ir)? (majrad - _ir) :
|
||||
is_finite(_or)? (_or - majrad) :
|
||||
assert(false, "Bad Parameters");
|
||||
anchor = get_anchor(anchor, center, BOT, CENTER);
|
||||
attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
|
||||
rotate_extrude(convexity=4) {
|
||||
right(majrad) circle(r=minrad);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: teardrop()
|
||||
|
@ -1614,9 +1833,9 @@ module teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, ancho
|
|||
cap_h2 = min(first_defined([cap_h2, cap_h, tip_y2]), tip_y2);
|
||||
capvec = unit([0, cap_h1-cap_h2, l]);
|
||||
anchors = [
|
||||
anchorpt("cap", [0,0,(cap_h1+cap_h2)/2], capvec),
|
||||
anchorpt("cap_fwd", [0,-l/2,cap_h1], unit((capvec+FWD)/2)),
|
||||
anchorpt("cap_back", [0,+l/2,cap_h2], unit((capvec+BACK)/2), 180),
|
||||
named_anchor("cap", [0,0,(cap_h1+cap_h2)/2], capvec),
|
||||
named_anchor("cap_fwd", [0,-l/2,cap_h1], unit((capvec+FWD)/2)),
|
||||
named_anchor("cap_back", [0,+l/2,cap_h2], unit((capvec+BACK)/2), 180),
|
||||
];
|
||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l, axis=BACK, anchors=anchors) {
|
||||
rot(from=UP,to=FWD) {
|
||||
|
@ -1697,6 +1916,273 @@ module onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP)
|
|||
}
|
||||
|
||||
|
||||
// Section: Text
|
||||
|
||||
// Module: atext()
|
||||
// Topics: Attachments, Text
|
||||
// Usage:
|
||||
// atext(text, [h], [size], [font]);
|
||||
// Description:
|
||||
// Creates a 3D text block that can be attached to other attachable objects.
|
||||
// NOTE: This cannot have children attached to it.
|
||||
// Arguments:
|
||||
// text = The text string to instantiate as an object.
|
||||
// h = The height to which the text should be extruded. Default: 1
|
||||
// size = The font size used to create the text block. Default: 10
|
||||
// font = The name of the font used to create the text block. Default: "Courier"
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `"baseline"`
|
||||
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards. See [orient](attachments.scad#orient). Default: `UP`
|
||||
// See Also: attachable()
|
||||
// Extra Anchors:
|
||||
// "baseline" = Anchors at the baseline of the text, at the start of the string.
|
||||
// str("baseline",VECTOR) = Anchors at the baseline of the text, modified by the X and Z components of the appended vector.
|
||||
// Examples:
|
||||
// atext("Foobar", h=3, size=10);
|
||||
// atext("Foobar", h=2, size=12, font="Helvetica");
|
||||
// atext("Foobar", h=2, anchor=CENTER);
|
||||
// atext("Foobar", h=2, anchor=str("baseline",CENTER));
|
||||
// atext("Foobar", h=2, anchor=str("baseline",BOTTOM+RIGHT));
|
||||
// Example: Using line_of() distributor
|
||||
// txt = "This is the string.";
|
||||
// line_of(spacing=[10,-5],n=len(txt))
|
||||
// atext(txt[$idx], size=10, anchor=CENTER);
|
||||
// Example: Using arc_of() distributor
|
||||
// txt = "This is the string";
|
||||
// arc_of(r=50, n=len(txt), sa=0, ea=180)
|
||||
// atext(select(txt,-1-$idx), size=10, anchor=str("baseline",CENTER), spin=-90);
|
||||
module atext(text, h=1, size=9, font="Courier", anchor="baseline", spin=0, orient=UP) {
|
||||
no_children($children);
|
||||
dummy1 =
|
||||
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Got: ",anchor))
|
||||
assert(is_undef(spin) || is_vector(spin,3) || is_num(spin), str("Got: ",spin))
|
||||
assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient));
|
||||
anchor = default(anchor, CENTER);
|
||||
spin = default(spin, 0);
|
||||
orient = default(orient, UP);
|
||||
geom = _attach_geom(size=[size,size,h]);
|
||||
anch = !any([for (c=anchor) c=="["])? anchor :
|
||||
let(
|
||||
parts = str_split(str_split(str_split(anchor,"]")[0],"[")[1],","),
|
||||
vec = [for (p=parts) str_float(str_strip_leading(p," "))]
|
||||
) vec;
|
||||
ha = anchor=="baseline"? "left" :
|
||||
anchor==anch && is_string(anchor)? "center" :
|
||||
anch.x<0? "left" :
|
||||
anch.x>0? "right" :
|
||||
"center";
|
||||
va = starts_with(anchor,"baseline")? "baseline" :
|
||||
anchor==anch && is_string(anchor)? "center" :
|
||||
anch.y<0? "bottom" :
|
||||
anch.y>0? "top" :
|
||||
"center";
|
||||
base = anchor=="baseline"? CENTER :
|
||||
anchor==anch && is_string(anchor)? CENTER :
|
||||
anch.z<0? BOTTOM :
|
||||
anch.z>0? TOP :
|
||||
CENTER;
|
||||
m = _attach_transform(base,spin,orient,geom);
|
||||
multmatrix(m) {
|
||||
$parent_anchor = anchor;
|
||||
$parent_spin = spin;
|
||||
$parent_orient = orient;
|
||||
$parent_geom = geom;
|
||||
$parent_size = _attach_geom_size(geom);
|
||||
$attach_to = undef;
|
||||
do_show = _attachment_is_shown($tags);
|
||||
if (do_show) {
|
||||
if (is_undef($color)) {
|
||||
linear_extrude(height=h, center=true)
|
||||
text(text=text, size=size, halign=ha, valign=va, font=font);
|
||||
} else color($color) {
|
||||
$color = undef;
|
||||
linear_extrude(height=h, center=true)
|
||||
text(text=text, size=size, halign=ha, valign=va, font=font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function _cut_interp(pathcut, path, data) =
|
||||
[for(entry=pathcut)
|
||||
let(
|
||||
a = path[entry[1]-1],
|
||||
b = path[entry[1]],
|
||||
c = entry[0],
|
||||
i = max_index(v_abs(b-a)),
|
||||
factor = (c[i]-a[i])/(b[i]-a[i])
|
||||
)
|
||||
(1-factor)*data[entry[1]-1]+ factor * data[entry[1]]
|
||||
];
|
||||
|
||||
|
||||
// Module: path_text()
|
||||
// Usage:
|
||||
// path_text(path, text, [size], [thickness], [font], [lettersize], [offset], [reverse], [normal], [top], [textmetrics])
|
||||
// Description:
|
||||
// Place the text letter by letter onto the specified path using textmetrics (if available and requested)
|
||||
// or user specified letter spacing. The path can be 2D or 3D. In 2D the text appears along the path with letters upright
|
||||
// as determined by the path direction. In 3D by default letters are positioned on the tangent line to the path with the path normal
|
||||
// pointing toward the reader. The path normal points away from the center of curvature (the opposite of the normal produced
|
||||
// by path_normals()). Note that this means that if the center of curvature switches sides the text will flip upside down.
|
||||
// If you want text on such a path you must supply your own normal or top vector.
|
||||
// .
|
||||
// Text appears starting at the beginning of the path, so if the 3D path moves right to left
|
||||
// then a left-to-right reading language will display in the wrong order. (For a 2D path text will appear upside down.)
|
||||
// The text for a 3D path appears positioned to be read from "outside" of the curve (from a point on the other side of the
|
||||
// curve from the center of curvature). If you need the text to read properly from the inside, you can set reverse to
|
||||
// true to flip the text, or supply your own normal.
|
||||
// .
|
||||
// If you do not have the experimental textmetrics feature enabled then you must specify the space for the letters
|
||||
// using lettersize, which can be a scalar or array. You will have the easiest time getting good results by using
|
||||
// a monospace font such as Courier. Note that even with text metrics, spacing may be different because path_text()
|
||||
// doesn't do kerning to adjust positions of individual glyphs. Also if your font has ligatures they won't be used.
|
||||
// .
|
||||
// By default letters appear centered on the path. The offset can be specified to shift letters toward the reader (in
|
||||
// the direction of the normal).
|
||||
// .
|
||||
// You can specify your own normal by setting `normal` to a direction or a list of directions. Your normal vector should
|
||||
// point toward the reader. You can also specify
|
||||
// top, which directs the top of the letters in a desired direction. If you specify your own directions and they
|
||||
// are not perpendicular to the path then the direction you specify will take priority and the
|
||||
// letters will not rest on the tangent line of the path. Note that the normal or top directions that you
|
||||
// specify must not be parallel to the path.
|
||||
// Arguments:
|
||||
// path = path to place the text on
|
||||
// text = text to create
|
||||
// size = font size
|
||||
// thickness = thickness of letters (not allowed for 2D path)
|
||||
// font = font to use
|
||||
// ---
|
||||
// lettersize = scalar or array giving size of letters
|
||||
// offset = distance to shift letters "up" (towards the reader). Not allowed for 2D path. Default: 0
|
||||
// normal = direction or list of directions pointing towards the reader of the text. Not allowed for 2D path.
|
||||
// top = direction or list of directions pointing toward the top of the text
|
||||
// reverse = reverse the letters if true. Not allowed for 2D path. Default: false
|
||||
// textmetrics = if set to true and lettersize is not given then use the experimental textmetrics feature. You must be running a dev snapshot that includes this feature and have the feature turned on in your preferences. Default: false
|
||||
// Example: The examples use Courier, a monospaced font. The width is 1/1.2 times the specified size for this font. This text could wrap around a cylinder.
|
||||
// path = path3d(arc(100, r=25, angle=[245, 370]));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2);
|
||||
// Example: By setting the normal to UP we can get text that lies flat, for writing around the edge of a disk:
|
||||
// path = path3d(arc(100, r=25, angle=[245, 370]));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, normal=UP);
|
||||
// Example: If we want text that reads from the other side we can use reverse. Note we have to reverse the direction of the path and also set the reverse option.
|
||||
// path = reverse(path3d(arc(100, r=25, angle=[65, 190])));
|
||||
// color("red")stroke(path, width=.3);
|
||||
// path_text(path, "Example text", font="Courier", size=5, lettersize = 5/1.2, reverse=true);
|
||||
// Example: text debossed onto a cylinder in a spiral. The text is 1 unit deep because it is half in, half out.
|
||||
// text = ("A long text example to wrap around a cylinder, possibly for a few times.");
|
||||
// L = 5*len(text);
|
||||
// maxang = 360*L/(PI*50);
|
||||
// spiral = [for(a=[0:1:maxang]) [25*cos(a), 25*sin(a), 10-30/maxang*a]];
|
||||
// difference(){
|
||||
// cyl(d=50, l=50, $fn=120);
|
||||
// path_text(spiral, text, size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// }
|
||||
// Example: Same example but text embossed. Make sure you have enough depth for the letters to fully overlap the object.
|
||||
// text = ("A long text example to wrap around a cylinder, possibly for a few times.");
|
||||
// L = 5*len(text);
|
||||
// maxang = 360*L/(PI*50);
|
||||
// spiral = [for(a=[0:1:maxang]) [25*cos(a), 25*sin(a), 10-30/maxang*a]];
|
||||
// cyl(d=50, l=50, $fn=120);
|
||||
// path_text(spiral, text, size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// Example: Here the text baseline sits on the path. (Note the default orientation makes text readable from below, so we specify the normal.)
|
||||
// path = arc(100, points = [[-20, 0, 20], [0,0,5], [20,0,20]]);
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "Example Text", size=5, lettersize=5/1.2, font="Courier", normal=FRONT);
|
||||
// Example: If we use top to orient the text upward, the text baseline is no longer aligned with the path.
|
||||
// path = arc(100, points = [[-20, 0, 20], [0,0,5], [20,0,20]]);
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "Example Text", size=5, lettersize=5/1.2, font="Courier", top=UP);
|
||||
// Example: This sine wave wrapped around the cylinder has a twisting normal that produces wild letter layout. We fix it with a custom normal which is different at every path point.
|
||||
// path = [for(theta = [0:360]) [25*cos(theta), 25*sin(theta), 4*cos(theta*4)]];
|
||||
// normal = [for(theta = [0:360]) [cos(theta), sin(theta),0]];
|
||||
// zrot(-120)
|
||||
// difference(){
|
||||
// cyl(r=25, h=20, $fn=120);
|
||||
// path_text(path, "A sine wave wiggles", font="Courier", lettersize=5/1.2, size=5, normal=normal);
|
||||
// }
|
||||
// Example: The path center of curvature changes, and the text flips.
|
||||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier", thickness=2);
|
||||
// Example: We can fix it with top:
|
||||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier", thickness=2, top=UP);
|
||||
// Example(2D): With a 2D path instead of 3D there's no ambiguity about direction and it works by default:
|
||||
// path = zrot(-120,p=concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180]))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier");
|
||||
module path_text(path, text, font, size, thickness, lettersize, offset=0, reverse=false, normal, top, textmetrics=false)
|
||||
{
|
||||
dummy2=assert(is_path(path,[2,3]),"Must supply a 2d or 3d path")
|
||||
assert(num_defined([normal,top])<=1, "Cannot define both \"normal\" and \"top\"");
|
||||
dim = len(path[0]);
|
||||
normalok = is_undef(normal) || is_vector(normal,3) || (is_path(normal,3) && len(normal)==len(path));
|
||||
topok = is_undef(top) || is_vector(top,dim) || (dim==2 && is_vector(top,3) && top[2]==0)
|
||||
|| (is_path(top,dim) && len(top)==len(path));
|
||||
dummy4 = assert(dim==3 || is_undef(thickness), "Cannot give a thickness with 2d path")
|
||||
assert(dim==3 || !reverse, "Reverse not allowed with 2d path")
|
||||
assert(dim==3 || offset==0, "Cannot give offset with 2d path")
|
||||
assert(dim==3 || is_undef(normal), "Cannot define \"normal\" for a 2d path, only \"top\"")
|
||||
assert(normalok,"\"normal\" must be a vector or path compatible with the given path")
|
||||
assert(topok,"\"top\" must be a vector or path compatible with the given path");
|
||||
thickness = first_defined([thickness,1]);
|
||||
normal = is_vector(normal) ? repeat(normal, len(path))
|
||||
: is_def(normal) ? normal
|
||||
: undef;
|
||||
|
||||
top = is_vector(top) ? repeat(dim==2?point2d(top):top, len(path))
|
||||
: is_def(top) ? top
|
||||
: undef;
|
||||
|
||||
lsize = is_def(lettersize) ? force_list(lettersize, len(text))
|
||||
: textmetrics ? [for(letter=text) let(t=textmetrics(letter, font=font, size=size)) t.advance[0]]
|
||||
: assert(false, "textmetrics disabled: Must specify letter size");
|
||||
|
||||
dummy1 = assert(sum(lsize)<=path_length(path),"Path is too short for the text");
|
||||
|
||||
pts = path_cut_points(path, add_scalar([0, each cumsum(lsize)],lsize[0]/2), direction=true);
|
||||
|
||||
usernorm = is_def(normal);
|
||||
usetop = is_def(top);
|
||||
|
||||
normpts = is_undef(normal) ? (reverse?1:-1)*subindex(pts,3) : _cut_interp(pts,path, normal);
|
||||
toppts = is_undef(top) ? undef : _cut_interp(pts,path,top);
|
||||
for(i=idx(text))
|
||||
let( tangent = pts[i][2] )
|
||||
assert(!usetop || !approx(tangent*toppts[i],norm(top[i])*norm(tangent)),
|
||||
str("Specified top direction parallel to path at character ",i))
|
||||
assert(usetop || !approx(tangent*normpts[i],norm(normpts[i])*norm(tangent)),
|
||||
str("Specified normal direction parallel to path at character ",i))
|
||||
let(
|
||||
adjustment = usetop ? (tangent*toppts[i])*toppts[i]/(toppts[i]*toppts[i])
|
||||
: usernorm ? (tangent*normpts[i])*normpts[i]/(normpts[i]*normpts[i])
|
||||
: [0,0,0]
|
||||
)
|
||||
move(pts[i][0])
|
||||
if(dim==3){
|
||||
frame_map(x=tangent-adjustment,
|
||||
z=usetop ? undef : normpts[i],
|
||||
y=usetop ? toppts[i] : undef)
|
||||
up(offset-thickness/2)
|
||||
linear_extrude(height=thickness)
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
} else {
|
||||
frame_map(x=point3d(tangent-adjustment), y=point3d(usetop ? toppts[i] : -normpts[i]))
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Section: Miscellaneous
|
||||
|
||||
|
|
3
std.scad
3
std.scad
|
@ -14,7 +14,6 @@ include <transforms.scad>
|
|||
include <distributors.scad>
|
||||
include <mutators.scad>
|
||||
include <attachments.scad>
|
||||
include <primitives.scad>
|
||||
include <shapes3d.scad>
|
||||
include <shapes2d.scad>
|
||||
include <drawing.scad>
|
||||
|
@ -34,7 +33,7 @@ include <regions.scad>
|
|||
include <strings.scad>
|
||||
include <skin.scad>
|
||||
include <vnf.scad>
|
||||
include <common.scad>
|
||||
include <utility.scad>
|
||||
include <debug.scad>
|
||||
|
||||
|
||||
|
|
51
tests/test_drawing.scad
Normal file
51
tests/test_drawing.scad
Normal file
|
@ -0,0 +1,51 @@
|
|||
include <../std.scad>
|
||||
|
||||
module test_turtle() {
|
||||
assert_approx(
|
||||
turtle([
|
||||
"move", 10,
|
||||
"ymove", 5,
|
||||
"xmove", 5,
|
||||
"xymove", [10,15],
|
||||
"left", 135,
|
||||
"untilx", 0,
|
||||
"turn", 90,
|
||||
"untily", 0,
|
||||
"right", 135,
|
||||
"arcsteps", 5,
|
||||
"arcright", 15, 30,
|
||||
"arcleft", 15, 30,
|
||||
"arcsteps", 0,
|
||||
"arcrightto", 15, 90,
|
||||
"arcleftto", 15, 180,
|
||||
"jump", [10,10],
|
||||
"xjump", 15,
|
||||
"yjump", 15,
|
||||
"angle", 30,
|
||||
"length", 15,
|
||||
"right",
|
||||
"move",
|
||||
"scale", 2,
|
||||
"left",
|
||||
"move",
|
||||
"addlength", 5,
|
||||
"repeat", 3, ["move"],
|
||||
], $fn=24),
|
||||
[[0,0],[10,0],[10,5],[15,5],[25,20],[-3.5527136788e-15,45],[-45,0],[-44.8716729206,1.9578928833],[-44.4888873943,3.88228567654],[-43.8581929877,5.74025148548],[-42.9903810568,7.5],[-42.1225691259,9.25974851452],[-41.4918747192,11.1177143235],[-41.1090891929,13.0421071167],[-40.9807621135,15],[-41.0157305757,16.0236362005],[-41.120472923,17.0424997364],[-41.2945007983,18.0518401958],[-41.5370028033,19.0469515674],[-41.8468482818,20.0231941826],[-42.222592591,20.9760163477],[-42.6624838375,21.900975566],[-43.1644710453,22.7937592505],[-43.7262137184,23.6502048317],[-44.345092753,24.4663191649],[-45.0182226494,25.2382971483],[-45.7424649653,25.9625394642],[-46.5144429486,26.6356693606],[-47.3305572818,27.2545483952],[-48.187002863,27.8162910682],[-49.0797865476,28.318278276],[-50.0047457658,28.7581695226],[-50.957567931,29.1339138318],[-51.9338105462,29.4437593102],[-52.9289219177,29.6862613152],[-53.9382623771,29.8602891905],[-54.9571259131,29.9650315379],[-55.9807621135,30],[10,10],[15,10],[15,15],[2.00961894323,22.5],[-27.9903810568,22.5],[-62.9903810568,22.5],[-97.9903810568,22.5],[-132.990381057,22.5]]
|
||||
);
|
||||
}
|
||||
test_turtle();
|
||||
|
||||
|
||||
module test_arc() {
|
||||
assert_approx(arc(N=8, d=100, angle=135, cp=[10,10]), [[60,10],[57.1941665154,26.5139530978],[49.0915741234,41.1744900929],[36.6016038258,52.3362099614],[21.1260466978,58.7463956091],[4.40177619483,59.6856104947],[-11.6941869559,55.0484433951],[-25.3553390593,45.3553390593]]);
|
||||
assert_approx(arc(N=8, d=100, angle=135, cp=[10,10],endpoint=false), [[60,10],[57.8470167866,24.5142338627],[51.5734806151,37.778511651],[41.7196642082,48.6505226681],[29.1341716183,56.1939766256],[14.9008570165,59.7592363336],[0.245483899194,59.0392640202],[-13.5698368413,54.0960632174]]);
|
||||
assert_approx(arc(N=8, d=100, angle=[45,225], cp=[10,10]), [[45.3553390593,45.3553390593],[26.5139530978,57.1941665154],[4.40177619483,59.6856104947],[-16.6016038258,52.3362099614],[-32.3362099614,36.6016038258],[-39.6856104947,15.5982238052],[-37.1941665154,-6.51395309776],[-25.3553390593,-25.3553390593]]);
|
||||
assert_approx(arc(N=8, d=100, start=45, angle=135, cp=[10,10]), [[45.3553390593,45.3553390593],[31.6941869559,55.0484433951],[15.5982238052,59.6856104947],[-1.12604669782,58.7463956091],[-16.6016038258,52.3362099614],[-29.0915741234,41.1744900929],[-37.1941665154,26.5139530978],[-40,10]]);
|
||||
assert_approx(arc(N=8, d=100, start=45, angle=-90, cp=[10,10]), [[45.3553390593,45.3553390593],[52.3362099614,36.6016038258],[57.1941665154,26.5139530978],[59.6856104947,15.5982238052],[59.6856104947,4.40177619483],[57.1941665154,-6.51395309776],[52.3362099614,-16.6016038258],[45.3553390593,-25.3553390593]]);
|
||||
assert_approx(arc(N=8, width=100, thickness=30), [[50,-3.5527136788e-15],[39.5300788555,13.9348601124],[25.3202618476,24.0284558904],[8.71492362453,29.3258437015],[-8.71492362453,29.3258437015],[-25.3202618476,24.0284558904],[-39.5300788555,13.9348601124],[-50,-1.42108547152e-14]]);
|
||||
assert_approx(arc(N=8, cp=[10,10], points=[[45,45],[-25,45]]), [[45,45],[36.3342442379,51.9107096148],[26.3479795075,56.7198412457],[15.5419588213,59.1862449514],[4.45804117867,59.1862449514],[-6.34797950747,56.7198412457],[-16.3342442379,51.9107096148],[-25,45]]);
|
||||
assert_approx(arc(N=24, cp=[10,10], points=[[45,45],[-25,45]], long=true), [[45,45],[51.3889035257,37.146982612],[56.0464336973,28.1583574081],[58.7777575294,18.4101349813],[59.4686187624,8.31010126292],[58.0901174104,-1.71924090789],[54.6999187001,-11.2583458482],[49.4398408296,-19.9081753929],[42.5299224539,-27.3068913894],[34.2592180667,-33.1449920477],[24.9737063235,-37.1782589647],[15.0618171232,-39.2379732261],[4.93818287676,-39.2379732261],[-4.97370632349,-37.1782589647],[-14.2592180667,-33.1449920477],[-22.5299224539,-27.3068913894],[-29.4398408296,-19.9081753929],[-34.6999187001,-11.2583458482],[-38.0901174104,-1.71924090789],[-39.4686187624,8.31010126292],[-38.7777575294,18.4101349813],[-36.0464336973,28.1583574081],[-31.3889035257,37.146982612],[-25,45]]);
|
||||
assert_approx(arc($fn=24, cp=[10,10], points=[[45,45],[-25,45]], long=true), [[45,45],[53.2421021636,34.0856928585],[58.1827254512,21.3324740498],[59.4446596304,7.71403542491],[56.9315576496,-5.72987274525],[50.8352916125,-17.9728253654],[41.6213035891,-28.0800887515],[29.9930697126,-35.2799863457],[16.8383906815,-39.0228152281],[3.16160931847,-39.0228152281],[-9.9930697126,-35.2799863457],[-21.6213035891,-28.0800887515],[-30.8352916125,-17.9728253654],[-36.9315576496,-5.72987274525],[-39.4446596304,7.71403542491],[-38.1827254512,21.3324740498],[-33.2421021636,34.0856928585],[-25,45]]);
|
||||
}
|
||||
test_arc();
|
|
@ -12,7 +12,7 @@ test_point_line_distance();
|
|||
test_segment_distance();
|
||||
test_line_normal();
|
||||
test_line_intersection();
|
||||
//test_line_ray_intersection(); // should add this typ eof case
|
||||
//test_line_ray_intersection(); // should add this type of case
|
||||
//test_ray_intersection(); // should add this type of case
|
||||
//test_ray_segment_intersection(); // should add this type of case
|
||||
test_line_closest_point();
|
||||
|
@ -35,7 +35,7 @@ test_polygon_line_intersection();
|
|||
test_plane_intersection();
|
||||
test_is_coplanar();
|
||||
test_are_points_on_plane();
|
||||
test_is_above_plane();
|
||||
test__is_point_above_plane();
|
||||
test_circle_2tangents();
|
||||
test_circle_3points();
|
||||
test_circle_point_tangents();
|
||||
|
@ -56,13 +56,6 @@ test_reverse_polygon();
|
|||
test_polygon_normal();
|
||||
|
||||
//tests to migrate to other files
|
||||
test_is_path();
|
||||
test_is_closed_path();
|
||||
test_close_path();
|
||||
test_cleanup_path();
|
||||
test_simplify_path();
|
||||
test_simplify_path_indexed();
|
||||
test_is_region();
|
||||
test_convex_distance();
|
||||
test_convex_collision();
|
||||
|
||||
|
@ -738,53 +731,19 @@ module test_is_coplanar() {
|
|||
*test_is_coplanar();
|
||||
|
||||
|
||||
module test_is_above_plane() {
|
||||
module test__is_point_above_plane() {
|
||||
plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
|
||||
assert(is_above_plane(plane, [5,5,10]) == false);
|
||||
assert(is_above_plane(plane, [-5,0,0]) == true);
|
||||
assert(is_above_plane(plane, [5,0,0]) == false);
|
||||
assert(is_above_plane(plane, [0,-5,0]) == true);
|
||||
assert(is_above_plane(plane, [0,5,0]) == false);
|
||||
assert(is_above_plane(plane, [0,0,5]) == true);
|
||||
assert(is_above_plane(plane, [0,0,-5]) == false);
|
||||
assert(_is_point_above_plane(plane, [5,5,10]) == false);
|
||||
assert(_is_point_above_plane(plane, [-5,0,0]) == true);
|
||||
assert(_is_point_above_plane(plane, [5,0,0]) == false);
|
||||
assert(_is_point_above_plane(plane, [0,-5,0]) == true);
|
||||
assert(_is_point_above_plane(plane, [0,5,0]) == false);
|
||||
assert(_is_point_above_plane(plane, [0,0,5]) == true);
|
||||
assert(_is_point_above_plane(plane, [0,0,-5]) == false);
|
||||
}
|
||||
*test_is_above_plane();
|
||||
*test__is_point_above_plane();
|
||||
|
||||
|
||||
module test_is_path() {
|
||||
assert(is_path([[1,2,3],[4,5,6]]));
|
||||
assert(is_path([[1,2,3],[4,5,6],[7,8,9]]));
|
||||
assert(!is_path(123));
|
||||
assert(!is_path("foo"));
|
||||
assert(!is_path(true));
|
||||
assert(!is_path([]));
|
||||
assert(!is_path([[]]));
|
||||
assert(!is_path([["foo","bar","baz"]]));
|
||||
assert(!is_path([[1,2,3]]));
|
||||
assert(!is_path([["foo","bar","baz"],["qux","quux","quuux"]]));
|
||||
}
|
||||
*test_is_path();
|
||||
|
||||
|
||||
module test_is_closed_path() {
|
||||
assert(!is_closed_path([[1,2,3],[4,5,6],[1,8,9]]));
|
||||
assert(is_closed_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]));
|
||||
}
|
||||
*test_is_closed_path();
|
||||
|
||||
|
||||
module test_close_path() {
|
||||
assert(close_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
|
||||
assert(close_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
|
||||
}
|
||||
*test_close_path();
|
||||
|
||||
|
||||
module test_cleanup_path() {
|
||||
assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9]]);
|
||||
assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9]]);
|
||||
}
|
||||
*test_cleanup_path();
|
||||
|
||||
|
||||
module test_polygon_area() {
|
||||
|
@ -869,19 +828,6 @@ module test_centroid() {
|
|||
*test_centroid();
|
||||
|
||||
|
||||
module test_simplify_path() {
|
||||
path = [[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]];
|
||||
assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]);
|
||||
}
|
||||
*test_simplify_path();
|
||||
|
||||
|
||||
module test_simplify_path_indexed() {
|
||||
pts = [[10,0], [0,-10], [20,20], [20,10], [-20,-20], [15,30], [-10,-20]];
|
||||
path = [4,6,1,0,3,2,5];
|
||||
assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]);
|
||||
}
|
||||
*test_simplify_path_indexed();
|
||||
|
||||
|
||||
module test_point_in_polygon() {
|
||||
|
@ -946,17 +892,6 @@ module test_reverse_polygon() {
|
|||
*test_reverse_polygon();
|
||||
|
||||
|
||||
module test_is_region() {
|
||||
assert(is_region([circle(d=10),square(10)]));
|
||||
assert(is_region([circle(d=10),square(10),circle(d=50)]));
|
||||
assert(is_region([square(10)]));
|
||||
assert(!is_region([]));
|
||||
assert(!is_region(23));
|
||||
assert(!is_region(true));
|
||||
assert(!is_region("foo"));
|
||||
}
|
||||
*test_is_region();
|
||||
|
||||
module test_convex_distance() {
|
||||
// 2D
|
||||
c1 = circle(10,$fn=24);
|
||||
|
|
51
tests/test_paths.scad
Normal file
51
tests/test_paths.scad
Normal file
|
@ -0,0 +1,51 @@
|
|||
include<../std.scad>
|
||||
|
||||
module test_is_path() {
|
||||
assert(is_path([[1,2,3],[4,5,6]]));
|
||||
assert(is_path([[1,2,3],[4,5,6],[7,8,9]]));
|
||||
assert(!is_path(123));
|
||||
assert(!is_path("foo"));
|
||||
assert(!is_path(true));
|
||||
assert(!is_path([]));
|
||||
assert(!is_path([[]]));
|
||||
assert(!is_path([["foo","bar","baz"]]));
|
||||
assert(!is_path([[1,2,3]]));
|
||||
assert(!is_path([["foo","bar","baz"],["qux","quux","quuux"]]));
|
||||
}
|
||||
test_is_path();
|
||||
|
||||
|
||||
module test_is_closed_path() {
|
||||
assert(!is_closed_path([[1,2,3],[4,5,6],[1,8,9]]));
|
||||
assert(is_closed_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]));
|
||||
}
|
||||
test_is_closed_path();
|
||||
|
||||
|
||||
module test_close_path() {
|
||||
assert(close_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
|
||||
assert(close_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9],[1,2,3]]);
|
||||
}
|
||||
test_close_path();
|
||||
|
||||
|
||||
module test_cleanup_path() {
|
||||
assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9]]) == [[1,2,3],[4,5,6],[1,8,9]]);
|
||||
assert(cleanup_path([[1,2,3],[4,5,6],[1,8,9],[1,2,3]]) == [[1,2,3],[4,5,6],[1,8,9]]);
|
||||
}
|
||||
test_cleanup_path();
|
||||
|
||||
|
||||
module test_simplify_path() {
|
||||
path = [[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]];
|
||||
assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]);
|
||||
}
|
||||
test_simplify_path();
|
||||
|
||||
|
||||
module test_simplify_path_indexed() {
|
||||
pts = [[10,0], [0,-10], [20,20], [20,10], [-20,-20], [15,30], [-10,-20]];
|
||||
path = [4,6,1,0,3,2,5];
|
||||
assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]);
|
||||
}
|
||||
test_simplify_path_indexed();
|
|
@ -1,65 +0,0 @@
|
|||
include <../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]]);
|
||||
}
|
||||
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(is_polygon_clockwise(circle(d=200)));
|
||||
assert(is_polygon_clockwise(circle(r=100)));
|
||||
assert(len(circle(d=100,$fn=6)) == 6);
|
||||
assert(len(circle(d=100,$fn=36)) == 36);
|
||||
}
|
||||
test_circle();
|
||||
|
||||
|
||||
module test_cube() {
|
||||
assert_equal(cube(100,center=true), [[[-50,-50,-50],[50,-50,-50],[50,50,-50],[-50,50,-50],[-50,-50,50],[50,-50,50],[50,50,50],[-50,50,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],center=true), [[[-30,-40,-50],[30,-40,-50],[30,40,-50],[-30,40,-50],[-30,-40,50],[30,-40,50],[30,40,50],[-30,40,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=CENTER), [[[-30,-40,-50],[30,-40,-50],[30,40,-50],[-30,40,-50],[-30,-40,50],[30,-40,50],[30,40,50],[-30,40,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],center=false), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100]), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=ALLNEG), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=TOP), [[[-30,-40,-100],[30,-40,-100],[30,40,-100],[-30,40,-100],[-30,-40,0],[30,-40,0],[30,40,0],[-30,40,0]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
}
|
||||
test_cube();
|
||||
|
||||
|
||||
module test_cylinder() {
|
||||
$fn=12;
|
||||
assert_approx(cylinder(r=40,h=100,center=true), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,center=true), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,anchor=CENTER), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,center=false), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,anchor=BOT), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
}
|
||||
test_cylinder();
|
||||
|
||||
|
||||
module test_sphere() {
|
||||
$fn=6;
|
||||
assert_approx(sphere(r=40), [[[20,0,34.6410161514],[10,17.3205080757,34.6410161514],[-10,17.3205080757,34.6410161514],[-20,0,34.6410161514],[-10,-17.3205080757,34.6410161514],[10,-17.3205080757,34.6410161514],[40,0,0],[20,34.6410161514,0],[-20,34.6410161514,0],[-40,0,0],[-20,-34.6410161514,0],[20,-34.6410161514,0],[20,0,-34.6410161514],[10,17.3205080757,-34.6410161514],[-10,17.3205080757,-34.6410161514],[-20,0,-34.6410161514],[-10,-17.3205080757,-34.6410161514],[10,-17.3205080757,-34.6410161514]],[[5,4,3,2,1,0],[12,13,14,15,16,17],[6,0,1],[6,1,7],[7,1,2],[7,2,8],[8,2,3],[8,3,9],[9,3,4],[9,4,10],[10,4,5],[10,5,11],[11,5,0],[11,0,6],[12,6,7],[12,7,13],[13,7,8],[13,8,14],[14,8,9],[14,9,15],[15,9,10],[15,10,16],[16,10,11],[16,11,17],[17,11,6],[17,6,12]]]);
|
||||
assert_approx(sphere(r=40,style="orig"), [[[20,0,34.6410161514],[10,17.3205080757,34.6410161514],[-10,17.3205080757,34.6410161514],[-20,0,34.6410161514],[-10,-17.3205080757,34.6410161514],[10,-17.3205080757,34.6410161514],[40,0,0],[20,34.6410161514,0],[-20,34.6410161514,0],[-40,0,0],[-20,-34.6410161514,0],[20,-34.6410161514,0],[20,0,-34.6410161514],[10,17.3205080757,-34.6410161514],[-10,17.3205080757,-34.6410161514],[-20,0,-34.6410161514],[-10,-17.3205080757,-34.6410161514],[10,-17.3205080757,-34.6410161514]],[[5,4,3,2,1,0],[12,13,14,15,16,17],[6,0,1],[6,1,7],[7,1,2],[7,2,8],[8,2,3],[8,3,9],[9,3,4],[9,4,10],[10,4,5],[10,5,11],[11,5,0],[11,0,6],[12,6,7],[12,7,13],[13,7,8],[13,8,14],[14,8,9],[14,9,15],[15,9,10],[15,10,16],[16,10,11],[16,11,17],[17,11,6],[17,6,12]]]);
|
||||
assert_approx(sphere(r=40,style="aligned"), [[[0,0,40],[34.6410161514,0,20],[17.3205080757,30,20],[-17.3205080757,30,20],[-34.6410161514,0,20],[-17.3205080757,-30,20],[17.3205080757,-30,20],[34.6410161514,0,-20],[17.3205080757,30,-20],[-17.3205080757,30,-20],[-34.6410161514,0,-20],[-17.3205080757,-30,-20],[17.3205080757,-30,-20],[0,0,-40]],[[1,0,2],[13,7,8],[2,0,3],[13,8,9],[3,0,4],[13,9,10],[4,0,5],[13,10,11],[5,0,6],[13,11,12],[6,0,1],[13,12,7],[1,2,8],[1,8,7],[2,3,9],[2,9,8],[3,4,10],[3,10,9],[4,5,11],[4,11,10],[5,6,12],[5,12,11],[6,1,7],[6,7,12]]]);
|
||||
assert_approx(sphere(r=40,style="stagger"), [[[0,0,40],[30,17.3205080757,20],[0,34.6410161514,20],[-30,17.3205080757,20],[-30,-17.3205080757,20],[0,-34.6410161514,20],[30,-17.3205080757,20],[34.6410161514,0,-20],[17.3205080757,30,-20],[-17.3205080757,30,-20],[-34.6410161514,0,-20],[-17.3205080757,-30,-20],[17.3205080757,-30,-20],[0,0,-40]],[[1,0,2],[13,7,8],[2,0,3],[13,8,9],[3,0,4],[13,9,10],[4,0,5],[13,10,11],[5,0,6],[13,11,12],[6,0,1],[13,12,7],[1,2,8],[1,8,7],[2,3,9],[2,9,8],[3,4,10],[3,10,9],[4,5,11],[4,11,10],[5,6,12],[5,12,11],[6,1,7],[6,7,12]]]);
|
||||
assert_approx(sphere(r=40,style="octa"), [[[0,0,40],[28.2842712475,0,28.2842712475],[0,28.2842712475,28.2842712475],[-28.2842712475,0,28.2842712475],[0,-28.2842712475,28.2842712475],[40,0,0],[28.2842712475,28.2842712475,0],[0,40,0],[-28.2842712475,28.2842712475,0],[-40,0,0],[-28.2842712475,-28.2842712475,0],[0,-40,0],[28.2842712475,-28.2842712475,0],[28.2842712475,0,-28.2842712475],[0,28.2842712475,-28.2842712475],[-28.2842712475,0,-28.2842712475],[0,-28.2842712475,-28.2842712475],[0,0,-40]],[[0,2,1],[0,3,2],[0,4,3],[0,1,4],[17,15,16],[17,14,15],[17,13,14],[17,16,13],[1,6,5],[1,2,6],[13,5,6],[13,6,14],[2,7,6],[14,6,7],[2,8,7],[2,3,8],[14,7,8],[14,8,15],[3,9,8],[15,8,9],[3,10,9],[3,4,10],[15,9,10],[15,10,16],[4,11,10],[16,10,11],[4,12,11],[4,1,12],[16,11,12],[16,12,13],[1,5,12],[13,12,5]]]);
|
||||
assert_approx(sphere(r=40,style="icosa"), [[[0,0,40],[28.0251707689,-20.3614784182,20],[28.0251707689,20.3614784182,20],[0,0,40],[28.0251707689,20.3614784182,20],[-10.7046626932,32.9455641419,20],[0,0,40],[-10.7046626932,32.9455641419,20],[-34.6410161514,6.66133814775e-15,20],[0,0,40],[-34.6410161514,0,20],[-10.7046626932,-32.9455641419,20],[0,0,40],[-10.7046626932,-32.9455641419,20],[28.0251707689,-20.3614784182,20],[34.6410161514,0,-20],[28.0251707689,-20.3614784182,20],[28.0251707689,20.3614784182,20],[10.7046626932,32.9455641419,-20],[28.0251707689,20.3614784182,20],[-10.7046626932,32.9455641419,20],[-28.0251707689,20.3614784182,-20],[-10.7046626932,32.9455641419,20],[-34.6410161514,-4.4408920985e-15,20],[-28.0251707689,-20.3614784182,-20],[-34.6410161514,1.11022302463e-15,20],[-10.7046626932,-32.9455641419,20],[10.7046626932,-32.9455641419,-20],[-10.7046626932,-32.9455641419,20],[28.0251707689,-20.3614784182,20],[0,0,-40],[-28.0251707689,20.3614784182,-20],[-28.0251707689,-20.3614784182,-20],[0,0,-40],[-28.0251707689,-20.3614784182,-20],[10.7046626932,-32.9455641419,-20],[0,0,-40],[10.7046626932,-32.9455641419,-20],[34.6410161514,-6.66133814775e-15,-20],[0,0,-40],[34.6410161514,0,-20],[10.7046626932,32.9455641419,-20],[0,0,-40],[10.7046626932,32.9455641419,-20],[-28.0251707689,20.3614784182,-20],[-34.6410161514,0,20],[-28.0251707689,20.3614784182,-20],[-28.0251707689,-20.3614784182,-20],[-10.7046626932,-32.9455641419,20],[-28.0251707689,-20.3614784182,-20],[10.7046626932,-32.9455641419,-20],[28.0251707689,-20.3614784182,20],[10.7046626932,-32.9455641419,-20],[34.6410161514,4.4408920985e-15,-20],[28.0251707689,20.3614784182,20],[34.6410161514,-1.11022302463e-15,-20],[10.7046626932,32.9455641419,-20],[-10.7046626932,32.9455641419,20],[10.7046626932,32.9455641419,-20],[-28.0251707689,20.3614784182,-20]],[[0,2,1],[3,5,4],[6,8,7],[9,11,10],[12,14,13],[16,17,15],[19,20,18],[22,23,21],[25,26,24],[28,29,27],[31,32,30],[34,35,33],[37,38,36],[40,41,39],[43,44,42],[45,47,46],[48,50,49],[51,53,52],[54,56,55],[57,59,58]]]);
|
||||
}
|
||||
test_sphere();
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
12
tests/test_regions.scad
Normal file
12
tests/test_regions.scad
Normal file
|
@ -0,0 +1,12 @@
|
|||
include<../std.scad>
|
||||
|
||||
module test_is_region() {
|
||||
assert(is_region([circle(d=10),square(10)]));
|
||||
assert(is_region([circle(d=10),square(10),circle(d=50)]));
|
||||
assert(is_region([square(10)]));
|
||||
assert(!is_region([]));
|
||||
assert(!is_region(23));
|
||||
assert(!is_region(true));
|
||||
assert(!is_region("foo"));
|
||||
}
|
||||
test_is_region();
|
|
@ -1,6 +1,29 @@
|
|||
include <../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]]);
|
||||
}
|
||||
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(is_polygon_clockwise(circle(d=200)));
|
||||
assert(is_polygon_clockwise(circle(r=100)));
|
||||
assert(len(circle(d=100,$fn=6)) == 6);
|
||||
assert(len(circle(d=100,$fn=36)) == 36);
|
||||
}
|
||||
test_circle();
|
||||
|
||||
|
||||
|
||||
module test_rect() {
|
||||
|
|
|
@ -1,6 +1,44 @@
|
|||
include <../std.scad>
|
||||
include <../hull.scad>
|
||||
|
||||
|
||||
module test_cube() {
|
||||
assert_equal(cube(100,center=true), [[[-50,-50,-50],[50,-50,-50],[50,50,-50],[-50,50,-50],[-50,-50,50],[50,-50,50],[50,50,50],[-50,50,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],center=true), [[[-30,-40,-50],[30,-40,-50],[30,40,-50],[-30,40,-50],[-30,-40,50],[30,-40,50],[30,40,50],[-30,40,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=CENTER), [[[-30,-40,-50],[30,-40,-50],[30,40,-50],[-30,40,-50],[-30,-40,50],[30,-40,50],[30,40,50],[-30,40,50]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],center=false), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100]), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=ALLNEG), [[[0,0,0],[60,0,0],[60,80,0],[0,80,0],[0,0,100],[60,0,100],[60,80,100],[0,80,100]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
assert_equal(cube([60,80,100],anchor=TOP), [[[-30,-40,-100],[30,-40,-100],[30,40,-100],[-30,40,-100],[-30,-40,0],[30,-40,0],[30,40,0],[-30,40,0]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[6,4,7],[6,5,4]]]);
|
||||
}
|
||||
test_cube();
|
||||
|
||||
|
||||
module test_cylinder() {
|
||||
$fn=12;
|
||||
assert_approx(cylinder(r=40,h=100,center=true), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,center=true), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,anchor=CENTER), [[[40,0,-50],[34.6410161514,-20,-50],[20,-34.6410161514,-50],[0,-40,-50],[-20,-34.6410161514,-50],[-34.6410161514,-20,-50],[-40,0,-50],[-34.6410161514,20,-50],[-20,34.6410161514,-50],[0,40,-50],[20,34.6410161514,-50],[34.6410161514,20,-50],[40,0,50],[34.6410161514,-20,50],[20,-34.6410161514,50],[0,-40,50],[-20,-34.6410161514,50],[-34.6410161514,-20,50],[-40,0,50],[-34.6410161514,20,50],[-20,34.6410161514,50],[0,40,50],[20,34.6410161514,50],[34.6410161514,20,50]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,center=false), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100,anchor=BOT), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
assert_approx(cylinder(d=80,h=100), [[[40,0,0],[34.6410161514,-20,0],[20,-34.6410161514,0],[0,-40,0],[-20,-34.6410161514,0],[-34.6410161514,-20,0],[-40,0,0],[-34.6410161514,20,0],[-20,34.6410161514,0],[0,40,0],[20,34.6410161514,0],[34.6410161514,20,0],[40,0,100],[34.6410161514,-20,100],[20,-34.6410161514,100],[0,-40,100],[-20,-34.6410161514,100],[-34.6410161514,-20,100],[-40,0,100],[-34.6410161514,20,100],[-20,34.6410161514,100],[0,40,100],[20,34.6410161514,100],[34.6410161514,20,100]],[[11,10,9,8,7,6,5,4,3,2,1,0],[0,13,12],[1,14,13],[2,15,14],[3,16,15],[4,17,16],[5,18,17],[6,19,18],[7,20,19],[8,21,20],[9,22,21],[10,23,22],[11,12,23],[0,1,13],[1,2,14],[2,3,15],[3,4,16],[4,5,17],[5,6,18],[6,7,19],[7,8,20],[8,9,21],[9,10,22],[10,11,23],[11,0,12],[12,13,14,15,16,17,18,19,20,21,22,23]]]);
|
||||
}
|
||||
test_cylinder();
|
||||
|
||||
|
||||
module test_sphere() {
|
||||
$fn=6;
|
||||
assert_approx(sphere(r=40), [[[20,0,34.6410161514],[10,17.3205080757,34.6410161514],[-10,17.3205080757,34.6410161514],[-20,0,34.6410161514],[-10,-17.3205080757,34.6410161514],[10,-17.3205080757,34.6410161514],[40,0,0],[20,34.6410161514,0],[-20,34.6410161514,0],[-40,0,0],[-20,-34.6410161514,0],[20,-34.6410161514,0],[20,0,-34.6410161514],[10,17.3205080757,-34.6410161514],[-10,17.3205080757,-34.6410161514],[-20,0,-34.6410161514],[-10,-17.3205080757,-34.6410161514],[10,-17.3205080757,-34.6410161514]],[[5,4,3,2,1,0],[12,13,14,15,16,17],[6,0,1],[6,1,7],[7,1,2],[7,2,8],[8,2,3],[8,3,9],[9,3,4],[9,4,10],[10,4,5],[10,5,11],[11,5,0],[11,0,6],[12,6,7],[12,7,13],[13,7,8],[13,8,14],[14,8,9],[14,9,15],[15,9,10],[15,10,16],[16,10,11],[16,11,17],[17,11,6],[17,6,12]]]);
|
||||
assert_approx(sphere(r=40,style="orig"), [[[20,0,34.6410161514],[10,17.3205080757,34.6410161514],[-10,17.3205080757,34.6410161514],[-20,0,34.6410161514],[-10,-17.3205080757,34.6410161514],[10,-17.3205080757,34.6410161514],[40,0,0],[20,34.6410161514,0],[-20,34.6410161514,0],[-40,0,0],[-20,-34.6410161514,0],[20,-34.6410161514,0],[20,0,-34.6410161514],[10,17.3205080757,-34.6410161514],[-10,17.3205080757,-34.6410161514],[-20,0,-34.6410161514],[-10,-17.3205080757,-34.6410161514],[10,-17.3205080757,-34.6410161514]],[[5,4,3,2,1,0],[12,13,14,15,16,17],[6,0,1],[6,1,7],[7,1,2],[7,2,8],[8,2,3],[8,3,9],[9,3,4],[9,4,10],[10,4,5],[10,5,11],[11,5,0],[11,0,6],[12,6,7],[12,7,13],[13,7,8],[13,8,14],[14,8,9],[14,9,15],[15,9,10],[15,10,16],[16,10,11],[16,11,17],[17,11,6],[17,6,12]]]);
|
||||
assert_approx(sphere(r=40,style="aligned"), [[[0,0,40],[34.6410161514,0,20],[17.3205080757,30,20],[-17.3205080757,30,20],[-34.6410161514,0,20],[-17.3205080757,-30,20],[17.3205080757,-30,20],[34.6410161514,0,-20],[17.3205080757,30,-20],[-17.3205080757,30,-20],[-34.6410161514,0,-20],[-17.3205080757,-30,-20],[17.3205080757,-30,-20],[0,0,-40]],[[1,0,2],[13,7,8],[2,0,3],[13,8,9],[3,0,4],[13,9,10],[4,0,5],[13,10,11],[5,0,6],[13,11,12],[6,0,1],[13,12,7],[1,2,8],[1,8,7],[2,3,9],[2,9,8],[3,4,10],[3,10,9],[4,5,11],[4,11,10],[5,6,12],[5,12,11],[6,1,7],[6,7,12]]]);
|
||||
assert_approx(sphere(r=40,style="stagger"), [[[0,0,40],[30,17.3205080757,20],[0,34.6410161514,20],[-30,17.3205080757,20],[-30,-17.3205080757,20],[0,-34.6410161514,20],[30,-17.3205080757,20],[34.6410161514,0,-20],[17.3205080757,30,-20],[-17.3205080757,30,-20],[-34.6410161514,0,-20],[-17.3205080757,-30,-20],[17.3205080757,-30,-20],[0,0,-40]],[[1,0,2],[13,7,8],[2,0,3],[13,8,9],[3,0,4],[13,9,10],[4,0,5],[13,10,11],[5,0,6],[13,11,12],[6,0,1],[13,12,7],[1,2,8],[1,8,7],[2,3,9],[2,9,8],[3,4,10],[3,10,9],[4,5,11],[4,11,10],[5,6,12],[5,12,11],[6,1,7],[6,7,12]]]);
|
||||
assert_approx(sphere(r=40,style="octa"), [[[0,0,40],[28.2842712475,0,28.2842712475],[0,28.2842712475,28.2842712475],[-28.2842712475,0,28.2842712475],[0,-28.2842712475,28.2842712475],[40,0,0],[28.2842712475,28.2842712475,0],[0,40,0],[-28.2842712475,28.2842712475,0],[-40,0,0],[-28.2842712475,-28.2842712475,0],[0,-40,0],[28.2842712475,-28.2842712475,0],[28.2842712475,0,-28.2842712475],[0,28.2842712475,-28.2842712475],[-28.2842712475,0,-28.2842712475],[0,-28.2842712475,-28.2842712475],[0,0,-40]],[[0,2,1],[0,3,2],[0,4,3],[0,1,4],[17,15,16],[17,14,15],[17,13,14],[17,16,13],[1,6,5],[1,2,6],[13,5,6],[13,6,14],[2,7,6],[14,6,7],[2,8,7],[2,3,8],[14,7,8],[14,8,15],[3,9,8],[15,8,9],[3,10,9],[3,4,10],[15,9,10],[15,10,16],[4,11,10],[16,10,11],[4,12,11],[4,1,12],[16,11,12],[16,12,13],[1,5,12],[13,12,5]]]);
|
||||
assert_approx(sphere(r=40,style="icosa"), [[[0,0,40],[28.0251707689,-20.3614784182,20],[28.0251707689,20.3614784182,20],[0,0,40],[28.0251707689,20.3614784182,20],[-10.7046626932,32.9455641419,20],[0,0,40],[-10.7046626932,32.9455641419,20],[-34.6410161514,6.66133814775e-15,20],[0,0,40],[-34.6410161514,0,20],[-10.7046626932,-32.9455641419,20],[0,0,40],[-10.7046626932,-32.9455641419,20],[28.0251707689,-20.3614784182,20],[34.6410161514,0,-20],[28.0251707689,-20.3614784182,20],[28.0251707689,20.3614784182,20],[10.7046626932,32.9455641419,-20],[28.0251707689,20.3614784182,20],[-10.7046626932,32.9455641419,20],[-28.0251707689,20.3614784182,-20],[-10.7046626932,32.9455641419,20],[-34.6410161514,-4.4408920985e-15,20],[-28.0251707689,-20.3614784182,-20],[-34.6410161514,1.11022302463e-15,20],[-10.7046626932,-32.9455641419,20],[10.7046626932,-32.9455641419,-20],[-10.7046626932,-32.9455641419,20],[28.0251707689,-20.3614784182,20],[0,0,-40],[-28.0251707689,20.3614784182,-20],[-28.0251707689,-20.3614784182,-20],[0,0,-40],[-28.0251707689,-20.3614784182,-20],[10.7046626932,-32.9455641419,-20],[0,0,-40],[10.7046626932,-32.9455641419,-20],[34.6410161514,-6.66133814775e-15,-20],[0,0,-40],[34.6410161514,0,-20],[10.7046626932,32.9455641419,-20],[0,0,-40],[10.7046626932,32.9455641419,-20],[-28.0251707689,20.3614784182,-20],[-34.6410161514,0,20],[-28.0251707689,20.3614784182,-20],[-28.0251707689,-20.3614784182,-20],[-10.7046626932,-32.9455641419,20],[-28.0251707689,-20.3614784182,-20],[10.7046626932,-32.9455641419,-20],[28.0251707689,-20.3614784182,20],[10.7046626932,-32.9455641419,-20],[34.6410161514,4.4408920985e-15,-20],[28.0251707689,20.3614784182,20],[34.6410161514,-1.11022302463e-15,-20],[10.7046626932,32.9455641419,-20],[-10.7046626932,32.9455641419,20],[10.7046626932,32.9455641419,-20],[-28.0251707689,20.3614784182,-20]],[[0,2,1],[3,5,4],[6,8,7],[9,11,10],[12,14,13],[16,17,15],[19,20,18],[22,23,21],[25,26,24],[28,29,27],[31,32,30],[34,35,33],[37,38,36],[40,41,39],[43,44,42],[45,47,46],[48,50,49],[51,53,52],[54,56,55],[57,59,58]]]);
|
||||
}
|
||||
test_sphere();
|
||||
|
||||
|
||||
|
||||
module test_prismoid() {
|
||||
$fn=24;
|
||||
assert_approx(prismoid([100,80],[50,40],h=50), [[[25,20,50],[25,-20,50],[-25,-20,50],[-25,20,50],[50,40,0],[50,-40,0],[-50,-40,0],[-50,40,0]],[[0,1,2],[0,2,3],[0,4,5],[0,5,1],[1,5,6],[1,6,2],[2,6,7],[2,7,3],[3,7,4],[3,4,0],[4,7,6],[4,6,5]]]);
|
||||
|
|
|
@ -81,11 +81,18 @@ test_vnf_centroid();
|
|||
|
||||
module test_vnf_volume() {
|
||||
assert_approx(vnf_volume(cube(100, center=false)), 1000000);
|
||||
assert(approx(vnf_volume(sphere(d=100, anchor=BOT, $fn=144)), 4/3*PI*pow(50,3), eps=1e3));
|
||||
assert(approx(vnf_volume(sphere(d=100, anchor=BOT, $fn=144)) / (4/3*PI*pow(50,3)),1, eps=.001));
|
||||
}
|
||||
test_vnf_volume();
|
||||
|
||||
|
||||
|
||||
module test_vnf_area(){
|
||||
assert(approx(vnf_area(sphere(d=100, $fn=144)) / (4*PI*50*50),1, eps=1e-3));
|
||||
}
|
||||
test_vnf_area();
|
||||
|
||||
|
||||
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]]);
|
||||
|
|
|
@ -96,7 +96,7 @@ function law_of_sines(a, A, b, B) =
|
|||
// p1 = The first vertex of the triangle.
|
||||
// p2 = The second vertex of the triangle.
|
||||
// p3 = The third vertex of the triangle.
|
||||
// Examples:
|
||||
// Example:
|
||||
// triangle_area([0,0], [5,10], [10,0]); // Returns -50
|
||||
// triangle_area([10,0], [5,10], [0,0]); // Returns 50
|
||||
function triangle_area(p1,p2,p3) =
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: common.scad
|
||||
// Common functions used in argument processing.
|
||||
// LibFile: utility.scad
|
||||
// Utility functions used in argument processing.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -18,7 +18,7 @@
|
|||
// Description:
|
||||
// Returns a string representing the type of the value. One of "undef", "boolean", "number", "nan", "string", "list", "range", "function" or "invalid".
|
||||
// Some malformed "ranges", like '[0:NAN:INF]' and '[0:"a":INF]', may be classified as "undef" or "invalid".
|
||||
// Examples:
|
||||
// Example:
|
||||
// typ = typeof(undef); // Returns: "undef"
|
||||
// typ = typeof(true); // Returns: "boolean"
|
||||
// typ = typeof(42); // Returns: "number"
|
||||
|
@ -294,7 +294,7 @@ function default(v,dflt=undef) = is_undef(v)? dflt : v;
|
|||
// Arguments:
|
||||
// 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.
|
||||
// Examples:
|
||||
// Example:
|
||||
// val = first_defined([undef,7,undef,true]); // Returns: 7
|
||||
function first_defined(v,recursive=false,_i=0) =
|
||||
_i<len(v) && (
|
||||
|
@ -321,9 +321,9 @@ function first_defined(v,recursive=false,_i=0) =
|
|||
// vals = The values to return the first one which is not `undef`.
|
||||
// names = A string with comma-separated names for the arguments whose values are passed in `vals`.
|
||||
// dflt = If given, the value returned if all `vals` are `undef`.
|
||||
// Examples:
|
||||
// length = one_defined([length,L,l], ["length","L","l"]);
|
||||
// length = one_defined([length,L,l], "length,L,l", dflt=1);
|
||||
// Example:
|
||||
// length1 = one_defined([length,L,l], ["length","L","l"]);
|
||||
// length2 = one_defined([length,L,l], "length,L,l", dflt=1);
|
||||
|
||||
function one_defined(vals, names, dflt=_UNDEF) =
|
||||
let(
|
||||
|
@ -420,13 +420,13 @@ function all_defined(v,recursive=false) =
|
|||
// center = If not `undef`, this overrides the value of `anchor`.
|
||||
// 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`
|
||||
// Examples:
|
||||
// anchr = get_anchor(undef, undef, BOTTOM, TOP); // Returns: [0, 0, 1] (TOP)
|
||||
// anchr = get_anchor(RIGHT, undef, BOTTOM, TOP); // Returns: [1, 0, 0] (RIGHT)
|
||||
// anchr = get_anchor(undef, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM)
|
||||
// anchr = get_anchor(RIGHT, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM)
|
||||
// anchr = get_anchor(undef, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER)
|
||||
// anchr = get_anchor(RIGHT, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER)
|
||||
// Example:
|
||||
// anchr1 = get_anchor(undef, undef, BOTTOM, TOP); // Returns: [0, 0, 1] (TOP)
|
||||
// anchr2 = get_anchor(RIGHT, undef, BOTTOM, TOP); // Returns: [1, 0, 0] (RIGHT)
|
||||
// anchr3 = get_anchor(undef, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM)
|
||||
// anchr4 = get_anchor(RIGHT, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM)
|
||||
// anchr5 = get_anchor(undef, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER)
|
||||
// anchr6 = get_anchor(RIGHT, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER)
|
||||
function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) =
|
||||
!is_undef(center)? (center? CENTER : uncentered) :
|
||||
!is_undef(anchor)? anchor :
|
||||
|
@ -454,7 +454,7 @@ function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) =
|
|||
// d2 = Second most specific diameter.
|
||||
// d = Most general diameter.
|
||||
// dflt = Value to return if all other values given are `undef`.
|
||||
// Examples:
|
||||
// Example:
|
||||
// r = get_radius(r1=undef, r=undef, dflt=undef); // Returns: undef
|
||||
// r = get_radius(r1=undef, r=undef, dflt=1); // Returns: 1
|
||||
// r = get_radius(r1=undef, r=6, dflt=1); // Returns: 6
|
||||
|
@ -488,6 +488,8 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) =
|
|||
// Topics: Argument Handling
|
||||
// See Also: get_anchor(), get_radius(), force_list()
|
||||
// Description:
|
||||
// This is expands a scalar or a list with length less than 3 to a length 3 vector in the
|
||||
// same way that OpenSCAD expands short vectors in some contexts, e.g. cube(10) or rotate([45,90]).
|
||||
// If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`.
|
||||
// If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`.
|
||||
// If `v` is a vector, returns the first 3 items, with any missing values replaced by `dflt`.
|
||||
|
@ -495,7 +497,7 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) =
|
|||
// Arguments:
|
||||
// v = Value to return vector from.
|
||||
// dflt = Default value to set empty vector parts from.
|
||||
// Examples:
|
||||
// Example:
|
||||
// vec = scalar_vec3(undef); // Returns: undef
|
||||
// vec = scalar_vec3(10); // Returns: [10,10,10]
|
||||
// vec = scalar_vec3(10,1); // Returns: [10,1,1]
|
||||
|
@ -514,7 +516,7 @@ function scalar_vec3(v, dflt) =
|
|||
// Calculate the standard number of sides OpenSCAD would give a circle based on `$fn`, `$fa`, and `$fs`.
|
||||
// Arguments:
|
||||
// r = Radius of circle to get the number of segments for.
|
||||
// Examples:
|
||||
// Example:
|
||||
// $fn=12; sides=segs(10); // Returns: 12
|
||||
// $fa=2; $fs=3, sides=segs(10); // Returns: 21
|
||||
function segs(r) =
|
42
vectors.scad
42
vectors.scad
|
@ -163,13 +163,13 @@ function pointlist_bounds(pts) =
|
|||
// Arguments:
|
||||
// v = The vector to normalize.
|
||||
// error = If given, and input is a zero-length vector, this value is returned. Default: Assert error on zero-length vector.
|
||||
// Examples:
|
||||
// unit([10,0,0]); // Returns: [1,0,0]
|
||||
// unit([0,10,0]); // Returns: [0,1,0]
|
||||
// unit([0,0,10]); // Returns: [0,0,1]
|
||||
// unit([0,-10,0]); // Returns: [0,-1,0]
|
||||
// unit([0,0,0],[1,2,3]); // Returns: [1,2,3]
|
||||
// unit([0,0,0]); // Asserts an error.
|
||||
// Example:
|
||||
// v1 = unit([10,0,0]); // Returns: [1,0,0]
|
||||
// v2 = unit([0,10,0]); // Returns: [0,1,0]
|
||||
// v3 = unit([0,0,10]); // Returns: [0,0,1]
|
||||
// v4 = unit([0,-10,0]); // Returns: [0,-1,0]
|
||||
// v5 = unit([0,0,0],[1,2,3]); // Returns: [1,2,3]
|
||||
// v6 = unit([0,0,0]); // Asserts an error.
|
||||
function unit(v, error=[[["ASSERT"]]]) =
|
||||
assert(is_vector(v), str("Expected a vector. Got: ",v))
|
||||
norm(v)<EPSILON? (error==[[["ASSERT"]]]? assert(norm(v)>=EPSILON,"Tried to normalize a zero vector") : error) :
|
||||
|
@ -191,13 +191,13 @@ function unit(v, error=[[["ASSERT"]]]) =
|
|||
// v1 = First vector or point.
|
||||
// v2 = Second vector or point.
|
||||
// v3 = Third point in three point mode.
|
||||
// Examples:
|
||||
// vector_angle(UP,LEFT); // Returns: 90
|
||||
// vector_angle(RIGHT,LEFT); // Returns: 180
|
||||
// vector_angle(UP+RIGHT,RIGHT); // Returns: 45
|
||||
// vector_angle([10,10], [0,0], [10,-10]); // Returns: 90
|
||||
// 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
|
||||
// Example:
|
||||
// ang1 = vector_angle(UP,LEFT); // Returns: 90
|
||||
// ang2 = vector_angle(RIGHT,LEFT); // Returns: 180
|
||||
// ang3 = vector_angle(UP+RIGHT,RIGHT); // Returns: 45
|
||||
// ang4 = vector_angle([10,10], [0,0], [10,-10]); // Returns: 90
|
||||
// ang5 = vector_angle([10,0,10], [0,0,0], [-10,10,0]); // Returns: 120
|
||||
// ang6 = vector_angle([[10,0,10], [0,0,0], [-10,10,0]]); // Returns: 120
|
||||
function vector_angle(v1,v2,v3) =
|
||||
assert( ( is_undef(v3) && ( is_undef(v2) || same_shape(v1,v2) ) )
|
||||
|| is_consistent([v1,v2,v3]) ,
|
||||
|
@ -233,13 +233,13 @@ function vector_angle(v1,v2,v3) =
|
|||
// v1 = First vector or point.
|
||||
// v2 = Second vector or point.
|
||||
// v3 = Third point in three point mode.
|
||||
// Examples:
|
||||
// vector_axis(UP,LEFT); // Returns: [0,-1,0] (FWD)
|
||||
// vector_axis(RIGHT,LEFT); // Returns: [0,-1,0] (FWD)
|
||||
// vector_axis(UP+RIGHT,RIGHT); // Returns: [0,1,0] (BACK)
|
||||
// vector_axis([10,10], [0,0], [10,-10]); // Returns: [0,0,-1] (DOWN)
|
||||
// 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]
|
||||
// Example:
|
||||
// axis1 = vector_axis(UP,LEFT); // Returns: [0,-1,0] (FWD)
|
||||
// axis2 = vector_axis(RIGHT,LEFT); // Returns: [0,-1,0] (FWD)
|
||||
// axis3 = vector_axis(UP+RIGHT,RIGHT); // Returns: [0,1,0] (BACK)
|
||||
// axis4 = vector_axis([10,10], [0,0], [10,-10]); // Returns: [0,0,-1] (DOWN)
|
||||
// axis5 = vector_axis([10,0,10], [0,0,0], [-10,10,0]); // Returns: [-0.57735, -0.57735, 0.57735]
|
||||
// axis6 = 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_vector(v3)
|
||||
? assert(is_consistent([v3,v2,v1]), "Bad arguments.")
|
||||
|
|
115
vnf.scad
115
vnf.scad
|
@ -21,63 +21,6 @@
|
|||
EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||
|
||||
|
||||
// Function: is_vnf()
|
||||
// Usage:
|
||||
// bool = is_vnf(x);
|
||||
// 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]));
|
||||
|
||||
|
||||
// Function: is_vnf_list()
|
||||
// Description: Returns true if the given value looks passingly like a list of VNF structures.
|
||||
function is_vnf_list(x) = is_list(x) && all([for (v=x) is_vnf(v)]);
|
||||
|
||||
|
||||
// Function: vnf_vertices()
|
||||
// Description: Given a VNF structure, returns the list of vertex points.
|
||||
function vnf_vertices(vnf) = vnf[0];
|
||||
|
||||
|
||||
// Function: vnf_faces()
|
||||
// Description: Given a VNF structure, returns the list of faces, where each face is a list of indices into the VNF vertex list.
|
||||
function vnf_faces(vnf) = vnf[1];
|
||||
|
||||
|
||||
// Function: vnf_get_vertex()
|
||||
// Usage:
|
||||
// vvnf = vnf_get_vertex(vnf, p);
|
||||
// Description:
|
||||
// Finds the index number of the given vertex point `p` in the given VNF structure `vnf`.
|
||||
// If said point does not already exist in the VNF vertex list, it is added to the returned VNF.
|
||||
// Returns: `[INDEX, VNF]` where INDEX is the index of the point in the returned VNF's vertex list,
|
||||
// and VNF is the possibly modified new VNF structure. If `p` is given as a list of points, then
|
||||
// the returned INDEX will be a list of indices.
|
||||
// Arguments:
|
||||
// vnf = The VNF structue to get the point index from.
|
||||
// p = The point, or list of points to get the index of.
|
||||
// Example:
|
||||
// vnf1 = vnf_get_vertex(p=[3,5,8]); // Returns: [0, [[[3,5,8]],[]]]
|
||||
// vnf2 = vnf_get_vertex(vnf1, p=[3,2,1]); // Returns: [1, [[[3,5,8],[3,2,1]],[]]]
|
||||
// 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(
|
||||
isvec = is_vector(p),
|
||||
pts = isvec? [p] : p,
|
||||
res = set_union(vnf[0], pts, get_indices=true)
|
||||
) [
|
||||
(isvec? res[0][0] : res[0]),
|
||||
[ res[1], vnf[1] ]
|
||||
];
|
||||
|
||||
|
||||
// Section: Constructing VNFs
|
||||
|
||||
// Function: vnf_vertex_array()
|
||||
|
@ -438,6 +381,63 @@ function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
|
|||
[nverts, nfaces];
|
||||
|
||||
|
||||
// Function: is_vnf()
|
||||
// Usage:
|
||||
// bool = is_vnf(x);
|
||||
// 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]));
|
||||
|
||||
|
||||
// Function: is_vnf_list()
|
||||
// Description: Returns true if the given value looks passingly like a list of VNF structures.
|
||||
function is_vnf_list(x) = is_list(x) && all([for (v=x) is_vnf(v)]);
|
||||
|
||||
|
||||
// Function: vnf_vertices()
|
||||
// Description: Given a VNF structure, returns the list of vertex points.
|
||||
function vnf_vertices(vnf) = vnf[0];
|
||||
|
||||
|
||||
// Function: vnf_faces()
|
||||
// Description: Given a VNF structure, returns the list of faces, where each face is a list of indices into the VNF vertex list.
|
||||
function vnf_faces(vnf) = vnf[1];
|
||||
|
||||
|
||||
// Function: vnf_get_vertex()
|
||||
// Usage:
|
||||
// vvnf = vnf_get_vertex(vnf, p);
|
||||
// Description:
|
||||
// Finds the index number of the given vertex point `p` in the given VNF structure `vnf`.
|
||||
// If said point does not already exist in the VNF vertex list, it is added to the returned VNF.
|
||||
// Returns: `[INDEX, VNF]` where INDEX is the index of the point in the returned VNF's vertex list,
|
||||
// and VNF is the possibly modified new VNF structure. If `p` is given as a list of points, then
|
||||
// the returned INDEX will be a list of indices.
|
||||
// Arguments:
|
||||
// vnf = The VNF structue to get the point index from.
|
||||
// p = The point, or list of points to get the index of.
|
||||
// Example:
|
||||
// vnf1 = vnf_get_vertex(p=[3,5,8]); // Returns: [0, [[[3,5,8]],[]]]
|
||||
// vnf2 = vnf_get_vertex(vnf1, p=[3,2,1]); // Returns: [1, [[[3,5,8],[3,2,1]],[]]]
|
||||
// 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(
|
||||
isvec = is_vector(p),
|
||||
pts = isvec? [p] : p,
|
||||
res = set_union(vnf[0], pts, get_indices=true)
|
||||
) [
|
||||
(isvec? res[0][0] : res[0]),
|
||||
[ res[1], vnf[1] ]
|
||||
];
|
||||
|
||||
|
||||
|
||||
// Section: Altering the VNF Internals
|
||||
|
||||
|
@ -963,6 +963,7 @@ function _split_polygons_at_each_y(polys, ys, _i=0) =
|
|||
// bad edges and vertices, overlaid on a transparent gray polyhedron of the VNF.
|
||||
// .
|
||||
// Currently checks for these problems:
|
||||
// .
|
||||
// Type | Color | Code | Message
|
||||
// ------- | -------- | ------------ | ---------------------------------
|
||||
// WARNING | Yellow | BIG_FACE | Face has more than 3 vertices, and may confuse CGAL.
|
||||
|
|
Loading…
Reference in a new issue