Merge branch 'master' into master

This commit is contained in:
adrianVmariano 2022-10-13 22:57:48 -04:00 committed by GitHub
commit a8442c74fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 523 additions and 164 deletions

231
ball_bearings.scad Normal file
View file

@ -0,0 +1,231 @@
//////////////////////////////////////////////////////////////////////
// LibFile: ball_bearings.scad
// Models for standard ball bearing cartridges.
// Includes:
// include <BOSL2/std.scad>
// include <BOSL2/ball_bearings.scad>
// FileGroup: Parts
// FileSummary: Models for standard ball bearing cartridges.
//////////////////////////////////////////////////////////////////////
// Section: Ball Bearing Models
// Module: ball_bearing()
// Description:
// Creates a model of a ball bearing assembly.
// Arguments:
// trade_size = String name of a standard ball bearing trade size. ie: "608", "6902ZZ", or "R8"
// id = Inner diameter of ball bearing assembly.
// od = Outer diameter of ball bearing assembly.
// width = Width of ball bearing assembly.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example:
// ball_bearing("608");
// Example:
// ball_bearing("608ZZ");
// Example:
// ball_bearing("R8");
// Example:
// ball_bearing(id=12,od=32,width=10,shield=false);
module ball_bearing(trade_size, id, od, width, shield=true, anchor=CTR, spin=0, orient=UP) {
info = is_undef(trade_size)? [id, od, width, shield] :
ball_bearing_info(trade_size);
check = assert(all_defined(info), "Bad Input");
id = info[0];
od = info[1];
width = info[2];
shield = info[3];
mid_d = (id+od)/2;
wall = (od-id)/2/3;
color("silver")
attachable(anchor,spin,orient, d=od, l=width) {
if (shield) {
tube(id=id, wall=wall, h=width);
tube(od=od, wall=wall, h=width);
tube(id=id+0.1, od=od-0.1, h=(wall*2+width)/2);
} else {
ball_cnt = floor(PI*mid_d*0.95 / (wall*2));
difference() {
union() {
tube(id=id, wall=wall, h=width);
tube(od=od, wall=wall, h=width);
}
torus(r_maj=mid_d/2, r_min=wall);
}
for (i=[0:1:ball_cnt-1]) {
zrot(i*360/ball_cnt) right(mid_d/2) sphere(d=wall*2);
}
}
children();
}
}
// Section: Ball Bearing Info
// Function: ball_bearing_info()
// Description:
// Get dimensional info for a standard metric ball bearing cartridge.
// Returns `[SHAFT_DIAM, OUTER_DIAM, WIDTH, SHIELDED]` for the cylindrical cartridge.
// Arguments:
// size = Inner diameter of lmXuu bearing, in mm.
function ball_bearing_info(trade_size) =
assert(is_string(trade_size))
let(
IN = 25.4,
data = [
// trade_size, ID, OD, width, shielded
[ "R2", 1/8*IN, 3/8*IN, 5/32*IN, false],
[ "R3", 3/16*IN, 1/2*IN, 5/32*IN, false],
[ "R4", 1/4*IN, 5/8*IN, 0.196*IN, false],
[ "R6", 3/8*IN, 7/8*IN, 7/32*IN, false],
[ "R8", 1/2*IN, 9/8*IN, 1/4*IN, false],
[ "R10", 5/8*IN, 11/8*IN, 9/32*IN, false],
[ "R12", 3/4*IN, 13/8*IN, 5/16*IN, false],
[ "R14", 7/8*IN, 15/8*IN, 3/8*IN, false],
[ "R16", 8/8*IN, 16/8*IN, 3/8*IN, false],
[ "R18", 9/8*IN, 17/8*IN, 3/8*IN, false],
[ "R20", 10/8*IN, 18/8*IN, 3/8*IN, false],
[ "R22", 11/8*IN, 20/8*IN, 7/16*IN, false],
[ "R24", 12/8*IN, 21/8*IN, 7/16*IN, false],
[ "R2ZZ", 1/8*IN, 3/8*IN, 5/32*IN, true ],
[ "R3ZZ", 3/16*IN, 1/2*IN, 5/32*IN, true ],
[ "R4ZZ", 1/4*IN, 5/8*IN, 0.196*IN, true ],
[ "R6ZZ", 3/8*IN, 7/8*IN, 7/32*IN, true ],
[ "R8ZZ", 1/2*IN, 9/8*IN, 1/4*IN, true ],
[ "R10ZZ", 5/8*IN, 11/8*IN, 9/32*IN, true ],
[ "R12ZZ", 3/4*IN, 13/8*IN, 5/16*IN, true ],
[ "R14ZZ", 7/8*IN, 15/8*IN, 3/8*IN, true ],
[ "R16ZZ", 8/8*IN, 16/8*IN, 3/8*IN, true ],
[ "R18ZZ", 9/8*IN, 17/8*IN, 3/8*IN, true ],
[ "R20ZZ", 10/8*IN, 18/8*IN, 3/8*IN, true ],
[ "R22ZZ", 11/8*IN, 20/8*IN, 7/16*IN, true ],
[ "R24ZZ", 12/8*IN, 21/8*IN, 7/16*IN, true ],
[ "608", 8, 22, 7, false],
[ "629", 9, 26, 8, false],
[ "635", 5, 19, 6, false],
[ "6000", 10, 26, 8, false],
[ "6001", 12, 28, 8, false],
[ "6002", 15, 32, 9, false],
[ "6003", 17, 35, 10, false],
[ "6007", 35, 62, 14, false],
[ "6200", 10, 30, 9, false],
[ "6201", 12, 32, 10, false],
[ "6202", 15, 35, 11, false],
[ "6203", 17, 40, 12, false],
[ "6204", 20, 47, 14, false],
[ "6205", 25, 52, 15, false],
[ "6206", 30, 62, 16, false],
[ "6207", 35, 72, 17, false],
[ "6208", 40, 80, 18, false],
[ "6209", 45, 85, 19, false],
[ "6210", 50, 90, 20, false],
[ "6211", 55, 100, 21, false],
[ "6212", 60, 110, 22, false],
[ "6301", 12, 37, 12, false],
[ "6302", 15, 42, 13, false],
[ "6303", 17, 47, 14, false],
[ "6304", 20, 52, 15, false],
[ "6305", 25, 62, 17, false],
[ "6306", 30, 72, 19, false],
[ "6307", 35, 80, 21, false],
[ "6308", 40, 90, 23, false],
[ "6309", 45, 100, 25, false],
[ "6310", 50, 110, 27, false],
[ "6311", 55, 120, 29, false],
[ "6312", 60, 130, 31, false],
[ "6403", 17, 62, 17, false],
[ "6800", 10, 19, 5, false],
[ "6801", 12, 21, 5, false],
[ "6802", 15, 24, 5, false],
[ "6803", 17, 26, 5, false],
[ "6804", 20, 32, 7, false],
[ "6805", 25, 37, 7, false],
[ "6806", 30, 42, 7, false],
[ "6900", 10, 22, 6, false],
[ "6901", 12, 24, 6, false],
[ "6902", 15, 28, 7, false],
[ "6903", 17, 30, 7, false],
[ "6904", 20, 37, 9, false],
[ "6905", 25, 42, 9, false],
[ "6906", 30, 47, 9, false],
[ "6907", 35, 55, 10, false],
[ "6908", 40, 62, 12, false],
[ "16002", 15, 22, 8, false],
[ "16004", 20, 42, 8, false],
[ "16005", 25, 47, 8, false],
[ "16100", 10, 28, 8, false],
[ "16101", 12, 30, 8, false],
[ "608ZZ", 8, 22, 7, true ],
[ "629ZZ", 9, 26, 8, true ],
[ "635ZZ", 5, 19, 6, true ],
[ "6000ZZ", 10, 26, 8, true ],
[ "6001ZZ", 12, 28, 8, true ],
[ "6002ZZ", 15, 32, 9, true ],
[ "6003ZZ", 17, 35, 10, true ],
[ "6007ZZ", 35, 62, 14, true ],
[ "6200ZZ", 10, 30, 9, true ],
[ "6201ZZ", 12, 32, 10, true ],
[ "6202ZZ", 15, 35, 11, true ],
[ "6203ZZ", 17, 40, 12, true ],
[ "6204ZZ", 20, 47, 14, true ],
[ "6205ZZ", 25, 52, 15, true ],
[ "6206ZZ", 30, 62, 16, true ],
[ "6207ZZ", 35, 72, 17, true ],
[ "6208ZZ", 40, 80, 18, true ],
[ "6209ZZ", 45, 85, 19, true ],
[ "6210ZZ", 50, 90, 20, true ],
[ "6211ZZ", 55, 100, 21, true ],
[ "6212ZZ", 60, 110, 22, true ],
[ "6301ZZ", 12, 37, 12, true ],
[ "6302ZZ", 15, 42, 13, true ],
[ "6303ZZ", 17, 47, 14, true ],
[ "6304ZZ", 20, 52, 15, true ],
[ "6305ZZ", 25, 62, 17, true ],
[ "6306ZZ", 30, 72, 19, true ],
[ "6307ZZ", 35, 80, 21, true ],
[ "6308ZZ", 40, 90, 23, true ],
[ "6309ZZ", 45, 100, 25, true ],
[ "6310ZZ", 50, 110, 27, true ],
[ "6311ZZ", 55, 120, 29, true ],
[ "6312ZZ", 60, 130, 31, true ],
[ "6403ZZ", 17, 62, 17, true ],
[ "6800ZZ", 10, 19, 5, true ],
[ "6801ZZ", 12, 21, 5, true ],
[ "6802ZZ", 15, 24, 5, true ],
[ "6803ZZ", 17, 26, 5, true ],
[ "6804ZZ", 20, 32, 7, true ],
[ "6805ZZ", 25, 37, 7, true ],
[ "6806ZZ", 30, 42, 7, true ],
[ "6900ZZ", 10, 22, 6, true ],
[ "6901ZZ", 12, 24, 6, true ],
[ "6902ZZ", 15, 28, 7, true ],
[ "6903ZZ", 17, 30, 7, true ],
[ "6904ZZ", 20, 37, 9, true ],
[ "6905ZZ", 25, 42, 9, true ],
[ "6906ZZ", 30, 47, 9, true ],
[ "6907ZZ", 35, 55, 10, true ],
[ "6908ZZ", 40, 62, 12, true ],
[ "16002ZZ", 15, 22, 8, true ],
[ "16004ZZ", 20, 42, 8, true ],
[ "16005ZZ", 25, 47, 8, true ],
[ "16100ZZ", 10, 28, 8, true ],
[ "16101ZZ", 12, 30, 8, true ],
],
found = search([trade_size], data, 1)[0]
)
assert(found!=[], str("Unsupported ball bearing trade size: ", trade_size))
select(data[found], 1, -1);
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////
// LibFile: linear_bearings.scad
// Mounts for LMxUU style linear bearings.
// Mounts and models for LMxUU style linear bearings.
// Includes:
// include <BOSL2/std.scad>
// include <BOSL2/linear_bearings.scad>
@ -12,58 +12,7 @@
include <metric_screws.scad>
// Section: Functions
// Function: get_lmXuu_bearing_diam()
// Description: Get outside diameter, in mm, of a standard lmXuu bearing.
// Arguments:
// size = Inner size of lmXuu bearing, in mm.
function get_lmXuu_bearing_diam(size) = lookup(size, [
[ 4.0, 8.0],
[ 5.0, 10.0],
[ 6.0, 12.0],
[ 8.0, 15.0],
[ 10.0, 19.0],
[ 12.0, 21.0],
[ 13.0, 23.0],
[ 16.0, 28.0],
[ 20.0, 32.0],
[ 25.0, 40.0],
[ 30.0, 45.0],
[ 35.0, 52.0],
[ 40.0, 60.0],
[ 50.0, 80.0],
[ 60.0, 90.0],
[ 80.0, 120.0],
[100.0, 150.0]
]);
// Function: get_lmXuu_bearing_length()
// Description: Get length, in mm, of a standard lmXuu bearing.
// Arguments:
// size = Inner size of lmXuu bearing, in mm.
function get_lmXuu_bearing_length(size) = lookup(size, [
[ 4.0, 12.0],
[ 5.0, 15.0],
[ 6.0, 19.0],
[ 8.0, 24.0],
[ 10.0, 29.0],
[ 12.0, 30.0],
[ 13.0, 32.0],
[ 16.0, 37.0],
[ 20.0, 42.0],
[ 25.0, 59.0],
[ 30.0, 64.0],
[ 35.0, 70.0],
[ 40.0, 80.0],
[ 50.0, 100.0],
[ 60.0, 110.0],
[ 80.0, 140.0],
[100.0, 175.0]
]);
// Section: Generic Linear Bearings
// Module: linear_bearing_housing()
// Description:
@ -125,6 +74,34 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw
}
// Module: linear_bearing()
// Description:
// Creates a rough model of a generic linear ball bearing cartridge.
// Arguments:
// l/length = The length of the linear bearing cartridge.
// od = The outer diameter of the linear bearing cartridge.
// id = The inner diameter of the linear bearing cartridge.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example:
// linear_bearing(l=24, od=15, id=8);
module linear_bearing(l, od=15, id=8, length, anchor=CTR, spin=0, orient=UP) {
l = first_defined([l, length, 24]);
attachable(anchor,spin,orient, d=od, l=l) {
color("silver") {
tube(id=id, od=od, l=l-1);
tube(id=od-1, od=od, l=l);
tube(id=id, od=id+1, l=l);
tube(id=id+2, od=od-2, l=l);
}
children();
}
}
// Section: lmXuu Linear Bearings
// Module: lmXuu_housing()
// Description:
// Creates a model of a clamp to hold a standard sized lmXuu linear bearing cartridge.
@ -142,10 +119,65 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw
// lmXuu_housing(size=10, wall=2, tab=6, screwsize=2.5);
module lmXuu_housing(size=8, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, anchor=BOTTOM, spin=0, orient=UP)
{
d = get_lmXuu_bearing_diam(size);
l = get_lmXuu_bearing_length(size);
info = lmXuu_info(size);
d = info[0];
l = info[1];
linear_bearing_housing(d=d, l=l, tab=tab, gap=gap, wall=wall, tabwall=tabwall, screwsize=screwsize, orient=orient, spin=spin, anchor=anchor) children();
}
// Module: lmXuu_bearing()
// Description:
// Creates a model of an lmXuu linear ball bearing cartridge.
// Arguments:
// size = Standard lmXuu inner size.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example:
// lmXuu_bearing(size=10);
module lmXuu_bearing(size=8, anchor=CTR, spin=0, orient=UP) {
info = lmXuu_info(size);
linear_bearing(l=info[1], id=size, od=info[0], anchor=anchor, spin=spin, orient=orient) children();
}
// Section: lmXuu Linear Bearing Info
// Function: lmXuu_info()
// Description:
// Get dimensional info for a standard metric lmXuu linear bearing cartridge.
// Returns `[DIAM, LENGTH]` for the cylindrical cartridge.
// Arguments:
// size = Inner diameter of lmXuu bearing, in mm.
function lmXuu_info(size) =
let(
data = [
// size, diam, length
[ 4, 8, 12],
[ 5, 10, 15],
[ 6, 12, 19],
[ 8, 15, 24],
[ 10, 19, 29],
[ 12, 21, 30],
[ 13, 23, 32],
[ 16, 28, 37],
[ 20, 32, 42],
[ 25, 40, 59],
[ 30, 45, 64],
[ 35, 52, 70],
[ 40, 60, 80],
[ 50, 80, 100],
[ 60, 90, 110],
[ 80, 120, 140],
[100, 150, 175],
],
found = search([size], data, 1)[0]
)
assert(found!=[], str("Unsupported lmXuu linear bearing size: ", size))
select(data[found], 1, -1);
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -23,7 +23,8 @@
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D roundover/bead mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior fillet between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// Arguments:
// r = Radius of the roundover.
@ -38,10 +39,18 @@
// Example(2D): 2D Bead Mask
// mask2d_roundover(r=10,inset=2);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_roundover(r=10, inset=2);
// Example: Making an interior fillet
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_roundover(r=10);
module mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
path = mask2d_roundover(r=r,d=d,excess=excess,inset=inset);
attachable(anchor,spin, two_d=true, path=path) {
@ -77,7 +86,8 @@ function mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D cove mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior rounded shelf decoration between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// Arguments:
// r = Radius of the cove.
@ -92,10 +102,18 @@ function mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
// Example(2D): 2D Inset Cove Mask
// mask2d_cove(r=10,inset=3);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_cove(r=10, inset=2);
// Example: Making an interior rounded shelf
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_cove(r=5, inset=5);
module mask2d_cove(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
path = mask2d_cove(r=r,d=d,excess=excess,inset=inset);
attachable(anchor,spin, two_d=true, path=path) {
@ -135,7 +153,8 @@ function mask2d_cove(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D chamfer mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior chamfer between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// The edge parameter specifies the length of the chamfer's slanted edge. Alternatively you can give x or y to
// specify the width or height. Only one of x, y, or width is permitted.
@ -158,10 +177,18 @@ function mask2d_cove(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
// Example(2D): 2D Inset Chamfer Mask
// mask2d_chamfer(x=10, inset=2);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_chamfer(x=10, inset=2);
// Example: Making an interior chamfer
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_chamfer(edge=10);
module mask2d_chamfer(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTER,spin=0) {
path = mask2d_chamfer(x=x, y=y, edge=edge, angle=angle, excess=excess, inset=inset);
attachable(anchor,spin, two_d=true, path=path, extent=true) {
@ -200,7 +227,8 @@ function mask2d_chamfer(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTE
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D rabbet mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior shelf decoration between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// Arguments:
// size = The size of the rabbet, either as a scalar or an [X,Y] list.
@ -213,10 +241,18 @@ function mask2d_chamfer(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTE
// Example(2D): 2D Asymmetrical Rabbet Mask
// mask2d_rabbet(size=[5,10]);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_rabbet(size=10);
// Example: Making an interior shelf
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_rabbet(size=[5,10]);
module mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) {
path = mask2d_rabbet(size=size, excess=excess);
attachable(anchor,spin, two_d=true, path=path, extent=false) {
@ -250,7 +286,8 @@ function mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) =
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D dovetail mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior dovetail between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// Arguments:
// edge = The length of the edge of the dovetail.
@ -272,10 +309,18 @@ function mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) =
// Example(2D): 2D Inset Dovetail Mask
// mask2d_dovetail(x=10, inset=2);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
// mask2d_dovetail(x=10, inset=2);
// Example: Making an interior dovetail
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_dovetail(x=10);
module mask2d_dovetail(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, anchor=CENTER, spin=0) {
path = mask2d_dovetail(x=x, y=y, edge=edge, angle=angle, inset=inset, shelf=shelf, excess=excess);
attachable(anchor,spin, two_d=true, path=path) {
@ -316,7 +361,8 @@ function mask2d_dovetail(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, an
// See Also: corner_profile(), edge_profile(), face_profile()
// Description:
// Creates a 2D teardrop mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior teardrop fillet between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
// This is particularly useful to make partially rounded bottoms, that don't need support to print.
// Arguments:
@ -332,10 +378,18 @@ function mask2d_dovetail(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, an
// Example(2D): Using a Custom Angle
// mask2d_teardrop(r=10,angle=30);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile(BOT)
// mask2d_teardrop(r=10, angle=40);
// Example: Making an interior teardrop fillet
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_teardrop(r=10);
function mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) =
assert(is_finite(angle))
assert(angle>0 && angle<90)
@ -371,7 +425,8 @@ module mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) {
//
// Description:
// Creates a 2D Ogee mask shape that is useful for extruding into a 3D mask for a 90° edge.
// This 2D mask is designed to be `difference()`d away from the edge of a shape that is in the first (X+Y+) quadrant.
// Conversely, you can use that same extruded shape to make an interior ogee decoration between two walls at a 90º angle.
// As a 2D mask, this is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
// Since there are a number of shapes that fall under the name ogee, the shape of this mask is given as a pattern.
// Patterns are given as TYPE, VALUE pairs. ie: `["fillet",10, "xstep",2, "step",[5,5], ...]`. See Patterns below.
// If called as a function, this just returns a 2D path of the outline of the mask shape.
@ -400,7 +455,7 @@ module mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) {
// "ystep",1, "xstep",1 // Ending shoulder.
// ]);
// Example: Masking by Edge Attachment
// diff("mask")
// diff()
// cube([50,60,70],center=true)
// edge_profile(TOP)
// mask2d_ogee([
@ -408,6 +463,18 @@ module mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) {
// "fillet",5, "round",5, // S-curve.
// "ystep",1, "xstep",1 // Ending shoulder.
// ]);
// Example: Making an interior ogee
// %render() difference() {
// move(-[5,0,5]) cube(30, anchor=BOT+LEFT);
// cube(310, anchor=BOT+LEFT);
// }
// xrot(90)
// linear_extrude(height=30, center=true)
// mask2d_ogee([
// "xstep", 1, "round",5,
// "ystep",1, "fillet",5,
// "xstep", 1, "ystep", 1,
// ]);
module mask2d_ogee(pattern, excess=0.01, anchor=CENTER,spin=0) {
path = mask2d_ogee(pattern, excess=excess);
attachable(anchor,spin, two_d=true, path=path) {
@ -485,3 +552,4 @@ function mask2d_ogee(pattern, excess=0.01, anchor=CENTER, spin=0) =
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -385,6 +385,9 @@ module rounding_angled_corner_mask(r, ang=90, d, anchor=CENTER, spin=0, orient=U
// rounding = Radius of the edge rounding.
// ---
// d = Diameter of cylinder.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example:
// difference() {
// cylinder(r=50, h=50, center=false);
@ -402,14 +405,16 @@ module rounding_angled_corner_mask(r, ang=90, d, anchor=CENTER, spin=0, orient=U
// #tag("remove")
// rounding_cylinder_mask(d=30, rounding=5);
// }
function rounding_cylinder_mask(r, rounding, d) = no_function("rounding_cylinder_mask");
module rounding_cylinder_mask(r, rounding, d)
function rounding_cylinder_mask(r, rounding, d, anchor, spin, orient) = no_function("rounding_cylinder_mask");
module rounding_cylinder_mask(r, rounding, d, anchor=CENTER, spin=0, orient=UP)
{
no_children($children);
r = get_radius(r=r, d=d, dflt=1);
difference() {
cyl(r=r+rounding, l=rounding*2, anchor=CENTER);
cyl(r=r, l=rounding*3, rounding=rounding, anchor=TOP);
attachable(anchor,spin,orient, r=r+rounding, l=rounding*2) {
difference() {
cyl(r=r+rounding, l=rounding*2, anchor=CENTER);
cyl(r=r, l=rounding*3, rounding=rounding, anchor=TOP);
}
children();
}
}
@ -428,6 +433,7 @@ module rounding_cylinder_mask(r, rounding, d)
// d = Diameter of hole to rounding.
// rounding = Radius of the rounding.
// excess = The extra thickness of the mask. Default: `0.1`.
// ---
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
@ -473,6 +479,10 @@ module rounding_hole_mask(r, rounding, excess=0.1, d, anchor=CENTER, spin=0, ori
// d = Diameter of the mask rounding.
// angle = Maximum angle from vertical. Default: 45
// excess = Excess mask size. Default: 0.1
// ---
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example(VPD=50,VPR=[55,0,120]):
// teardrop_edge_mask(l=20, r=10, angle=40);
// Example(VPD=300,VPR=[75,0,25]):
@ -483,19 +493,16 @@ module rounding_hole_mask(r, rounding, excess=0.1, d, anchor=CENTER, spin=0, ori
// corner_mask(BOT)
// teardrop_corner_mask(r=10, angle=40);
// }
function teardrop_edge_mask(l, r, angle, excess=0.1, d) = no_function("teardrop_edge_mask");
module teardrop_edge_mask(l, r, angle, excess=0.1, d)
function teardrop_edge_mask(l, r, angle, excess=0.1, d, anchor, spin, orient) = no_function("teardrop_edge_mask");
module teardrop_edge_mask(l, r, angle, excess=0.1, d, anchor=CTR, spin=0, orient=UP)
{
no_children($children);
assert(is_num(l));
assert(is_num(angle));
assert(is_num(excess));
assert(angle>0 && angle<90);
r = get_radius(r=r, d=d, dflt=1);
difference() {
translate(-[1,1,0]*excess) cube([r+excess,r+excess,l], anchor=FWD+LEFT);
translate([r,r,0]) teardrop(r=r, l=l+1, cap_h=r, ang=angle, orient=FWD);
}
path = mask2d_teardrop(r=r, angle=angle, excess=excess);
linear_sweep(path, height=l, center=true, atype="bbox", anchor=anchor, spin=spin, orient=orient) children();
}
@ -510,6 +517,9 @@ module teardrop_edge_mask(l, r, angle, excess=0.1, d)
// excess = Excess mask size. Default: 0.1
// ---
// d = Diameter of the mask rounding.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Example:
// teardrop_corner_mask(r=20, angle=40);
// Example:
@ -520,17 +530,21 @@ module teardrop_edge_mask(l, r, angle, excess=0.1, d)
// corner_mask(BOT)
// teardrop_corner_mask(r=10, angle=40);
// }
function teardrop_corner_mask(r, angle, excess=0.1, d) = no_function("teardrop_corner_mask");
module teardrop_corner_mask(r, angle, excess=0.1, d)
function teardrop_corner_mask(r, angle, excess=0.1, d, anchor, spin, orient) = no_function("teardrop_corner_mask");
module teardrop_corner_mask(r, angle, excess=0.1, d, anchor=CTR, spin=0, orient=UP)
{
no_children($children);
assert(is_num(angle));
assert(is_num(excess));
assert(angle>0 && angle<90);
r = get_radius(r=r, d=d, dflt=1);
difference() {
translate(-[1,1,1]*excess) cube(r+excess, center=false);
translate([1,1,1]*r) onion(r=r, ang=angle, orient=DOWN);
size = (r+excess) * [1,1,1];
midpt = (r-excess)/2 * [1,1,1];
attachable(anchor,spin,orient, size=size, offset=midpt) {
difference() {
translate(-[1,1,1]*excess) cube(r+excess, center=false);
translate([1,1,1]*r) onion(r=r, ang=angle, orient=DOWN);
}
children();
}
}

View file

@ -4,7 +4,7 @@
// that produce a VNF. Also included are shortcuts cylinders in each orientation and extended versions of
// the standard modules that provide roundovers and chamfers. The spheroid() module provides
// several different ways to make a sphere, and the text modules let you write text on a path
// so you can place it on a curved object. A ruler lets you measure objects.
// so you can place it on a curved object. A ruler lets you measure objects.
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Basic Modeling
@ -319,7 +319,7 @@ module cuboid(
teardrop = is_bool(teardrop)&&teardrop? 45 : teardrop;
chamfer = approx(chamfer,0) ? undef : chamfer;
rounding = approx(rounding,0) ? undef : rounding;
checks =
checks =
assert(is_vector(size,3))
assert(all_positive(size))
assert(is_undef(chamfer) || is_finite(chamfer),"chamfer must be a finite value")
@ -574,7 +574,7 @@ function cuboid(
// Creates a rectangular prismoid shape with optional roundovers and chamfering.
// You can only round or chamfer the vertical(ish) edges. For those edges, you can
// specify rounding and/or chamferring per-edge, and for top and bottom separately.
// If you want to round the bottom or top edges see {{rounded_prism()}}.
// If you want to round the bottom or top edges see {{rounded_prism()}}.
//
// Arguments:
// size1 = [width, length] of the bottom end of the prism.
@ -657,7 +657,7 @@ module prismoid(
eps = pow(2,-14);
size1 = is_num(size1)? [size1,size1] : size1;
size2 = is_num(size2)? [size2,size2] : size2;
checks2 =
checks2 =
assert(all_nonnegative(size1))
assert(all_nonnegative(size2))
assert(size1.x + size2.x > 0)
@ -951,7 +951,7 @@ module rect_tube(
isize2 = is_def(is2)? is2 :
(is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
undef;
checks2 =
checks2 =
assert(wall==undef || is_num(wall))
assert(size1!=undef, "Bad size/size1 argument.")
assert(size2!=undef, "Bad size/size2 argument.")
@ -1155,10 +1155,15 @@ function cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
// cyl(l|h, r|d, rounding2=, ...);
// cyl(l|h, r|d, rounding1=, rounding2=, ...);
//
// Usage: Textured Cylinders
// cyl(l|h, r|d, texture=, [tex_size=]|[tex_counts=], [tex_scale=], [tex_rot=], [tex_samples=], [tex_style=], [tex_taper=], [tex_inset=], ...);
// cyl(l|h, r1=, r2=, texture=, [tex_size=]|[tex_counts=], [tex_scale=], [tex_rot=], [tex_samples=], [tex_style=], [tex_taper=], [tex_inset=], ...);
// cyl(l|h, d1=, d2=, texture=, [tex_size=]|[tex_counts=], [tex_scale=], [tex_rot=], [tex_samples=], [tex_style=], [tex_taper=], [tex_inset=], ...);
//
// Topics: Cylinders, Textures, Rounding, Chamfers
//
// Description:
// Creates cylinders in various anchorings and orientations, with optional rounding and chamfers.
// Creates cylinders in various anchorings and orientations, with optional rounding, chamfers, or textures.
// You can use `h` and `l` interchangably, and all variants allow specifying size by either `r`|`d`,
// or `r1`|`d1` and `r2`|`d2`. Note: the chamfers and rounding cannot be cumulatively longer than
// the cylinder's length.
@ -1522,7 +1527,8 @@ module cyl(
[0,l/2]
];
rotate_extrude(convexity=2) polygon(path);
vnf = rotate_sweep(path);
vnf_polyhedron(vnf, convexity=2);
}
}
children();
@ -2007,19 +2013,19 @@ function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=
// When called as a function, returns a [VNF](vnf.scad) for a spheroid.
// The exact triangulation of this spheroid can be controlled via the `style=`
// argument, where the value can be one of `"orig"`, `"aligned"`, `"stagger"`,
// `"octa"`, or `"icosa"`.
// `"octa"`, or `"icosa"`.
// - `style="orig"` constructs a sphere the same way that the OpenSCAD `sphere()` built-in does.
// - `style="aligned"` constructs a sphere where, if `$fn` is a multiple of 4, it has vertices at all axis maxima and minima. ie: its bounding box is exactly the sphere diameter in length on all three axes. This is the default.
// - `style="stagger"` forms a sphere where all faces are triangular, but the top and bottom poles have thinner triangles.
// - `style="octa"` forms a sphere by subdividing an octahedron. This makes more uniform faces over the entirety of the sphere, and guarantees the bounding box is the sphere diameter in size on all axes. The effective `$fn` value is quantized to a multiple of 4. This is used in constructing rounded corners for various other shapes.
// - `style="icosa"` forms a sphere by subdividing an icosahedron. This makes even more uniform faces over the whole sphere. The effective `$fn` value is quantized to a multiple of 5. This sphere has a guaranteed bounding box when `$fn` is a multiple of 10.
// - `style="icosa"` forms a sphere by subdividing an icosahedron. This makes even more uniform faces over the whole sphere. The effective `$fn` value is quantized to a multiple of 5. This sphere has a guaranteed bounding box when `$fn` is a multiple of 10.
// .
// By default the object spheroid() produces is a polyhedron whose vertices all lie on the requested sphere. This means
// the approximating polyhedron is inscribed in the sphere.
// The `circum` argument requests a circumscribing sphere, where the true sphere is
// inside and tangent to all the faces of the approximating polyhedron. To produce
// a circumscribing polyhedron, we use the dual polyhedron of the basic form. The dual of a polyhedron is
// a new polyhedron whose vertices are obtained from the faces of the parent polyhedron.
// a new polyhedron whose vertices are obtained from the faces of the parent polyhedron.
// The "orig" and "align" forms are duals of each other. If you request a circumscribing polyhedron in
// these styles then the polyhedron will look the same as the default inscribing form. But for the other
// styles, the duals are completely different from their parents, and from each other. Generation of the circumscribed versions (duals)
@ -2030,7 +2036,7 @@ function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=
// but is undersized on the Z axis. With style="octa" the circumscribed sphere has faces at each axis, so
// the radius on the axes is equal to the specified radius, which is the *minimum* radius of the circumscribed sphere.
// The same thing is true for style="icosa" when $fn is a multiple of 10. This would enable you to create spherical
// holes with guaranteed on-axis dimensions.
// holes with guaranteed on-axis dimensions.
// Arguments:
// r = Radius of the spheroid.
// style = The style of the spheroid's construction. One of "orig", "aligned", "stagger", "octa", or "icosa". Default: "aligned"
@ -2052,14 +2058,14 @@ function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=
// spheroid(d=100, style="stagger", $fn=10);
// Example: style="stagger" with circum=true
// spheroid(d=100, style="stagger", circum=true, $fn=10);
// Example: style="octa", octahedral based tesselation. In this style, $fn is quantized to a multiple of 4.
// Example: style="octa", octahedral based tesselation. In this style, $fn is quantized to a multiple of 4.
// spheroid(d=100, style="octa", $fn=10);
// Example: style="octa", with circum=true, produces mostly very irregular hexagonal faces
// spheroid(d=100, style="octa", circum=true, $fn=16);
// Example: style="icosa", icosahedral based tesselation. In this style, $fn is quantized to a multiple of 5.
// spheroid(d=100, style="icosa", $fn=10);
// spheroid(d=100, style="icosa", $fn=10);
// Example: style="icosa", circum=true. This style has hexagons and 12 pentagons, similar to (but not the same as) a soccer ball.
// spheroid(d=100, style="icosa", circum=true, $fn=10);
// spheroid(d=100, style="icosa", circum=true, $fn=10);
// Example: Anchoring
// spheroid(d=100, anchor=FRONT);
// Example: Spin
@ -2071,10 +2077,10 @@ function sphere(r, d, circum=false, style="orig", anchor=CENTER, spin=0, orient=
// Example: Called as Function
// vnf = spheroid(d=100, style="icosa");
// vnf_polyhedron(vnf);
// Example: With "orig" the circumscribing sphere has the same form. The green sphere is a tiny bit oversized so it pokes through the low points in the circumscribed sphere with low $fn. This demonstrates that these spheres are in fact circumscribing.
// Example: With "orig" the circumscribing sphere has the same form. The green sphere is a tiny bit oversized so it pokes through the low points in the circumscribed sphere with low $fn. This demonstrates that these spheres are in fact circumscribing.
// color("green")spheroid(r=10.01, $fn=256);
// spheroid(r=10, style="orig", circum=true, $fn=16);
// Example: With "aligned" the same is true: the circumscribing sphere is also aligned, if $fn is divisible by 4.
// Example: With "aligned" the same is true: the circumscribing sphere is also aligned, if $fn is divisible by 4.
// color("green")spheroid(r=10.01, $fn=256);
// spheroid(r=10, style="aligned", circum=true, $fn=16);
// Example: For the other styles, the circumscribing sphere is different, as shown here with "stagger"
@ -2118,8 +2124,8 @@ module spheroid(r, style="aligned", d, circum=false, dual=false, anchor=CENTER,
// p is a list of 3 points defining a triangle in any dimension. N is the number of extra points
// to add, so output triangle has N+2 points on each side.
function _subsample_triangle(p,N) =
// to add, so output triangle has N+2 points on each side.
function _subsample_triangle(p,N) =
[for(i=[0:N+1]) [for (j=[0:N+1-i]) unit(lerp(p[0],p[1],i/(N+1)) + (p[2]-p[0])*j/(N+1))]];
@ -2165,7 +2171,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
[reorient(anchor,spin,orient, r=r, p=dualvert), faces]
:
style=="icosa" ? // subdivide faces of an icosahedron and project them onto a sphere
let(
let(
N = icosa_steps-1,
// construct an icosahedron
icovert=[ for(i=[-1,1], j=[-1,1]) each [[0,i,j*PHI], [i,j*PHI,0], [j*PHI,0,i]]],
@ -2188,7 +2194,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
// Expand to full face list
fullfaces = [for(i=idx(tri_list)) each [for(f=faces) f+i*size]],
fullvert = flatten(flatten(tri_list)) // eliminate triangle structure
)
)
[reorient(anchor,spin,orient, r=r, p=fullvert), fullfaces]
:
let(
@ -2231,10 +2237,10 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
[
for (i=idx(meridians), j=[0:1:meridians[i]-1])
spherical_to_xyz(r, j*360/meridians[i], i*180/(len(meridians)-1))
]
]
: assert(in_list(style,["orig","aligned","stagger","octa","icosa"])),
lv = len(verts),
faces = circum && style=="stagger" ?
faces = circum && style=="stagger" ?
let(ptcount=2*hsides)
[
[for(i=[ptcount-2:-2:0]) i],
@ -2252,7 +2258,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
? [(j*2+3)%ptcount, j*2+1, lv-ptcount+(2+j*2)%ptcount, lv-ptcount+(3+j*2)%ptcount, lv-ptcount+(4+j*2)%ptcount]
: [(j*2+3)%ptcount, j*2+1, lv-ptcount+(1+j*2)%ptcount, lv-ptcount+(j*2)%ptcount, lv-ptcount+(3+j*2)%ptcount],
[for(i=[1:2:ptcount-1]) i],
]
]
: style=="aligned" || style=="stagger" ? // includes case of aligned with circum == true
[
for (i=[0:1:hsides-1])
@ -2270,7 +2276,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
] : [
[base+j, base+(j+1)%hsides, base+hsides+(j+1)%hsides],
[base+j, base+hsides+(j+1)%hsides, base+hsides+j],
]
]
)
]
: style=="orig"? [
@ -2280,7 +2286,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
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=="octa"?*/
let(
@ -2288,7 +2294,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
0, 1,
for (i = [1:1:octa_steps]) i*4,
for (i = [octa_steps-1:-1:1]) i*4,
1,
1,
],
offs = cumsum(meridians),
pc = last(offs)-1,
@ -2318,7 +2324,7 @@ function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, or
[p5, p7, p8],
if (k<m-1) [p5, p8, p6],
],
]
]
) [reorient(anchor,spin,orient, r=r, p=verts), faces];
@ -2687,7 +2693,7 @@ function onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) =
// Usage:
// text3d(text, [h], [size], [font], ...);
// Description:
// Creates a 3D text block that supports anchoring and attachment to attachable objects. You cannot attach children to text.
// Creates a 3D text block that supports anchoring and attachment to attachable objects. You cannot attach children to text.
// .
// Historically fonts were specified by their "body size", the height of the metal body
// on which the glyphs were cast. This means the size was an upper bound on the size
@ -2707,7 +2713,7 @@ function onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) =
// font size, you should multiply your desired size by 0.72.
// .
// To find the fonts that you have available in your OpenSCAD installation,
// go to the Help menu and select "Font List".
// go to the Help menu and select "Font List".
// Arguments:
// text = Text to create.
// h = Extrusion height for the text. Default: 1
@ -2810,21 +2816,21 @@ function _cut_interp(pathcut, path, data) =
// 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.
// .
// 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.
// 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.
// 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).
// 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
@ -2851,7 +2857,7 @@ function _cut_interp(pathcut, path, data) =
// font size, you should multiply your desired size by 0.72.
// .
// To find the fonts that you have available in your OpenSCAD installation,
// go to the Help menu and select "Font List".
// go to the Help menu and select "Font List".
// Arguments:
// path = path to place the text on
// text = text to create
@ -2867,7 +2873,7 @@ function _cut_interp(pathcut, path, data) =
// 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
// kern = scalar or array giving size adjustments for each letter. Default: 0
// Example(3D,NoScales): 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.
// Example(3D,NoScales): 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);
@ -2875,11 +2881,11 @@ function _cut_interp(pathcut, path, data) =
// 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(3D,NoScales): 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.
// Example(3D,NoScales): 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(3D,Med,NoScales): text debossed onto a cylinder in a spiral. The text is 1 unit deep because it is half in, half out.
// Example(3D,Med,NoScales): 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);
@ -2888,7 +2894,7 @@ function _cut_interp(pathcut, path, data) =
// cyl(d=50, l=50, $fn=120);
// path_text(spiral, text, size=5, lettersize=5/1.2, font="Courier", thickness=2);
// }
// Example(3D,Med,NoScales): Same example but text embossed. Make sure you have enough depth for the letters to fully overlap the object.
// Example(3D,Med,NoScales): 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);
@ -2899,11 +2905,11 @@ function _cut_interp(pathcut, path, data) =
// 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(3D,NoScales): If we use top to orient the text upward, the text baseline is no longer aligned with the path.
// Example(3D,NoScales): 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(3D,Med,NoScales): 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.
// Example(3D,Med,NoScales): 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)
@ -2911,7 +2917,7 @@ function _cut_interp(pathcut, path, data) =
// 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(3D,Med,NoScales): The path center of curvature changes, and the text flips.
// Example(3D,Med,NoScales): 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);
@ -2955,7 +2961,7 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
kern = force_list(kern, len(text));
dummy3 = assert(is_list(kern) && len(kern)==len(text), "kern must be a scalar or list whose length is len(text)");
lsize = kern + (
is_def(lettersize) ? force_list(lettersize, len(text))
: textmetrics ? [for(letter=text) let(t=textmetrics(letter, font=font, size=size)) t.advance[0]]
@ -2968,9 +2974,10 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
pts = path_cut_points(path, add_scalar([0, each cumsum(lsize)],start+lsize[0]/2), direction=true);
usernorm = is_def(normal);
usetop = is_def(top);
normpts = is_undef(normal) ? (reverse?1:-1)*column(pts,3) : _cut_interp(pts,path, normal);
toppts = is_undef(top) ? undef : _cut_interp(pts,path,top);
for (i = idx(text)) {
@ -3404,7 +3411,7 @@ module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3
widths = width * widthfactor * [for(logsize = [0:-1:-depth+1]) pow(pipscale,-logsize)];
offsets = concat([0],cumsum(widths));
attachable(anchor,spin,orient, size=[length,width,thickness]) {
translate([-length/2, -width/2, 0])
translate([-length/2, -width/2, 0])
for(i=[0:1:len(scales)-1]) {
count = ceil(length/scales[i]);
fontsize = 0.5*min(widths[i], scales[i]/ceil(log(count*scales[i]/unit)));
@ -3412,7 +3419,7 @@ module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3
xcopies(scales[i], n=count, sp=[0,0,0]) union() {
actlen = ($idx<count-1) || approx(length%scales[i],0) ? scales[i] : length % scales[i];
color(colors[$idx%2], alpha=alpha) {
w = i>0 ? quantup(widths[i],1/1024) : widths[i]; // What is the i>0 test supposed to do here?
w = i>0 ? quantup(widths[i],1/1024) : widths[i]; // What is the i>0 test supposed to do here?
cube([quantup(actlen,1/1024),quantup(w,1/1024),thickness], anchor=FRONT+LEFT);
}
mark =

View file

@ -508,6 +508,8 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
// Function&Module: linear_sweep()
// Usage:
// linear_sweep(region, [height], [center=], [slices=], [twist=], [scale=], [style=], [convexity=]) [ATTACHMENTS];
// Usage: With Texturing
// linear_sweep(region, [height], [center=], texture=, [tex_size=]|[tex_counts=], [tex_scale=], [style=], [tex_samples=], ...) [ATTACHMENTS];
// Description:
// If called as a module, creates a polyhedron that is the linear extrusion of the given 2D region or polygon.
// If called as a function, returns a VNF that can be used to generate a polyhedron of the linear extrusion
@ -541,6 +543,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
// Anchor Types:
// "hull" = Anchors to the virtual convex hull of the shape.
// "intersect" = Anchors to the surface of the shape.
// "bbox" = Anchors to the bounding box of the extruded shape.
// Extra Anchors:
// "origin" = Centers the extruded shape vertically only, but keeps the original path positions in the X and Y. Oriented UP.
// "original_base" = Keeps the original path positions in the X and Y, but at the bottom of the extrusion. Oriented UP.
@ -662,9 +665,16 @@ module linear_sweep(
named_anchor("original_base", [0,0,-h/2], UP)
];
cp = default(cp, "centroid");
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="intersect"? attach_geom(cp=cp, region=region, h=h, extent=false, shift=shift, scale=scale, twist=twist, anchors=anchors) :
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="intersect"? attach_geom(cp=cp, region=region, h=h, extent=false, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="bbox"?
let(
bounds = pointlist_bounds(flatten(region)),
size = bounds[1] - bounds[0],
midpt = (bounds[0] + bounds[1])/2
)
attach_geom(cp=[0,0,0], size=point3d(size,h), offset=point3d(midpt), shift=shift, scale=scale, twist=twist, anchors=anchors) :
assert(in_list(atype, ["hull","intersect","bbox"]), "Anchor type must be \"hull\", \"intersect\", or \"bbox\".");
attachable(anchor,spin,orient, geom=geom) {
vnf_polyhedron(vnf, convexity=convexity);
children();
@ -744,20 +754,29 @@ function linear_sweep(
named_anchor("original_base", [0,0,-h/2], UP)
],
cp = default(cp, "centroid"),
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="intersect"? attach_geom(cp=cp, region=region, h=h, extent=false, shift=shift, scale=scale, twist=twist, anchors=anchors) :
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"")
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="intersect"? attach_geom(cp=cp, region=region, h=h, extent=false, shift=shift, scale=scale, twist=twist, anchors=anchors) :
atype=="bbox"?
let(
bounds = pointlist_bounds(flatten(region)),
size = bounds[1] - bounds[0],
midpt = (bounds[0] + bounds[1])/2
)
attach_geom(cp=[0,0,0], size=point3d(size,h), offset=point3d(midpt), shift=shift, scale=scale, twist=twist, anchors=anchors) :
assert(in_list(atype, ["hull","intersect","bbox"]), "Anchor type must be \"hull\", \"intersect\", or \"bbox\".")
) reorient(anchor,spin,orient, geom=geom, p=vnf);
// Function&Module: rotate_sweep()
// Usage: As Function
// vnf = rotate_sweep(shape, angle, ...);
// vnf = rotate_sweep(shape, [angle], ...);
// Usage: As Module
// rotate_sweep(shape, angle, ...) [ATTACHMENTS];
// rotate_sweep(shape, [angle], ...) [ATTACHMENTS];
// Usage: With Texturing
// rotate_sweep(shape, texture=, [tex_size=]|[tex_counts=], [tex_scale=], [tex_samples=], [tex_rot=], [tex_inset=], ...) [ATTACHMENTS];
// Topics: Extrusion, Sweep, Revolution
// Description:
// Takes a polygon or [region](regions.scad) and sweeps it in a rotation around the Z axis.
// Takes a polygon or [region](regions.scad) and sweeps it in a rotation around the Z axis, with optional texturing.
// When called as a function, returns a [VNF](vnf.scad).
// When called as a module, creates the sweep as geometry.
// Arguments:

View file

@ -2,27 +2,15 @@ include <../std.scad>
include <../linear_bearings.scad>
module test_get_lmXuu_bearing_diam() {
assert_equal(get_lmXuu_bearing_diam(4), 8);
assert_equal(get_lmXuu_bearing_diam(8), 15);
assert_equal(get_lmXuu_bearing_diam(10), 19);
assert_equal(get_lmXuu_bearing_diam(25), 40);
assert_equal(get_lmXuu_bearing_diam(50), 80);
assert_equal(get_lmXuu_bearing_diam(100), 150);
module test_lmXuu_info() {
assert_equal(lmXuu_info(4), [8, 12]);
assert_equal(lmXuu_info(8), [15, 24]);
assert_equal(lmXuu_info(10), [19, 29]);
assert_equal(lmXuu_info(25), [40, 59]);
assert_equal(lmXuu_info(50), [80, 100]);
assert_equal(lmXuu_info(100), [150, 175]);
}
test_get_lmXuu_bearing_diam();
test_lmXuu_info();
module test_get_lmXuu_bearing_length() {
assert_equal(get_lmXuu_bearing_length(4), 12);
assert_equal(get_lmXuu_bearing_length(8), 24);
assert_equal(get_lmXuu_bearing_length(10), 29);
assert_equal(get_lmXuu_bearing_length(25), 59);
assert_equal(get_lmXuu_bearing_length(50), 100);
assert_equal(get_lmXuu_bearing_length(100), 175);
}
test_get_lmXuu_bearing_length();
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// vim: expandtab shiftwidth=4 softtabstop=4 nowrap