mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 00:09:41 +00:00
Examples fix
merge primitives stuff into shapes*.scad move text commands to shapes3d.scad rename common.scad
This commit is contained in:
parent
e6a2ee2084
commit
935a113fcf
15 changed files with 654 additions and 660 deletions
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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],
|
||||
|
|
176
paths.scad
176
paths.scad
|
@ -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
|
|
@ -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=])
|
||||
|
|
493
shapes3d.scad
493
shapes3d.scad
|
@ -8,6 +8,78 @@
|
|||
|
||||
// Section: Cuboids
|
||||
|
||||
// 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()
|
||||
//
|
||||
// Usage: Standard Cubes
|
||||
|
@ -807,6 +879,105 @@ function right_triangle(size=[1,1,1], center, anchor, spin=0, orient=UP) =
|
|||
// Section: Cylindroids
|
||||
|
||||
|
||||
|
||||
|
||||
// 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()
|
||||
//
|
||||
// Description:
|
||||
|
@ -1331,6 +1502,61 @@ module torus(
|
|||
// Section: Spheroid
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Function&Module: spheroid()
|
||||
// Usage: Typical
|
||||
// spheroid(r|d, [circum], [style]);
|
||||
|
@ -1697,6 +1923,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
|
||||
|
||||
|
|
2
std.scad
2
std.scad
|
@ -34,7 +34,7 @@ include <regions.scad>
|
|||
include <strings.scad>
|
||||
include <skin.scad>
|
||||
include <vnf.scad>
|
||||
include <common.scad>
|
||||
include <utility.scad>
|
||||
include <debug.scad>
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
@ -731,17 +731,17 @@ 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();
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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]]]);
|
||||
|
|
|
@ -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>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -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`.
|
Loading…
Reference in a new issue