mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Removed overrides for square() and circle() builtin modules.
This commit is contained in:
parent
104a43bd1f
commit
ff96db86d2
7 changed files with 357 additions and 323 deletions
|
@ -729,7 +729,7 @@ function reorient(
|
||||||
//
|
//
|
||||||
// Example(NORENDER): Spherical Shape
|
// Example(NORENDER): Spherical Shape
|
||||||
// attachable(anchor, spin, orient, r=r) {
|
// attachable(anchor, spin, orient, r=r) {
|
||||||
// staggered_sphere(r=r);
|
// sphere(r=r);
|
||||||
// children();
|
// children();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
|
@ -2,7 +2,7 @@ include <BOSL2/std.scad>
|
||||||
include <BOSL2/debug.scad>
|
include <BOSL2/debug.scad>
|
||||||
|
|
||||||
|
|
||||||
sphere(d=30) show_anchors();
|
spheroid(d=30) show_anchors();
|
||||||
|
|
||||||
|
|
||||||
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
253
primitives.scad
253
primitives.scad
|
@ -14,138 +14,59 @@
|
||||||
|
|
||||||
// Function&Module: square()
|
// Function&Module: square()
|
||||||
// Usage:
|
// Usage:
|
||||||
// square(size, [center], [rounding], [chamfer], [anchor], [spin])
|
// square(size, [center])
|
||||||
// Description:
|
// Description:
|
||||||
// When called as a module, creates a 2D square of the given size, with optional rounding or chamfering.
|
// 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.
|
// When called as a function, returns a 2D path/list of points for a square/rectangle of the given size.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// size = The size of the square to create. If given as a scalar, both X and Y will be the same size.
|
// size = The size of the square to create. If given as a scalar, both X and Y will be the same size.
|
||||||
// rounding = The rounding radius for the corners. If given as a list of four numbers, gives individual radii for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no rounding)
|
|
||||||
// chamfer = The chamfer size for the corners. If given as a list of four numbers, gives individual chamfers for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no chamfer)
|
|
||||||
// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`.
|
// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`.
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
// anchor = (Function only) 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`
|
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
// Example(2D):
|
// Example(2D):
|
||||||
// square(40);
|
// square(40);
|
||||||
// Example(2D): Centered
|
// Example(2D): Centered
|
||||||
// square([40,30], center=true);
|
// square([40,30], center=true);
|
||||||
// Example(2D): Anchored
|
|
||||||
// square([40,30], anchor=FRONT);
|
|
||||||
// Example(2D): Spun
|
|
||||||
// square([40,30], anchor=FRONT, spin=30);
|
|
||||||
// Example(2D): Chamferred Rect
|
|
||||||
// square([40,30], chamfer=5, center=true);
|
|
||||||
// Example(2D): Rounded Rect
|
|
||||||
// square([40,30], rounding=5, center=true);
|
|
||||||
// Example(2D): Mixed Chamferring and Rounding
|
|
||||||
// square([40,30],center=true,rounding=[5,0,10,0],chamfer=[0,8,0,15],$fa=1,$fs=1);
|
|
||||||
// Example(2D): Called as Function
|
// Example(2D): Called as Function
|
||||||
// path = square([40,30], chamfer=5, anchor=FRONT, spin=30);
|
// path = square([40,30], anchor=FRONT, spin=30);
|
||||||
// stroke(path, closed=true);
|
// stroke(path, closed=true);
|
||||||
// move_copies(path) color("blue") circle(d=2,$fn=8);
|
// move_copies(path) color("blue") circle(d=2,$fn=8);
|
||||||
module square(size=1, center, rounding=0, chamfer=0, anchor, spin=0) {
|
function square(size=1, center, anchor, spin=0) =
|
||||||
size = is_num(size)? [size,size] : point2d(size);
|
|
||||||
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT);
|
|
||||||
pts = square(size=size, rounding=rounding, chamfer=chamfer, center=true);
|
|
||||||
attachable(anchor,spin, two_d=true, size=size) {
|
|
||||||
translate(-size/2) polygon(move(size/2,p=pts)); // Extraneous translation works around fine grid quantizing.
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function square(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
|
|
||||||
assert(is_num(size) || is_vector(size))
|
|
||||||
assert(is_num(chamfer) || len(chamfer)==4)
|
|
||||||
assert(is_num(rounding) || len(rounding)==4)
|
|
||||||
let(
|
let(
|
||||||
|
anchor = get_anchor(anchor, center, [-1,-1], [-1,-1]),
|
||||||
size = is_num(size)? [size,size] : point2d(size),
|
size = is_num(size)? [size,size] : point2d(size),
|
||||||
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT),
|
|
||||||
complex = rounding!=0 || chamfer!=0
|
|
||||||
)
|
|
||||||
(rounding==0 && chamfer==0)? let(
|
|
||||||
path = [
|
path = [
|
||||||
[ size.x/2, -size.y/2],
|
[ size.x,-size.y],
|
||||||
[-size.x/2, -size.y/2],
|
[-size.x,-size.y],
|
||||||
[-size.x/2, size.y/2],
|
[-size.x, size.y],
|
||||||
[ size.x/2, size.y/2]
|
[ size.x, size.y]
|
||||||
]
|
] / 2
|
||||||
) rot(spin, p=move(-vmul(anchor,size/2), p=path)) :
|
) reorient(anchor,spin, two_d=true, size=size, p=path);
|
||||||
let(
|
|
||||||
chamfer = is_list(chamfer)? chamfer : [for (i=[0:3]) chamfer],
|
|
||||||
rounding = is_list(rounding)? rounding : [for (i=[0:3]) rounding],
|
|
||||||
quadorder = [3,2,1,0],
|
|
||||||
quadpos = [[1,1],[-1,1],[-1,-1],[1,-1]],
|
|
||||||
insets = [for (i=[0:3]) chamfer[i]>0? chamfer[i] : rounding[i]>0? rounding[i] : 0],
|
|
||||||
insets_x = max(insets[0]+insets[1],insets[2]+insets[3]),
|
|
||||||
insets_y = max(insets[0]+insets[3],insets[1]+insets[2])
|
|
||||||
)
|
|
||||||
assert(insets_x <= size.x, "Requested roundings and/or chamfers exceed the square width.")
|
|
||||||
assert(insets_y <= size.y, "Requested roundings and/or chamfers exceed the square height.")
|
|
||||||
let(
|
|
||||||
path = [
|
|
||||||
for(i = [0:3])
|
|
||||||
let(
|
|
||||||
quad = quadorder[i],
|
|
||||||
inset = insets[quad],
|
|
||||||
cverts = quant(segs(inset),4)/4,
|
|
||||||
cp = vmul(size/2-[inset,inset], quadpos[quad]),
|
|
||||||
step = 90/cverts,
|
|
||||||
angs =
|
|
||||||
chamfer[quad] > 0? [0,-90]-90*[i,i] :
|
|
||||||
rounding[quad] > 0? [for (j=[0:1:cverts]) 360-j*step-i*90] :
|
|
||||||
[0]
|
|
||||||
)
|
|
||||||
each [for (a = angs) cp + inset*[cos(a),sin(a)]]
|
|
||||||
]
|
|
||||||
) complex?
|
|
||||||
reorient(anchor,spin, two_d=true, path=path, p=path) :
|
|
||||||
reorient(anchor,spin, two_d=true, size=size, p=path);
|
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: circle()
|
// Function&Module: circle()
|
||||||
// Usage:
|
// Usage:
|
||||||
// circle(r|d, [realign], [circum])
|
// circle(r|d)
|
||||||
// Description:
|
// Description:
|
||||||
// When called as a module, creates a 2D polygon that approximates a circle of the given size.
|
// 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.
|
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle of the given size.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// r = The radius of the circle to create.
|
// r = The radius of the circle to create.
|
||||||
// d = The diameter of the circle to create.
|
// d = The diameter of the circle to create.
|
||||||
// realign = If true, rotates the polygon that approximates the circle by half of one size.
|
// anchor = (Function only) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||||
// circum = If true, the polygon that approximates the circle will be upsized slightly to circumscribe the theoretical circle. If false, it inscribes the theoretical circle. Default: false
|
// spin = (Function only) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
// 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`
|
|
||||||
// Example(2D): By Radius
|
// Example(2D): By Radius
|
||||||
// circle(r=25);
|
// circle(r=25);
|
||||||
// Example(2D): By Diameter
|
// Example(2D): By Diameter
|
||||||
// circle(d=50);
|
// circle(d=50);
|
||||||
// Example(2D): Anchoring
|
|
||||||
// circle(d=50, anchor=FRONT);
|
|
||||||
// Example(2D): Spin
|
|
||||||
// circle(d=50, anchor=FRONT, spin=45);
|
|
||||||
// Example(NORENDER): Called as Function
|
// Example(NORENDER): Called as Function
|
||||||
// path = circle(d=50, anchor=FRONT, spin=45);
|
// path = circle(d=50, anchor=FRONT, spin=45);
|
||||||
module circle(r, d, realign=false, circum=false, anchor=CENTER, spin=0) {
|
function circle(r, d, anchor=CENTER, spin=0) =
|
||||||
r = get_radius(r=r, d=d, dflt=1);
|
|
||||||
sides = segs(r);
|
|
||||||
rr = circum? r/cos(180/sides) : r;
|
|
||||||
pts = circle(r=rr, realign=realign, $fn=sides);
|
|
||||||
attachable(anchor,spin, two_d=true, r=rr) {
|
|
||||||
polygon(pts);
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function circle(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
|
|
||||||
let(
|
let(
|
||||||
r = get_radius(r=r, d=d, dflt=1),
|
r = get_radius(r=r, d=d, dflt=1),
|
||||||
sides = segs(r),
|
sides = segs(r),
|
||||||
offset = realign? 180/sides : 0,
|
path = [for (i=[0:1:sides-1]) let(a=360-i*360/sides) r*[cos(a),sin(a)]]
|
||||||
rr = r / (circum? cos(180/sides) : 1),
|
) reorient(anchor,spin, two_d=true, r=r, p=path);
|
||||||
pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) rr*[cos(a),sin(a)]]
|
|
||||||
) reorient(anchor,spin, two_d=true, r=rr, p=pts);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,10 +106,11 @@ function circle(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
|
||||||
module cube(size=1, center, anchor, spin=0, orient=UP)
|
module cube(size=1, center, anchor, spin=0, orient=UP)
|
||||||
{
|
{
|
||||||
anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
|
anchor = get_anchor(anchor, center, ALLNEG, ALLNEG);
|
||||||
vnf = cube(size, center=true);
|
size = scalar_vec3(size);
|
||||||
siz = scalar_vec3(size);
|
attachable(anchor,spin,orient, size=size) {
|
||||||
attachable(anchor,spin,orient, size=siz) {
|
linear_extrude(height=size.z, center=true, convexity=2) {
|
||||||
vnf_polyhedron(vnf, convexity=2);
|
square([size.x,size.y], center=true);
|
||||||
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,9 +188,18 @@ module cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
|
||||||
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
|
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
|
||||||
l = first_defined([h, l, 1]);
|
l = first_defined([h, l, 1]);
|
||||||
sides = segs(max(r1,r2));
|
sides = segs(max(r1,r2));
|
||||||
vnf = cylinder(l=l, r1=r1, r2=r2, center=true);
|
|
||||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
||||||
vnf_polyhedron(vnf, convexity=2);
|
if(r1>r2) {
|
||||||
|
linear_extrude(height=l, center=true, convexity=2, scale=r2/r1) {
|
||||||
|
circle(r=r1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zflip() {
|
||||||
|
linear_extrude(height=l, center=true, convexity=2, scale=r1/r2) {
|
||||||
|
circle(r=r2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +238,7 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
|
||||||
// r = Radius of the sphere.
|
// r = Radius of the sphere.
|
||||||
// d = Diameter 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)
|
// 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", "alt", "stagger", or "icosa". Default: "orig"
|
// style = The style of the sphere's construction. One of "orig", "aligned", "stagger", or "icosa". Default: "orig"
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
// 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`
|
// 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`
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||||
|
@ -317,8 +248,8 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
|
||||||
// sphere(d=100);
|
// sphere(d=100);
|
||||||
// Example: style="orig"
|
// Example: style="orig"
|
||||||
// sphere(d=100, style="orig", $fn=10);
|
// sphere(d=100, style="orig", $fn=10);
|
||||||
// Example: style="alt"
|
// Example: style="aligned"
|
||||||
// sphere(d=100, style="alt", $fn=10);
|
// sphere(d=100, style="aligned", $fn=10);
|
||||||
// Example: style="stagger"
|
// Example: style="stagger"
|
||||||
// sphere(d=100, style="stagger", $fn=10);
|
// sphere(d=100, style="stagger", $fn=10);
|
||||||
// Example: style="icosa"
|
// Example: style="icosa"
|
||||||
|
@ -336,110 +267,12 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
|
||||||
// Example: Called as Function
|
// Example: Called as Function
|
||||||
// vnf = sphere(d=100, style="icosa");
|
// vnf = sphere(d=100, style="icosa");
|
||||||
// vnf_polyhedron(vnf);
|
// vnf_polyhedron(vnf);
|
||||||
module sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP)
|
module sphere(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP)
|
||||||
{
|
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient) children();
|
||||||
r = get_radius(r=r, d=d, dflt=1);
|
|
||||||
sides = segs(r);
|
|
||||||
vnf = sphere(r=r, circum=circum, style=style);
|
|
||||||
attachable(anchor,spin,orient, r=r) {
|
|
||||||
vnf_polyhedron(vnf, convexity=2);
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=UP) =
|
function sphere(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP) =
|
||||||
let(
|
spheroid(r=r, d=d, circum=circum, style=style, anchor=anchor, spin=spin, orient=orient);
|
||||||
r = get_radius(r=r, d=d, dflt=1),
|
|
||||||
hsides = segs(r),
|
|
||||||
vsides = max(2,ceil(hsides/2)),
|
|
||||||
icosa_steps = round(max(5,hsides)/5),
|
|
||||||
rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r,
|
|
||||||
stagger = style=="stagger",
|
|
||||||
verts = style=="orig"? [
|
|
||||||
for (i=[0:1:vsides-1]) let(phi = (i+0.5)*180/(vsides))
|
|
||||||
for (j=[0:1:hsides-1]) let(theta = j*360/hsides)
|
|
||||||
spherical_to_xyz(rr, theta, phi),
|
|
||||||
] : style=="alt" || style=="stagger"? [
|
|
||||||
spherical_to_xyz(rr, 0, 0),
|
|
||||||
for (i=[1:1:vsides-1]) let(phi = i*180/vsides)
|
|
||||||
for (j=[0:1:hsides-1]) let(theta = (j+((stagger && i%2!=0)?0.5:0))*360/hsides)
|
|
||||||
spherical_to_xyz(rr, theta, phi),
|
|
||||||
spherical_to_xyz(rr, 0, 180)
|
|
||||||
] : style=="icosa"? [
|
|
||||||
for (tb=[0,1], j=[0,2], i = [0:1:4]) let(
|
|
||||||
theta0 = i*360/5,
|
|
||||||
theta1 = (i-0.5)*360/5,
|
|
||||||
theta2 = (i+0.5)*360/5,
|
|
||||||
phi0 = 180/3 * j,
|
|
||||||
phi1 = 180/3,
|
|
||||||
v0 = spherical_to_xyz(1,theta0,phi0),
|
|
||||||
v1 = spherical_to_xyz(1,theta1,phi1),
|
|
||||||
v2 = spherical_to_xyz(1,theta2,phi1),
|
|
||||||
ax0 = vector_axis(v0, v1),
|
|
||||||
ang0 = vector_angle(v0, v1),
|
|
||||||
ax1 = vector_axis(v0, v2),
|
|
||||||
ang1 = vector_angle(v0, v2)
|
|
||||||
)
|
|
||||||
for (k = [0:1:icosa_steps]) let(
|
|
||||||
u = k/icosa_steps,
|
|
||||||
vv0 = rot(ang0*u, ax0, p=v0),
|
|
||||||
vv1 = rot(ang1*u, ax1, p=v0),
|
|
||||||
ax2 = vector_axis(vv0, vv1),
|
|
||||||
ang2 = vector_angle(vv0, vv1)
|
|
||||||
)
|
|
||||||
for (l = [0:1:k]) let(
|
|
||||||
v = k? l/k : 0,
|
|
||||||
pt = rot(ang2*v, v=ax2, p=vv0) * rr * (tb? -1 : 1)
|
|
||||||
) pt
|
|
||||||
] : assert(in_list(style,["orig","alt","stagger","icosa"])),
|
|
||||||
lv = len(verts),
|
|
||||||
faces = style=="orig"? [
|
|
||||||
[for (i=[0:1:hsides-1]) hsides-i-1],
|
|
||||||
[for (i=[0:1:hsides-1]) lv-hsides+i],
|
|
||||||
for (i=[0:1:vsides-2], j=[0:1:hsides-1]) each [
|
|
||||||
[(i+1)*hsides+j, i*hsides+j, i*hsides+(j+1)%hsides],
|
|
||||||
[(i+1)*hsides+j, i*hsides+(j+1)%hsides, (i+1)*hsides+(j+1)%hsides],
|
|
||||||
]
|
|
||||||
] : style=="alt" || style=="stagger"? [
|
|
||||||
for (i=[0:1:hsides-1]) let(
|
|
||||||
b2 = lv-2-hsides
|
|
||||||
) each [
|
|
||||||
[i+1, 0, ((i+1)%hsides)+1],
|
|
||||||
[lv-1, b2+i+1, b2+((i+1)%hsides)+1],
|
|
||||||
],
|
|
||||||
for (i=[0:1:vsides-3], j=[0:1:hsides-1]) let(
|
|
||||||
base = 1 + hsides*i
|
|
||||||
) each (
|
|
||||||
(stagger && i%2!=0)? [
|
|
||||||
[base+j, base+hsides+j%hsides, base+hsides+(j+hsides-1)%hsides],
|
|
||||||
[base+j, base+(j+1)%hsides, base+hsides+j],
|
|
||||||
] : [
|
|
||||||
[base+j, base+(j+1)%hsides, base+hsides+(j+1)%hsides],
|
|
||||||
[base+j, base+hsides+(j+1)%hsides, base+hsides+j],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
] : style=="icosa"? let(
|
|
||||||
pyr = [for (x=[0:1:icosa_steps+1]) x],
|
|
||||||
tri = sum(pyr),
|
|
||||||
soff = cumsum(pyr)
|
|
||||||
) [
|
|
||||||
for (tb=[0,1], j=[0,1], i = [0:1:4]) let(
|
|
||||||
base = ((((tb*2) + j) * 5) + i) * tri
|
|
||||||
)
|
|
||||||
for (k = [0:1:icosa_steps-1])
|
|
||||||
for (l = [0:1:k]) let(
|
|
||||||
v1 = base + soff[k] + l,
|
|
||||||
v2 = base + soff[k+1] + l,
|
|
||||||
v3 = base + soff[k+1] + (l + 1),
|
|
||||||
faces = [
|
|
||||||
if(l>0) [v1-1,v1,v2],
|
|
||||||
[v1,v3,v2],
|
|
||||||
],
|
|
||||||
faces2 = (tb+j)%2? [for (f=faces) reverse(f)] : faces
|
|
||||||
) each faces2
|
|
||||||
] : []
|
|
||||||
) [reorient(anchor,spin,orient, r=r, p=verts), faces];
|
|
||||||
|
|
||||||
|
|
||||||
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
272
shapes.scad
272
shapes.scad
|
@ -205,12 +205,12 @@ module cuboid(
|
||||||
minkowski() {
|
minkowski() {
|
||||||
cube(isize, center=true);
|
cube(isize, center=true);
|
||||||
if (trimcorners) {
|
if (trimcorners) {
|
||||||
sphere(r=rounding, $fn=sides);
|
spheroid(r=rounding, $fn=sides);
|
||||||
} else {
|
} else {
|
||||||
intersection() {
|
intersection() {
|
||||||
cylinder(r=rounding, h=rounding*2, center=true, $fn=sides);
|
cyl(r=rounding, h=rounding*2, $fn=sides);
|
||||||
rotate([90,0,0]) cylinder(r=rounding, h=rounding*2, center=true, $fn=sides);
|
rotate([90,0,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
|
||||||
rotate([0,90,0]) cylinder(r=rounding, h=rounding*2, center=true, $fn=sides);
|
rotate([0,90,0]) cyl(r=rounding, h=rounding*2, $fn=sides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ module cuboid(
|
||||||
rotate(majrots[axis]) cube([rounding*2, rounding*2, size[axis]+0.1], center=true);
|
rotate(majrots[axis]) cube([rounding*2, rounding*2, size[axis]+0.1], center=true);
|
||||||
}
|
}
|
||||||
translate(vmul(EDGE_OFFSETS[axis][i], size/2 - [1,1,1]*rounding)) {
|
translate(vmul(EDGE_OFFSETS[axis][i], size/2 - [1,1,1]*rounding)) {
|
||||||
rotate(majrots[axis]) cylinder(h=size[axis]+0.2, r=rounding, center=true, $fn=sides);
|
rotate(majrots[axis]) cyl(h=size[axis]+0.2, r=rounding, $fn=sides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ module cuboid(
|
||||||
cube(rounding*2, center=true);
|
cube(rounding*2, center=true);
|
||||||
}
|
}
|
||||||
translate(vmul([xa,ya,za], size/2-[1,1,1]*rounding)) {
|
translate(vmul([xa,ya,za], size/2-[1,1,1]*rounding)) {
|
||||||
sphere(r=rounding, $fn=sides);
|
spheroid(r=rounding, $fn=sides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,12 +422,12 @@ module rounded_prismoid(
|
||||||
down(h/2) {
|
down(h/2) {
|
||||||
hull() {
|
hull() {
|
||||||
linear_extrude(height=eps, center=false, convexity=2) {
|
linear_extrude(height=eps, center=false, convexity=2) {
|
||||||
square(size1, rounding=rr1, center=true);
|
rect(size1, rounding=rr1, center=true);
|
||||||
}
|
}
|
||||||
up(h-0.01) {
|
up(h-0.01) {
|
||||||
translate(shiftby) {
|
translate(shiftby) {
|
||||||
linear_extrude(height=eps, center=false, convexity=2) {
|
linear_extrude(height=eps, center=false, convexity=2) {
|
||||||
square(size2, rounding=rr2, center=true);
|
rect(size2, rounding=rr2, center=true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,10 +705,7 @@ module cyl(
|
||||||
module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
||||||
{
|
{
|
||||||
anchor = rot(from=RIGHT, to=UP, p=anchor);
|
anchor = rot(from=RIGHT, to=UP, p=anchor);
|
||||||
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=RIGHT, anchor=anchor) {
|
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=RIGHT, anchor=anchor) children();
|
||||||
for (i=[0:1:$children-2]) children(i);
|
|
||||||
if ($children>0) children($children-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -746,10 +743,7 @@ module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
|
||||||
module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
||||||
{
|
{
|
||||||
anchor = rot(from=BACK, to=UP, p=anchor);
|
anchor = rot(from=BACK, to=UP, p=anchor);
|
||||||
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=BACK, anchor=anchor) {
|
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=BACK, anchor=anchor) children();
|
||||||
for (i=[0:1:$children-2]) children(i);
|
|
||||||
if ($children>0) children($children-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -786,10 +780,7 @@ module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
|
||||||
// }
|
// }
|
||||||
module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER)
|
||||||
{
|
{
|
||||||
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=UP, anchor=anchor) {
|
cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=UP, anchor=anchor) children();
|
||||||
for (i=[0:1:$children-2]) children(i);
|
|
||||||
if ($children>0) children($children-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -915,7 +906,7 @@ module torus(
|
||||||
anchor = get_anchor(anchor, center, BOT, CENTER);
|
anchor = get_anchor(anchor, center, BOT, CENTER);
|
||||||
attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
|
attachable(anchor,spin,orient, r=(majrad+minrad), l=minrad*2) {
|
||||||
rotate_extrude(convexity=4) {
|
rotate_extrude(convexity=4) {
|
||||||
right(majrad) circle(minrad);
|
right(majrad) circle(r=minrad);
|
||||||
}
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
@ -923,106 +914,173 @@ module torus(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Spheroids
|
// Section: Spheroid
|
||||||
|
|
||||||
|
|
||||||
// Module: spheroid()
|
// Function&Module: spheroid()
|
||||||
|
// Usage: As Module
|
||||||
|
// spheroid(r|d, [circum], [style])
|
||||||
|
// Usage: As Function
|
||||||
|
// vnf = spheroid(r|d, [circum], [style])
|
||||||
// Description:
|
// Description:
|
||||||
// An version of `sphere()` with anchors points and orientation.
|
// Creates a spheroid object, with support for anchoring and attachments.
|
||||||
// Usage:
|
// This is a drop-in replacement for the built-in `sphere()` module.
|
||||||
// spheroid(r|d, [circum])
|
// When called as a function, returns a [VNF](vnf.scad) for a spheroid.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// r = Radius of the sphere.
|
// r = Radius of the spheroid.
|
||||||
// d = Diameter of the sphere.
|
// d = Diameter of the spheroid.
|
||||||
// circum = If true, circumscribes the perfect sphere of the given radius/diameter.
|
// circum = If true, the spheroid is made large enough to circumscribe the sphere of the ideal side. Otherwise inscribes. Default: false (inscribes)
|
||||||
|
// style = The style of the spheroid's construction. One of "orig", "aligned", "stagger", or "icosa". Default: "aligned"
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
// 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`
|
// 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`
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||||
// Example: By Radius
|
// Example: By Radius
|
||||||
// spheroid(r=50, circum=true);
|
// spheroid(r=50);
|
||||||
// Example: By Diameter
|
// Example: By Diameter
|
||||||
// spheroid(d=100, circum=true);
|
// spheroid(d=100);
|
||||||
|
// Example: style="orig"
|
||||||
|
// spheroid(d=100, style="orig", $fn=10);
|
||||||
|
// Example: style="aligned"
|
||||||
|
// spheroid(d=100, style="aligned", $fn=10);
|
||||||
|
// Example: style="stagger"
|
||||||
|
// spheroid(d=100, style="stagger", $fn=10);
|
||||||
|
// Example: style="icosa"
|
||||||
|
// spheroid(d=100, style="icosa", $fn=10);
|
||||||
|
// // In "icosa" style, $fn is quantized
|
||||||
|
// // to the nearest multiple of 5.
|
||||||
|
// Example: Anchoring
|
||||||
|
// spheroid(d=100, anchor=FRONT);
|
||||||
|
// Example: Spin
|
||||||
|
// spheroid(d=100, anchor=FRONT, spin=45);
|
||||||
|
// Example: Orientation
|
||||||
|
// spheroid(d=100, anchor=FRONT, spin=45, orient=FWD);
|
||||||
// Example: Standard Connectors
|
// Example: Standard Connectors
|
||||||
// spheroid(d=40, circum=true) show_anchors();
|
// spheroid(d=50) show_anchors();
|
||||||
module spheroid(r=undef, d=undef, circum=false, anchor=CENTER, spin=0, orient=UP)
|
// Example: Called as Function
|
||||||
|
// vnf = spheroid(d=100, style="icosa");
|
||||||
|
// vnf_polyhedron(vnf);
|
||||||
|
module spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP)
|
||||||
{
|
{
|
||||||
r = get_radius(r=r, d=d, dflt=1);
|
|
||||||
hsides = segs(r);
|
|
||||||
vsides = ceil(hsides/2);
|
|
||||||
rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r;
|
|
||||||
attachable(anchor,spin,orient, r=rr) {
|
|
||||||
sphere(r=rr);
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Module: staggered_sphere()
|
|
||||||
//
|
|
||||||
// Description:
|
|
||||||
// An alternate construction to the standard `sphere()` built-in, with different triangulation.
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
// staggered_sphere(r|d, [circum])
|
|
||||||
//
|
|
||||||
// Arguments:
|
|
||||||
// r = Radius of the sphere.
|
|
||||||
// d = Diameter of the sphere.
|
|
||||||
// circum = If true, circumscribes the perfect sphere of the given size.
|
|
||||||
// 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
|
|
||||||
// staggered_sphere(r=50, circum=true);
|
|
||||||
// Example: By Diameter
|
|
||||||
// staggered_sphere(d=100, circum=true);
|
|
||||||
// Example: Standard Connectors
|
|
||||||
// staggered_sphere(d=40, circum=true) show_anchors();
|
|
||||||
module staggered_sphere(r=undef, d=undef, circum=false, anchor=CENTER, spin=0, orient=UP) {
|
|
||||||
r = get_radius(r=r, d=d, dflt=1);
|
r = get_radius(r=r, d=d, dflt=1);
|
||||||
sides = segs(r);
|
sides = segs(r);
|
||||||
vsides = max(3, ceil(sides/2))+1;
|
attachable(anchor,spin,orient, r=r) {
|
||||||
step = 360/sides;
|
if (style=="orig") {
|
||||||
vstep = 180/(vsides-1);
|
rotate_extrude(convexity=2,$fn=sides) {
|
||||||
rr = circum? (r / cos(180/sides) / cos(90/vsides)) : r;
|
difference() {
|
||||||
pts = concat(
|
zrot(180/sides) oval(r=r, circum=circum, $fn=sides);
|
||||||
[[0,0,rr]],
|
left(r) square(2*r,center=true);
|
||||||
[
|
}
|
||||||
for (p = [1:1:vsides-2], t = [0:1:sides-1]) let(
|
}
|
||||||
ta = (t+(p%2/2))*step,
|
} else if (style=="aligned") {
|
||||||
pa = p*vstep
|
rotate_extrude(convexity=2,$fn=sides) {
|
||||||
) spherical_to_xyz(rr, ta, pa)
|
difference() {
|
||||||
],
|
oval(r=r, circum=circum, $fn=sides);
|
||||||
[[0,0,-rr]]
|
left(r) square(2*r,center=true);
|
||||||
);
|
}
|
||||||
pcnt = len(pts);
|
}
|
||||||
faces = concat(
|
} else {
|
||||||
[
|
vnf = spheroid(r=r, circum=circum, style=style);
|
||||||
for (i = [1:1:sides]) each [
|
vnf_polyhedron(vnf, convexity=2);
|
||||||
[0, i%sides+1, i],
|
}
|
||||||
[pcnt-1, pcnt-1-(i%sides+1), pcnt-1-i]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
for (p = [0:1:vsides-4], i = [0:1:sides-1]) let(
|
|
||||||
b1 = 1+p*sides,
|
|
||||||
b2 = 1+(p+1)*sides,
|
|
||||||
v1 = b1+i,
|
|
||||||
v2 = b1+(i+1)%sides,
|
|
||||||
v3 = b2+((i+((p%2)?(sides-1):0))%sides),
|
|
||||||
v4 = b2+((i+1+((p%2)?(sides-1):0))%sides)
|
|
||||||
) each [[v1,v4,v3], [v1,v2,v4]]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
attachable(anchor,spin,orient, r=rr) {
|
|
||||||
zrot((floor(sides/4)%2==1)? 180/sides : 0) polyhedron(points=pts, faces=faces);
|
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orient=UP) =
|
||||||
|
let(
|
||||||
|
r = get_radius(r=r, d=d, dflt=1),
|
||||||
|
hsides = segs(r),
|
||||||
|
vsides = max(2,ceil(hsides/2)),
|
||||||
|
icosa_steps = round(max(5,hsides)/5),
|
||||||
|
rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r,
|
||||||
|
stagger = style=="stagger",
|
||||||
|
verts = style=="orig"? [
|
||||||
|
for (i=[0:1:vsides-1]) let(phi = (i+0.5)*180/(vsides))
|
||||||
|
for (j=[0:1:hsides-1]) let(theta = j*360/hsides)
|
||||||
|
spherical_to_xyz(rr, theta, phi),
|
||||||
|
] : style=="aligned" || style=="stagger"? [
|
||||||
|
spherical_to_xyz(rr, 0, 0),
|
||||||
|
for (i=[1:1:vsides-1]) let(phi = i*180/vsides)
|
||||||
|
for (j=[0:1:hsides-1]) let(theta = (j+((stagger && i%2!=0)?0.5:0))*360/hsides)
|
||||||
|
spherical_to_xyz(rr, theta, phi),
|
||||||
|
spherical_to_xyz(rr, 0, 180)
|
||||||
|
] : style=="icosa"? [
|
||||||
|
for (tb=[0,1], j=[0,2], i = [0:1:4]) let(
|
||||||
|
theta0 = i*360/5,
|
||||||
|
theta1 = (i-0.5)*360/5,
|
||||||
|
theta2 = (i+0.5)*360/5,
|
||||||
|
phi0 = 180/3 * j,
|
||||||
|
phi1 = 180/3,
|
||||||
|
v0 = spherical_to_xyz(1,theta0,phi0),
|
||||||
|
v1 = spherical_to_xyz(1,theta1,phi1),
|
||||||
|
v2 = spherical_to_xyz(1,theta2,phi1),
|
||||||
|
ax0 = vector_axis(v0, v1),
|
||||||
|
ang0 = vector_angle(v0, v1),
|
||||||
|
ax1 = vector_axis(v0, v2),
|
||||||
|
ang1 = vector_angle(v0, v2)
|
||||||
|
)
|
||||||
|
for (k = [0:1:icosa_steps]) let(
|
||||||
|
u = k/icosa_steps,
|
||||||
|
vv0 = rot(ang0*u, ax0, p=v0),
|
||||||
|
vv1 = rot(ang1*u, ax1, p=v0),
|
||||||
|
ax2 = vector_axis(vv0, vv1),
|
||||||
|
ang2 = vector_angle(vv0, vv1)
|
||||||
|
)
|
||||||
|
for (l = [0:1:k]) let(
|
||||||
|
v = k? l/k : 0,
|
||||||
|
pt = rot(ang2*v, v=ax2, p=vv0) * rr * (tb? -1 : 1)
|
||||||
|
) pt
|
||||||
|
] : assert(in_list(style,["orig","aligned","stagger","icosa"])),
|
||||||
|
lv = len(verts),
|
||||||
|
faces = style=="orig"? [
|
||||||
|
[for (i=[0:1:hsides-1]) hsides-i-1],
|
||||||
|
[for (i=[0:1:hsides-1]) lv-hsides+i],
|
||||||
|
for (i=[0:1:vsides-2], j=[0:1:hsides-1]) each [
|
||||||
|
[(i+1)*hsides+j, i*hsides+j, i*hsides+(j+1)%hsides],
|
||||||
|
[(i+1)*hsides+j, i*hsides+(j+1)%hsides, (i+1)*hsides+(j+1)%hsides],
|
||||||
|
]
|
||||||
|
] : style=="aligned" || style=="stagger"? [
|
||||||
|
for (i=[0:1:hsides-1]) let(
|
||||||
|
b2 = lv-2-hsides
|
||||||
|
) each [
|
||||||
|
[i+1, 0, ((i+1)%hsides)+1],
|
||||||
|
[lv-1, b2+i+1, b2+((i+1)%hsides)+1],
|
||||||
|
],
|
||||||
|
for (i=[0:1:vsides-3], j=[0:1:hsides-1]) let(
|
||||||
|
base = 1 + hsides*i
|
||||||
|
) each (
|
||||||
|
(stagger && i%2!=0)? [
|
||||||
|
[base+j, base+hsides+j%hsides, base+hsides+(j+hsides-1)%hsides],
|
||||||
|
[base+j, base+(j+1)%hsides, base+hsides+j],
|
||||||
|
] : [
|
||||||
|
[base+j, base+(j+1)%hsides, base+hsides+(j+1)%hsides],
|
||||||
|
[base+j, base+hsides+(j+1)%hsides, base+hsides+j],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
] : style=="icosa"? let(
|
||||||
|
pyr = [for (x=[0:1:icosa_steps+1]) x],
|
||||||
|
tri = sum(pyr),
|
||||||
|
soff = cumsum(pyr)
|
||||||
|
) [
|
||||||
|
for (tb=[0,1], j=[0,1], i = [0:1:4]) let(
|
||||||
|
base = ((((tb*2) + j) * 5) + i) * tri
|
||||||
|
)
|
||||||
|
for (k = [0:1:icosa_steps-1])
|
||||||
|
for (l = [0:1:k]) let(
|
||||||
|
v1 = base + soff[k] + l,
|
||||||
|
v2 = base + soff[k+1] + l,
|
||||||
|
v3 = base + soff[k+1] + (l + 1),
|
||||||
|
faces = [
|
||||||
|
if(l>0) [v1-1,v1,v2],
|
||||||
|
[v1,v3,v2],
|
||||||
|
],
|
||||||
|
faces2 = (tb+j)%2? [for (f=faces) reverse(f)] : faces
|
||||||
|
) each faces2
|
||||||
|
] : []
|
||||||
|
) [reorient(anchor,spin,orient, r=r, p=verts), faces];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: 3D Printing Shapes
|
// Section: 3D Printing Shapes
|
||||||
|
|
||||||
|
@ -1176,7 +1234,7 @@ module pie_slice(
|
||||||
anchor = get_anchor(anchor, center, BOT, BOT);
|
anchor = get_anchor(anchor, center, BOT, BOT);
|
||||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
||||||
difference() {
|
difference() {
|
||||||
cylinder(r1=r1, r2=r2, h=l, center=true);
|
cyl(r1=r1, r2=r2, h=l);
|
||||||
if (ang<180) rotate(ang) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
|
if (ang<180) rotate(ang) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true);
|
||||||
difference() {
|
difference() {
|
||||||
fwd(maxd/2) cube([2*maxd, maxd, l+0.2], center=true);
|
fwd(maxd/2) cube([2*maxd, maxd, l+0.2], center=true);
|
||||||
|
@ -1330,10 +1388,10 @@ module arced_slot(
|
||||||
zrot(sa) {
|
zrot(sa) {
|
||||||
difference() {
|
difference() {
|
||||||
pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=UP, anchor=CENTER);
|
pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=UP, anchor=CENTER);
|
||||||
cylinder(h=h+0.1, r1=r-sr1, r2=r-sr2, center=true);
|
cyl(h=h+0.1, r1=r-sr1, r2=r-sr2);
|
||||||
}
|
}
|
||||||
right(r) cylinder(h=h, r1=sr1, r2=sr2, center=true, $fn=fn_minor);
|
right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
|
||||||
zrot(da) right(r) cylinder(h=h, r1=sr1, r2=sr2, center=true, $fn=fn_minor);
|
zrot(da) right(r) cyl(h=h, r1=sr1, r2=sr2, $fn=fn_minor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
children();
|
children();
|
||||||
|
|
144
shapes2d.scad
144
shapes2d.scad
|
@ -694,6 +694,148 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: 2D Primitives
|
||||||
|
|
||||||
|
// Function&Module: rect()
|
||||||
|
// Usage:
|
||||||
|
// rect(size, [center], [rounding], [chamfer], [anchor], [spin])
|
||||||
|
// Description:
|
||||||
|
// When called as a module, creates a 2D rectangle of the given size, with optional rounding or chamfering.
|
||||||
|
// 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 rectangle to create. If given as a scalar, both X and Y will be the same size.
|
||||||
|
// rounding = The rounding radius for the corners. If given as a list of four numbers, gives individual radii for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no rounding)
|
||||||
|
// chamfer = The chamfer size for the corners. If given as a list of four numbers, gives individual chamfers for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no chamfer)
|
||||||
|
// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`.
|
||||||
|
// 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`
|
||||||
|
// Example(2D):
|
||||||
|
// rect(40);
|
||||||
|
// Example(2D): Centered
|
||||||
|
// rect([40,30], center=true);
|
||||||
|
// Example(2D): Anchored
|
||||||
|
// rect([40,30], anchor=FRONT);
|
||||||
|
// Example(2D): Spun
|
||||||
|
// rect([40,30], anchor=FRONT, spin=30);
|
||||||
|
// Example(2D): Chamferred Rect
|
||||||
|
// rect([40,30], chamfer=5, center=true);
|
||||||
|
// Example(2D): Rounded Rect
|
||||||
|
// rect([40,30], rounding=5, center=true);
|
||||||
|
// Example(2D): Mixed Chamferring and Rounding
|
||||||
|
// rect([40,30],center=true,rounding=[5,0,10,0],chamfer=[0,8,0,15],$fa=1,$fs=1);
|
||||||
|
// Example(2D): Called as Function
|
||||||
|
// path = rect([40,30], chamfer=5, anchor=FRONT, spin=30);
|
||||||
|
// stroke(path, closed=true);
|
||||||
|
// move_copies(path) color("blue") circle(d=2,$fn=8);
|
||||||
|
module rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) {
|
||||||
|
size = is_num(size)? [size,size] : point2d(size);
|
||||||
|
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT);
|
||||||
|
attachable(anchor,spin, two_d=true, size=size) {
|
||||||
|
if (rounding==0 && chamfer==0) {
|
||||||
|
square(size, center=true);
|
||||||
|
} else {
|
||||||
|
pts = rect(size=size, rounding=rounding, chamfer=chamfer, center=true);
|
||||||
|
polygon(pts);
|
||||||
|
}
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function rect(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
|
||||||
|
assert(is_num(size) || is_vector(size))
|
||||||
|
assert(is_num(chamfer) || len(chamfer)==4)
|
||||||
|
assert(is_num(rounding) || len(rounding)==4)
|
||||||
|
let(
|
||||||
|
size = is_num(size)? [size,size] : point2d(size),
|
||||||
|
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT),
|
||||||
|
complex = rounding!=0 || chamfer!=0
|
||||||
|
)
|
||||||
|
(rounding==0 && chamfer==0)? let(
|
||||||
|
path = [
|
||||||
|
[ size.x/2, -size.y/2],
|
||||||
|
[-size.x/2, -size.y/2],
|
||||||
|
[-size.x/2, size.y/2],
|
||||||
|
[ size.x/2, size.y/2]
|
||||||
|
]
|
||||||
|
) rot(spin, p=move(-vmul(anchor,size/2), p=path)) :
|
||||||
|
let(
|
||||||
|
chamfer = is_list(chamfer)? chamfer : [for (i=[0:3]) chamfer],
|
||||||
|
rounding = is_list(rounding)? rounding : [for (i=[0:3]) rounding],
|
||||||
|
quadorder = [3,2,1,0],
|
||||||
|
quadpos = [[1,1],[-1,1],[-1,-1],[1,-1]],
|
||||||
|
insets = [for (i=[0:3]) chamfer[i]>0? chamfer[i] : rounding[i]>0? rounding[i] : 0],
|
||||||
|
insets_x = max(insets[0]+insets[1],insets[2]+insets[3]),
|
||||||
|
insets_y = max(insets[0]+insets[3],insets[1]+insets[2])
|
||||||
|
)
|
||||||
|
assert(insets_x <= size.x, "Requested roundings and/or chamfers exceed the rect width.")
|
||||||
|
assert(insets_y <= size.y, "Requested roundings and/or chamfers exceed the rect height.")
|
||||||
|
let(
|
||||||
|
path = [
|
||||||
|
for(i = [0:3])
|
||||||
|
let(
|
||||||
|
quad = quadorder[i],
|
||||||
|
inset = insets[quad],
|
||||||
|
cverts = quant(segs(inset),4)/4,
|
||||||
|
cp = vmul(size/2-[inset,inset], quadpos[quad]),
|
||||||
|
step = 90/cverts,
|
||||||
|
angs =
|
||||||
|
chamfer[quad] > 0? [0,-90]-90*[i,i] :
|
||||||
|
rounding[quad] > 0? [for (j=[0:1:cverts]) 360-j*step-i*90] :
|
||||||
|
[0]
|
||||||
|
)
|
||||||
|
each [for (a = angs) cp + inset*[cos(a),sin(a)]]
|
||||||
|
]
|
||||||
|
) complex?
|
||||||
|
reorient(anchor,spin, two_d=true, path=path, p=path) :
|
||||||
|
reorient(anchor,spin, two_d=true, size=size, p=path);
|
||||||
|
|
||||||
|
|
||||||
|
// Function&Module: oval()
|
||||||
|
// Usage:
|
||||||
|
// oval(r|d, [realign], [circum])
|
||||||
|
// Description:
|
||||||
|
// When called as a 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.
|
||||||
|
// realign = If true, rotates the polygon that approximates the circle by half of one size.
|
||||||
|
// circum = If true, the polygon that approximates the circle will be upsized slightly to circumscribe the theoretical circle. If false, it inscribes the theoretical circle. Default: false
|
||||||
|
// 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`
|
||||||
|
// Example(2D): By Radius
|
||||||
|
// oval(r=25);
|
||||||
|
// Example(2D): By Diameter
|
||||||
|
// oval(d=50);
|
||||||
|
// Example(2D): Anchoring
|
||||||
|
// oval(d=50, anchor=FRONT);
|
||||||
|
// Example(2D): Spin
|
||||||
|
// oval(d=50, anchor=FRONT, spin=45);
|
||||||
|
// Example(NORENDER): Called as Function
|
||||||
|
// path = oval(d=50, anchor=FRONT, spin=45);
|
||||||
|
module oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) {
|
||||||
|
r = get_radius(r=r, d=d, dflt=1);
|
||||||
|
sides = segs(r);
|
||||||
|
rr = circum? r/cos(180/sides) : r;
|
||||||
|
attachable(anchor,spin, two_d=true, r=rr) {
|
||||||
|
zrot(realign? 180/sides : 0) circle(r=r, $fn=sides);
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
|
||||||
|
let(
|
||||||
|
r = get_radius(r=r, d=d, dflt=1),
|
||||||
|
sides = segs(r),
|
||||||
|
offset = realign? 180/sides : 0,
|
||||||
|
rr = r / (circum? cos(180/sides) : 1),
|
||||||
|
pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) rr*[cos(a),sin(a)]]
|
||||||
|
) reorient(anchor,spin, two_d=true, r=rr, p=pts);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: 2D N-Gons
|
// Section: 2D N-Gons
|
||||||
|
|
||||||
// Function&Module: regular_ngon()
|
// Function&Module: regular_ngon()
|
||||||
|
@ -738,7 +880,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
|
||||||
)
|
)
|
||||||
assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.")
|
assert(!is_undef(r), "regular_ngon(): need to specify one of r, d, or, od, ir, id, side.")
|
||||||
let(
|
let(
|
||||||
path = rounding==0? circle(r=r, realign=realign, $fn=n) : (
|
path = rounding==0? oval(r=r, realign=realign, $fn=n) : (
|
||||||
let(
|
let(
|
||||||
steps = floor(segs(r)/n),
|
steps = floor(segs(r)/n),
|
||||||
step = 360/n/steps,
|
step = 360/n/steps,
|
||||||
|
|
|
@ -844,7 +844,8 @@ module sweep(shape, transformations, closed=false, caps, convexity=10) {
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: path_sweep()
|
// Function&Module: path_sweep()
|
||||||
// Usage: path_sweep(shape, path, [method], [normal], [closed], [twist], [twist_by_length], [symmetry], [last_normal], [tangent], [relaxed], [caps], [convexity], [transforms])
|
// Usage:
|
||||||
|
// path_sweep(shape, path, [method], [normal], [closed], [twist], [twist_by_length], [symmetry], [last_normal], [tangent], [relaxed], [caps], [convexity], [transforms])
|
||||||
// Description:
|
// Description:
|
||||||
// Takes as input a 2d shape (specified as a point list) and a 2d or 3d path and constructs a polyhedron by sweeping the shape along the path.
|
// Takes as input a 2d shape (specified as a point list) and a 2d or 3d path and constructs a polyhedron by sweeping the shape along the path.
|
||||||
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF by default or if you set `transforms=true` then
|
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF by default or if you set `transforms=true` then
|
||||||
|
@ -1027,7 +1028,7 @@ module sweep(shape, transformations, closed=false, caps, convexity=10) {
|
||||||
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
|
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
|
||||||
// path_sweep(ushape, helix, method="manual", normal=normals);
|
// path_sweep(ushape, helix, method="manual", normal=normals);
|
||||||
// Example: When using "manual" it is important to choose a normal that works for the whole path, producing a consistent result. Here we have specified an upward normal, and indeed the shape is pointed up everywhere, but two abrupt transitional twists render the model invalid.
|
// Example: When using "manual" it is important to choose a normal that works for the whole path, producing a consistent result. Here we have specified an upward normal, and indeed the shape is pointed up everywhere, but two abrupt transitional twists render the model invalid.
|
||||||
// yzcircle = yrot(90,p=circle($fn=64, r=30));
|
// yzcircle = yrot(90,p=path3d(circle($fn=64, r=30)));
|
||||||
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
|
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
|
||||||
// path_sweep(ushape, yzcircle, method="manual", normal=UP, closed=true);
|
// path_sweep(ushape, yzcircle, method="manual", normal=UP, closed=true);
|
||||||
// Example: The "natural" method will introduce twists when the curvature changes direction. A warning is displayed.
|
// Example: The "natural" method will introduce twists when the curvature changes direction. A warning is displayed.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,279];
|
BOSL_VERSION = [2,0,280];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
|
Loading…
Reference in a new issue