2017-08-30 00:00:16 +00:00
//////////////////////////////////////////////////////////////////////
2019-03-23 04:13:18 +00:00
// LibFile: shapes.scad
// Common useful shapes and structured objects.
// To use, add the following lines to the beginning of your file:
// ```
2019-04-19 07:25:10 +00:00
// include <BOSL2/std.scad>
2019-03-23 04:13:18 +00:00
// ```
2017-08-30 00:00:16 +00:00
//////////////////////////////////////////////////////////////////////
/*
BSD 2 - Clause License
2019-04-20 00:02:17 +00:00
Copyright ( c ) 2017 - 2019 , Revar Desmera
2017-08-30 00:00:16 +00:00
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
* Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
2019-03-23 04:13:18 +00:00
// Section: Cuboids
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
// Module: cuboid()
//
// Description:
// Creates a cube or cuboid object, with optional chamfering or filleting/rounding.
//
// Arguments:
2019-02-27 11:56:34 +00:00
// size = The size of the cube.
// chamfer = Size of chamfer, inset from sides. Default: No chamferring.
// fillet = Radius of fillet for edge rounding. Default: No filleting.
2019-03-23 04:13:18 +00:00
// edges = Edges to chamfer/fillet. Use `EDGE` constants from constants.scad. Default: `EDGES_ALL`
// trimcorners = If true, rounds or chamfers corners where three chamferred/filleted edges meet. Default: `true`
2019-04-19 06:32:17 +00:00
// p1 = Align the cuboid's corner at `p1`, if given. Forces `align=UP+BACK+RIGHT`.
2019-03-23 04:13:18 +00:00
// p2 = If given with `p1`, defines the cornerpoints of the cuboid.
2019-04-19 06:32:17 +00:00
// align = The side of the origin to align to. Use constants from `constants.scad`. Default: `CENTER`
// center = If given, overrides `align`. A true value sets `align=CENTER`, false sets `align=UP+BACK+RIGHT`.
2019-03-23 04:13:18 +00:00
//
// Example: Simple regular cube.
2019-02-27 11:56:34 +00:00
// cuboid(40);
2019-03-23 04:13:18 +00:00
// Example: Cube with minimum cornerpoint given.
// cuboid(20, p1=[10,0,0]);
// Example: Rectangular cube, with given X, Y, and Z sizes.
// cuboid([20,40,50]);
// Example: Rectangular cube defined by opposing cornerpoints.
// cuboid(p1=[0,10,0], p2=[20,30,30]);
// Example: Rectangular cube with chamferred edges and corners.
// cuboid([30,40,50], chamfer=5);
// Example: Rectangular cube with chamferred edges, without trimmed corners.
// cuboid([30,40,50], chamfer=5, trimcorners=false);
// Example: Rectangular cube with rounded edges and corners.
// cuboid([30,40,50], fillet=10);
// Example: Rectangular cube with rounded edges, without trimmed corners.
// cuboid([30,40,50], fillet=10, trimcorners=false);
// Example: Rectangular cube with only some edges chamferred.
// cuboid([30,40,50], chamfer=5, edges=EDGE_TOP_FR+EDGE_TOP_RT+EDGE_FR_RT, $fn=24);
// Example: Rectangular cube with only some edges rounded.
// cuboid([30,40,50], fillet=5, edges=EDGE_TOP_FR+EDGE_TOP_RT+EDGE_FR_RT, $fn=24);
2019-04-22 08:08:41 +00:00
// Example: Standard Connectors
// cuboid(40, chamfer=5) show_connectors();
2019-02-27 11:56:34 +00:00
module cuboid (
size = [ 1 , 1 , 1 ] ,
2019-03-23 04:13:18 +00:00
p1 = undef , p2 = undef ,
2019-02-27 11:56:34 +00:00
chamfer = undef ,
fillet = undef ,
edges = EDGES_ALL ,
2019-03-23 04:13:18 +00:00
trimcorners = true ,
align = [ 0 , 0 , 0 ] ,
center = undef
2019-02-27 11:56:34 +00:00
) {
2019-03-23 04:13:18 +00:00
size = scalar_vec3 ( size ) ;
2019-04-20 00:02:17 +00:00
if ( ! is_undef ( p1 ) ) {
if ( ! is_undef ( p2 ) ) {
2019-03-23 04:13:18 +00:00
translate ( [ for ( v = array_zip ( [ p1 , p2 ] , 0 ) ) min ( v ) ] ) {
2019-04-22 08:08:41 +00:00
cuboid ( size = vabs ( p2 - p1 ) , chamfer = chamfer , fillet = fillet , edges = edges , trimcorners = trimcorners , align = ALLNEG ) children ( ) ;
2019-02-27 11:56:34 +00:00
}
} else {
2019-03-23 04:13:18 +00:00
translate ( p1 ) {
2019-04-22 08:08:41 +00:00
cuboid ( size = size , chamfer = chamfer , fillet = fillet , edges = edges , trimcorners = trimcorners , align = ALLNEG ) children ( ) ;
2019-02-27 11:56:34 +00:00
}
}
2019-03-23 04:13:18 +00:00
} else {
2019-04-20 00:02:17 +00:00
if ( chamfer ! = undef ) assert ( chamfer < = min ( size ) / 2 , "chamfer must be smaller than half the cube width, length, or height." ) ;
if ( fillet ! = undef ) assert ( fillet < = min ( size ) / 2 , "fillet must be smaller than half the cube width, length, or height." ) ;
2019-04-17 02:16:50 +00:00
majrots = [ [ 0 , 90 , 0 ] , [ 90 , 0 , 0 ] , [ 0 , 0 , 0 ] ] ;
2019-04-19 06:32:17 +00:00
orient_and_align ( size , ORIENT_Z , align , center = center , noncentered = ALLPOS , chain = true ) {
2019-03-23 04:13:18 +00:00
if ( chamfer ! = undef ) {
isize = [ for ( v = size ) max ( 0.001 , v - 2 * chamfer ) ] ;
if ( edges = = EDGES_ALL && trimcorners ) {
hull ( ) {
2019-04-17 02:16:50 +00:00
cube ( [ size . x , isize . y , isize . z ] , center = true ) ;
cube ( [ isize . x , size . y , isize . z ] , center = true ) ;
cube ( [ isize . x , isize . y , size . z ] , center = true ) ;
2019-03-23 04:13:18 +00:00
}
} else {
difference ( ) {
cube ( size , center = true ) ;
// Chamfer edges
for ( i = [ 0 : 3 ] , axis = [ 0 : 2 ] ) {
if ( edges [ axis ] [ i ] > 0 ) {
translate ( vmul ( EDGE_OFFSETS [ axis ] [ i ] , size / 2 ) ) {
rotate ( majrots [ axis ] ) {
zrot ( 45 ) cube ( [ chamfer * sqrt ( 2 ) , chamfer * sqrt ( 2 ) , size [ axis ] + 0.01 ] , center = true ) ;
}
2019-02-27 11:56:34 +00:00
}
}
}
2019-03-23 04:13:18 +00:00
// Chamfer triple-edge corners.
if ( trimcorners ) {
for ( za = [ - 1 , 1 ] , ya = [ - 1 , 1 ] , xa = [ - 1 , 1 ] ) {
if ( corner_edge_count ( edges , [ xa , ya , za ] ) > 2 ) {
translate ( vmul ( [ xa , ya , za ] / 2 , size - [ 1 , 1 , 1 ] * chamfer * 4 / 3 ) ) {
2019-04-19 06:32:17 +00:00
rot ( from = UP , to = [ xa , ya , za ] ) {
2019-03-23 04:13:18 +00:00
upcube ( chamfer * 3 ) ;
}
2019-02-27 11:56:34 +00:00
}
}
}
}
}
}
2019-03-23 04:13:18 +00:00
} else if ( fillet ! = undef ) {
sides = quantup ( segs ( fillet ) , 4 ) ;
sc = 1 / cos ( 180 / sides ) ;
isize = [ for ( v = size ) max ( 0.001 , v - 2 * fillet ) ] ;
if ( edges = = EDGES_ALL ) {
minkowski ( ) {
cube ( isize , center = true ) ;
if ( trimcorners ) {
sphere ( r = fillet * sc , $fn = sides ) ;
} else {
intersection ( ) {
zrot ( 180 / sides ) cylinder ( r = fillet * sc , h = fillet * 2 , center = true , $fn = sides ) ;
rotate ( [ 90 , 0 , 0 ] ) zrot ( 180 / sides ) cylinder ( r = fillet * sc , h = fillet * 2 , center = true , $fn = sides ) ;
rotate ( [ 0 , 90 , 0 ] ) zrot ( 180 / sides ) cylinder ( r = fillet * sc , h = fillet * 2 , center = true , $fn = sides ) ;
}
2019-02-27 11:56:34 +00:00
}
}
2019-03-23 04:13:18 +00:00
} else {
difference ( ) {
cube ( size , center = true ) ;
2019-02-27 11:56:34 +00:00
2019-03-23 04:13:18 +00:00
// Round edges.
for ( i = [ 0 : 3 ] , axis = [ 0 : 2 ] ) {
if ( edges [ axis ] [ i ] > 0 ) {
difference ( ) {
translate ( vmul ( EDGE_OFFSETS [ axis ] [ i ] , size / 2 ) ) {
rotate ( majrots [ axis ] ) cube ( [ fillet * 2 , fillet * 2 , size [ axis ] + 0.1 ] , center = true ) ;
}
translate ( vmul ( EDGE_OFFSETS [ axis ] [ i ] , size / 2 - [ 1 , 1 , 1 ] * fillet ) ) {
rotate ( majrots [ axis ] ) zrot ( 180 / sides ) cylinder ( h = size [ axis ] + 0.2 , r = fillet * sc , center = true , $fn = sides ) ;
}
2019-02-27 11:56:34 +00:00
}
}
}
2019-03-23 04:13:18 +00:00
// Round triple-edge corners.
if ( trimcorners ) {
for ( za = [ - 1 , 1 ] , ya = [ - 1 , 1 ] , xa = [ - 1 , 1 ] ) {
if ( corner_edge_count ( edges , [ xa , ya , za ] ) > 2 ) {
difference ( ) {
translate ( vmul ( [ xa , ya , za ] , size / 2 ) ) {
cube ( fillet * 2 , center = true ) ;
}
translate ( vmul ( [ xa , ya , za ] , size / 2 - [ 1 , 1 , 1 ] * fillet ) ) {
zrot ( 180 / sides ) sphere ( r = fillet * sc * sc , $fn = sides ) ;
}
2019-02-27 11:56:34 +00:00
}
}
}
}
}
}
2019-03-23 04:13:18 +00:00
} else {
cube ( size = size , center = true ) ;
2019-02-27 11:56:34 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-02-27 11:56:34 +00:00
}
2019-01-29 12:29:42 +00:00
}
}
2019-02-27 11:56:34 +00:00
2019-03-23 04:13:18 +00:00
// Module: leftcube()
//
// Description:
// Makes a cube that is aligned on the left side of the origin.
//
// Usage:
// leftcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
// Example:
// leftcube([20,30,40]);
module leftcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; left ( siz [ 0 ] / 2 ) cube ( size = size , center = true ) ; }
// Module: rightcube()
//
// Description:
// Makes a cube that is aligned on the right side of the origin.
//
// Usage:
// rightcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// rightcube([20,30,40]);
module rightcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; right ( siz [ 0 ] / 2 ) cube ( size = size , center = true ) ; }
// Module: fwdcube()
//
// Description:
// Makes a cube that is aligned on the front side of the origin.
//
// Usage:
// fwdcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
// Example:
// fwdcube([20,30,40]);
module fwdcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; fwd ( siz [ 1 ] / 2 ) cube ( size = size , center = true ) ; }
// Module: backcube()
//
// Description:
// Makes a cube that is aligned on the front side of the origin.
//
// Usage:
// backcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
// Example:
// backcube([20,30,40]);
module backcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; back ( siz [ 1 ] / 2 ) cube ( size = size , center = true ) ; }
// Module: downcube()
//
// Description:
// Makes a cube that is aligned on the bottom side of the origin.
//
// Usage:
// downcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
// Example:
// downcube([20,30,40]);
module downcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; down ( siz [ 2 ] / 2 ) cube ( size = size , center = true ) ; }
// Module: upcube()
//
// Description:
// Makes a cube that is aligned on the top side of the origin.
//
// Usage:
// upcube(size);
//
// Arguments:
// size = The size of the cube to make.
//
// Example:
// upcube([20,30,40]);
module upcube ( size = [ 1 , 1 , 1 ] ) { siz = scalar_vec3 ( size ) ; up ( siz [ 2 ] / 2 ) cube ( size = size , center = true ) ; }
// Section: Prismoids
// Module: prismoid()
//
// Description:
// Creates a rectangular prismoid shape.
//
// Usage:
// prismoid(size1, size2, h, [shift], [orient], [align|center]);
//
// Arguments:
// size1 = [width, length] of the axis-negative end of the prism.
// size2 = [width, length] of the axis-positive end of the prism.
// h = Height of the prism.
// shift = [x, y] amount to shift the center of the top with respect to the center of the bottom.
// orient = Orientation of the prismoid. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the prismoid by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `UP`.
// center = If given, overrides `align`. A true value sets `align=CENTER`, false sets `align=UP`.
2019-03-23 04:13:18 +00:00
//
// Example: Rectangular Pyramid
// prismoid(size1=[40,40], size2=[0,0], h=20);
// Example: Prism
// prismoid(size1=[40,40], size2=[0,40], h=20);
// Example: Truncated Pyramid
// prismoid(size1=[35,50], size2=[20,30], h=20);
// Example: Wedge
// prismoid(size1=[60,35], size2=[30,0], h=30);
// Example: Truncated Tetrahedron
// prismoid(size1=[10,40], size2=[40,10], h=40);
// Example: Inverted Truncated Pyramid
// prismoid(size1=[15,5], size2=[30,20], h=20);
// Example: Right Prism
// prismoid(size1=[30,60], size2=[0,60], shift=[-15,0], h=30);
// Example(FlatSpin): Shifting/Skewing
// prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]);
2019-04-22 08:08:41 +00:00
// Example(Spin): Standard Connectors
// prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]) show_connectors();
2019-03-23 04:13:18 +00:00
module prismoid (
size1 = [ 1 , 1 ] , size2 = [ 1 , 1 ] , h = 1 , shift = [ 0 , 0 ] ,
2019-04-22 08:08:41 +00:00
orient = ORIENT_Z , align = DOWN , center = undef
2019-03-23 04:13:18 +00:00
) {
eps = 0.001 ;
2019-04-17 02:16:50 +00:00
shiftby = point3d ( point2d ( shift ) ) ;
s1 = [ max ( size1 . x , eps ) , max ( size1 . y , eps ) ] ;
s2 = [ max ( size2 . x , eps ) , max ( size2 . y , eps ) ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( [ s1 . x , s1 . y , h ] , orient , align , center , size2 = s2 , shift = shift , noncentered = DOWN , chain = true ) {
2019-03-23 04:13:18 +00:00
polyhedron (
points = [
2019-04-17 02:16:50 +00:00
[ + s2 . x / 2 , + s2 . y / 2 , + h / 2 ] + shiftby ,
[ + s2 . x / 2 , - s2 . y / 2 , + h / 2 ] + shiftby ,
[ - s2 . x / 2 , - s2 . y / 2 , + h / 2 ] + shiftby ,
[ - s2 . x / 2 , + s2 . y / 2 , + h / 2 ] + shiftby ,
[ + s1 . x / 2 , + s1 . y / 2 , - h / 2 ] ,
[ + s1 . x / 2 , - s1 . y / 2 , - h / 2 ] ,
[ - s1 . x / 2 , - s1 . y / 2 , - h / 2 ] ,
[ - s1 . x / 2 , + s1 . y / 2 , - h / 2 ] ,
2019-03-23 04:13:18 +00:00
] ,
faces = [
[ 0 , 1 , 2 ] ,
[ 0 , 2 , 3 ] ,
[ 0 , 4 , 5 ] ,
[ 0 , 5 , 1 ] ,
[ 1 , 5 , 6 ] ,
[ 1 , 6 , 2 ] ,
[ 2 , 6 , 7 ] ,
[ 2 , 7 , 3 ] ,
[ 3 , 7 , 4 ] ,
[ 3 , 4 , 0 ] ,
[ 4 , 7 , 6 ] ,
[ 4 , 6 , 5 ] ,
] ,
convexity = 2
) ;
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
// Module: rounded_prismoid()
//
// Description:
// Creates a rectangular prismoid shape with rounded vertical edges.
//
// Arguments:
// size1 = [width, length] of the bottom of the prism.
// size2 = [width, length] of the top of the prism.
// h = Height of the prism.
// r = radius of vertical edge fillets.
// r1 = radius of vertical edge fillets at bottom.
// r2 = radius of vertical edge fillets at top.
// shift = [x, y] amount to shift the center of the top with respect to the center of the bottom.
// orient = Orientation of the prismoid. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the prismoid by the axis-negative (`size1`) end. Use the constants from `constants.scad`. Default: `UP`.
2019-03-23 04:13:18 +00:00
// center = vertically center the prism. Overrides `align`.
//
// Example: Rounded Pyramid
// rounded_prismoid(size1=[40,40], size2=[0,0], h=25, r=5);
// Example: Centered Rounded Pyramid
// rounded_prismoid(size1=[40,40], size2=[0,0], h=25, r=5, center=true);
// Example: Disparate Top and Bottom Radii
// rounded_prismoid(size1=[40,60], size2=[40,60], h=20, r1=3, r2=10, $fn=24);
// Example(FlatSpin): Shifting/Skewing
// rounded_prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5], r=5);
2019-04-22 08:08:41 +00:00
// Example(Spin): Standard Connectors
// rounded_prismoid(size1=[40,60], size2=[40,60], h=20, r1=3, r2=10, $fn=24) show_connectors();
2019-03-23 04:13:18 +00:00
module rounded_prismoid (
size1 , size2 , h , shift = [ 0 , 0 ] ,
r = undef , r1 = undef , r2 = undef ,
2019-04-22 08:08:41 +00:00
align = DOWN , orient = ORIENT_Z , center = undef
2019-03-23 04:13:18 +00:00
) {
eps = 0.001 ;
2019-04-17 02:16:50 +00:00
maxrad1 = min ( size1 . x / 2 , size1 . y / 2 ) ;
maxrad2 = min ( size2 . x / 2 , size2 . y / 2 ) ;
2019-03-23 04:13:18 +00:00
rr1 = min ( maxrad1 , ( r1 ! = undef ) ? r1 : r ) ;
rr2 = min ( maxrad2 , ( r2 ! = undef ) ? r2 : r ) ;
shiftby = point3d ( shift ) ;
2019-04-19 06:32:17 +00:00
orient_and_align ( [ size1 . x , size1 . y , h ] , orient , align , center , size2 = size2 , shift = shift , noncentered = UP , chain = true ) {
2019-04-17 02:16:50 +00:00
down ( h / 2 ) {
hull ( ) {
linear_extrude ( height = eps , center = false , convexity = 2 ) {
offset ( r = rr1 ) {
square ( [ max ( eps , size1 [ 0 ] - 2 * rr1 ) , max ( eps , size1 [ 1 ] - 2 * rr1 ) ] , center = true ) ;
}
2019-03-23 04:13:18 +00:00
}
2019-04-17 02:16:50 +00:00
up ( h - 0.01 ) {
translate ( shiftby ) {
linear_extrude ( height = eps , center = false , convexity = 2 ) {
offset ( r = rr2 ) {
square ( [ max ( eps , size2 [ 0 ] - 2 * rr2 ) , max ( eps , size2 [ 1 ] - 2 * rr2 ) ] , center = true ) ;
}
2019-03-23 04:13:18 +00:00
}
}
}
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
// Module: right_triangle()
//
// Description:
// Creates a 3D right triangular prism.
//
// Usage:
// right_triangle(size, [orient], [align|center]);
//
// Arguments:
// size = [width, thickness, height]
// orient = The axis to place the hypotenuse along. Only accepts `ORIENT_X`, `ORIENT_Y`, or `ORIENT_Z` from `constants.scad`. Default: `ORIENT_Y`.
2019-04-22 08:08:41 +00:00
// align = The side of the origin to align to. Use constants from `constants.scad`. Default: `ALLNEG`.
// center = If given, overrides `align`. A true value sets `align=CENTER`, false sets `align=ALLNEG`.
2019-03-23 04:13:18 +00:00
//
// Example: Centered
// right_triangle([60, 10, 40], center=true);
// Example: *Non*-Centered
// right_triangle([60, 10, 40]);
2019-04-22 08:08:41 +00:00
// Example: Standard Connectors
// right_triangle([60, 15, 40]) show_connectors();
module right_triangle ( size = [ 1 , 1 , 1 ] , orient = ORIENT_Y , align = ALLNEG , center = undef )
2019-03-23 04:13:18 +00:00
{
2019-04-17 02:16:50 +00:00
size = scalar_vec3 ( size ) ;
orient_and_align ( size , align = align , center = center , chain = true ) {
2019-03-23 04:13:18 +00:00
if ( orient = = ORIENT_X ) {
2019-04-17 02:16:50 +00:00
ang = atan2 ( size . y , size . z ) ;
masksize = [ size . x , size . y , norm ( [ size . y , size . z ] ) ] + [ 1 , 1 , 1 ] ;
2019-03-23 04:13:18 +00:00
xrot ( ang ) {
difference ( ) {
2019-04-17 02:16:50 +00:00
xrot ( - ang ) cube ( size , center = true ) ;
back ( masksize . y / 2 ) cube ( masksize , center = true ) ;
2019-03-23 04:13:18 +00:00
}
}
} else if ( orient = = ORIENT_Y ) {
2019-04-17 02:16:50 +00:00
ang = atan2 ( size . x , size . z ) ;
masksize = [ size . x , size . y , norm ( [ size . x , size . z ] ) ] + [ 1 , 1 , 1 ] ;
2019-03-23 04:13:18 +00:00
yrot ( - ang ) {
difference ( ) {
2019-04-17 02:16:50 +00:00
yrot ( ang ) cube ( size , center = true ) ;
right ( masksize . x / 2 ) cube ( masksize , center = true ) ;
2019-03-23 04:13:18 +00:00
}
}
} else if ( orient = = ORIENT_Z ) {
2019-04-17 02:16:50 +00:00
ang = atan2 ( size . x , size . y ) ;
masksize = [ norm ( [ size . x , size . y ] ) , size . y , size . z ] + [ 1 , 1 , 1 ] ;
2019-03-23 04:13:18 +00:00
zrot ( - ang ) {
difference ( ) {
2019-04-17 02:16:50 +00:00
zrot ( ang ) cube ( size , center = true ) ;
back ( masksize . y / 2 ) cube ( masksize , center = true ) ;
2019-03-23 04:13:18 +00:00
}
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
// Section: Cylindroids
// Module: cyl()
//
// Description:
// Creates cylinders in various alignments and orientations,
// with optional fillets and chamfers. You can use `r` and `l`
// interchangably, and all variants allow specifying size
// by either `r`|`d`, or `r1`|`d1` and `r2`|`d2`.
// Note that that chamfers and fillets cannot cross the
// midpoint of the cylinder's length.
//
// Usage: Normal Cylinders
// cyl(l|h, r|d, [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r1|d1, r2/d2, [circum], [realign], [orient], [align], [center]);
//
// Usage: Chamferred Cylinders
// cyl(l|h, r|d, chamfer, [chamfang], [from_end], [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, chamfer1, [chamfang1], [from_end], [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, chamfer2, [chamfang2], [from_end], [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, chamfer1, chamfer2, [chamfang1], [chamfang2], [from_end], [circum], [realign], [orient], [align], [center]);
//
// Usage: Rounded/Filleted Cylinders
// cyl(l|h, r|d, fillet, [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, fillet1, [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, fillet2, [circum], [realign], [orient], [align], [center]);
// cyl(l|h, r|d, fillet1, fillet2, [circum], [realign], [orient], [align], [center]);
//
// Arguments:
// l / h = Length of cylinder along oriented axis. (Default: 1.0)
2019-02-27 11:56:34 +00:00
// r = Radius of cylinder.
// r1 = Radius of the negative (X-, Y-, Z-) end of cylinder.
// r2 = Radius of the positive (X+, Y+, Z+) end of cylinder.
// d = Diameter of cylinder.
// d1 = Diameter of the negative (X-, Y-, Z-) end of cylinder.
// d2 = Diameter of the positive (X+, Y+, Z+) end of cylinder.
2019-03-23 04:13:18 +00:00
// circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false`
2019-02-28 01:45:15 +00:00
// chamfer = The size of the chamfers on the ends of the cylinder. Default: none.
// chamfer1 = The size of the chamfer on the axis-negative end of the cylinder. Default: none.
// chamfer2 = The size of the chamfer on the axis-positive end of the cylinder. Default: none.
// chamfang = The angle in degrees of the chamfers on the ends of the cylinder.
// chamfang1 = The angle in degrees of the chamfer on the axis-negative end of the cylinder.
// chamfang2 = The angle in degrees of the chamfer on the axis-positive end of the cylinder.
2019-03-23 04:13:18 +00:00
// from_end = If true, chamfer is measured from the end of the cylinder, instead of inset from the edge. Default: `false`.
2019-02-27 11:56:34 +00:00
// fillet = The radius of the fillets on the ends of the cylinder. Default: none.
// fillet1 = The radius of the fillet on the axis-negative end of the cylinder.
// fillet2 = The radius of the fillet on the axis-positive end of the cylinder.
// realign = If true, rotate the cylinder by half the angle of one face.
2019-03-23 04:13:18 +00:00
// orient = Orientation of the cylinder. Use the `ORIENT_` constants from `constants.scad`. Default: vertical.
2019-04-19 06:32:17 +00:00
// align = Alignment of the cylinder. Use the constants from `constants.scad`. Default: centered.
2019-04-22 08:08:41 +00:00
// center = If given, overrides `align`. A true value sets `align=CENTER`, false sets `align=DOWN`.
2019-03-23 04:13:18 +00:00
//
// Example: By Radius
// xdistribute(30) {
// cyl(l=40, r=10);
// cyl(l=40, r1=10, r2=5);
// }
//
// Example: By Diameter
// xdistribute(30) {
// cyl(l=40, d=25);
// cyl(l=40, d1=25, d2=10);
// }
//
// Example: Chamferring
// xdistribute(60) {
// // Shown Left to right.
// cyl(l=40, d=40, chamfer=7); // Default chamfang=45
// cyl(l=40, d=40, chamfer=7, chamfang=30, from_end=false);
// cyl(l=40, d=40, chamfer=7, chamfang=30, from_end=true);
// }
//
// Example: Rounding/Filleting
// cyl(l=40, d=40, fillet=10);
//
// Example: Heterogenous Chamfers and Fillets
// ydistribute(80) {
// // Shown Front to Back.
// cyl(l=40, d=40, fillet1=15, orient=ORIENT_X);
// cyl(l=40, d=40, chamfer2=5, orient=ORIENT_X);
// cyl(l=40, d=40, chamfer1=12, fillet2=10, orient=ORIENT_X);
// }
//
// Example: Putting it all together
// cyl(l=40, d1=25, d2=15, chamfer1=10, chamfang1=30, from_end=true, fillet2=5);
2019-04-22 08:08:41 +00:00
//
// Example: Standard Connectors
// xdistribute(40) {
// cyl(l=30, d=25) show_connectors();
// cyl(l=30, d1=25, d2=10) show_connectors();
// }
//
2019-02-27 11:56:34 +00:00
module cyl (
2019-03-23 04:13:18 +00:00
l = undef , h = undef ,
2019-02-27 11:56:34 +00:00
r = undef , r1 = undef , r2 = undef ,
d = undef , d1 = undef , d2 = undef ,
chamfer = undef , chamfer1 = undef , chamfer2 = undef ,
chamfang = undef , chamfang1 = undef , chamfang2 = undef ,
fillet = undef , fillet1 = undef , fillet2 = undef ,
2019-02-28 01:45:15 +00:00
circum = false , realign = false , from_end = false ,
2019-04-19 06:32:17 +00:00
orient = ORIENT_Z , align = CENTER , center = undef
2019-02-27 11:56:34 +00:00
) {
r1 = get_radius ( r1 , r , d1 , d , 1 ) ;
r2 = get_radius ( r2 , r , d2 , d , 1 ) ;
2019-03-23 04:13:18 +00:00
l = first_defined ( [ l , h , 1 ] ) ;
2019-04-17 02:16:50 +00:00
size1 = [ r1 * 2 , r1 * 2 , l ] ;
size2 = [ r2 * 2 , r2 * 2 , l ] ;
2019-02-27 11:56:34 +00:00
sides = segs ( max ( r1 , r2 ) ) ;
sc = circum ? 1 / cos ( 180 / sides ) : 1 ;
2019-04-17 02:16:50 +00:00
phi = atan2 ( l , r1 - r2 ) ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size1 , orient , align , center = center , size2 = size2 , geometry = "cylinder" , chain = true ) {
2019-02-27 11:56:34 +00:00
zrot ( realign ? 180 / sides : 0 ) {
2019-03-02 19:14:36 +00:00
if ( ! any_defined ( [ chamfer , chamfer1 , chamfer2 , fillet , fillet1 , fillet2 ] ) ) {
cylinder ( h = l , r1 = r1 * sc , r2 = r2 * sc , center = true , $fn = sides ) ;
} else {
2019-02-28 01:45:15 +00:00
vang = atan2 ( l , r1 - r2 ) / 2 ;
chang1 = 90 - first_defined ( [ chamfang1 , chamfang , vang ] ) ;
chang2 = 90 - first_defined ( [ chamfang2 , chamfang , 90 - vang ] ) ;
2019-03-02 19:14:36 +00:00
cham1 = first_defined ( [ chamfer1 , chamfer ] ) * ( from_end ? 1 : tan ( chang1 ) ) ;
cham2 = first_defined ( [ chamfer2 , chamfer ] ) * ( from_end ? 1 : tan ( chang2 ) ) ;
fil1 = first_defined ( [ fillet1 , fillet ] ) ;
fil2 = first_defined ( [ fillet2 , fillet ] ) ;
2019-03-23 04:13:18 +00:00
if ( chamfer ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( chamfer < = r1 , "chamfer is larger than the r1 radius of the cylinder." ) ;
assert ( chamfer < = r2 , "chamfer is larger than the r2 radius of the cylinder." ) ;
assert ( chamfer < = l / 2 , "chamfer is larger than half the length of the cylinder." ) ;
2019-03-23 04:13:18 +00:00
}
if ( cham1 ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( cham1 < = r1 , "chamfer1 is larger than the r1 radius of the cylinder." ) ;
assert ( cham1 < = l / 2 , "chamfer1 is larger than half the length of the cylinder." ) ;
2019-03-23 04:13:18 +00:00
}
if ( cham2 ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( cham2 < = r2 , "chamfer2 is larger than the r2 radius of the cylinder." ) ;
assert ( cham2 < = l / 2 , "chamfer2 is larger than half the length of the cylinder." ) ;
2019-03-23 04:13:18 +00:00
}
if ( fillet ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( fillet < = r1 , "fillet is larger than the r1 radius of the cylinder." ) ;
assert ( fillet < = r2 , "fillet is larger than the r2 radius of the cylinder." ) ;
assert ( fillet < = l / 2 , "fillet is larger than half the length of the cylinder." ) ;
2019-03-23 04:13:18 +00:00
}
if ( fil1 ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( fil1 < = r1 , "fillet1 is larger than the r1 radius of the cylinder." ) ;
assert ( fil1 < = l / 2 , "fillet1 is larger than half the length of the cylinder." ) ;
2019-03-23 04:13:18 +00:00
}
if ( fil2 ! = undef ) {
2019-04-20 00:02:17 +00:00
assert ( fil2 < = r2 , "fillet2 is larger than the r1 radius of the cylinder." ) ;
assert ( fil2 < = l / 2 , "fillet2 is larger than half the length of the cylinder." ) ;
2019-02-27 11:56:34 +00:00
}
2019-03-02 19:14:36 +00:00
dy1 = first_defined ( [ cham1 , fil1 , 0 ] ) ;
dy2 = first_defined ( [ cham2 , fil2 , 0 ] ) ;
maxd = max ( r1 , r2 , l ) ;
rotate_extrude ( convexity = 2 ) {
hull ( ) {
2019-02-27 11:56:34 +00:00
difference ( ) {
2019-03-02 19:14:36 +00:00
union ( ) {
difference ( ) {
back ( l / 2 ) {
if ( cham2 ! = undef && cham2 > 0 ) {
rr2 = sc * ( r2 + ( r1 - r2 ) * dy2 / l ) ;
chlen2 = min ( rr2 , cham2 / sin ( chang2 ) ) ;
translate ( [ rr2 , - cham2 ] ) {
rotate ( - chang2 ) {
translate ( [ - chlen2 , - chlen2 ] ) {
square ( chlen2 , center = false ) ;
}
}
}
} else if ( fil2 ! = undef && fil2 > 0 ) {
translate ( [ r2 - fil2 * tan ( vang ) , - fil2 ] ) {
circle ( r = fil2 ) ;
}
} else {
translate ( [ r2 - 0.005 , - 0.005 ] ) {
square ( 0.01 , center = true ) ;
}
}
2019-02-27 11:56:34 +00:00
}
2019-03-02 19:14:36 +00:00
// Make sure the corner fiddly bits never cross the X axis.
fwd ( maxd ) square ( maxd , center = false ) ;
2019-02-27 11:56:34 +00:00
}
2019-03-02 19:14:36 +00:00
difference ( ) {
fwd ( l / 2 ) {
if ( cham1 ! = undef && cham1 > 0 ) {
rr1 = sc * ( r1 + ( r2 - r1 ) * dy1 / l ) ;
chlen1 = min ( rr1 , cham1 / sin ( chang1 ) ) ;
translate ( [ rr1 , cham1 ] ) {
rotate ( chang1 ) {
left ( chlen1 ) {
square ( chlen1 , center = false ) ;
}
}
}
} else if ( fil1 ! = undef && fil1 > 0 ) {
right ( r1 ) {
translate ( [ - fil1 / tan ( vang ) , fil1 ] ) {
fsegs1 = quantup ( segs ( fil1 ) , 4 ) ;
circle ( r = fil1 , $fn = fsegs1 ) ;
}
}
} else {
right ( r1 - 0.01 ) {
square ( 0.01 , center = false ) ;
}
}
2019-02-27 11:56:34 +00:00
}
2019-03-02 19:14:36 +00:00
// Make sure the corner fiddly bits never cross the X axis.
square ( maxd , center = false ) ;
2019-02-27 11:56:34 +00:00
}
2019-03-02 19:14:36 +00:00
// Force the hull to extend to the axis
2019-02-27 11:56:34 +00:00
right ( 0.01 / 2 ) square ( [ 0.01 , l ] , center = true ) ;
}
2019-03-02 19:14:36 +00:00
// Clear anything left of the Y axis.
left ( maxd / 2 ) square ( maxd , center = true ) ;
// Clear anything right of face
right ( ( r1 + r2 ) / 2 ) {
rotate ( 90 - vang * 2 ) {
fwd ( maxd / 2 ) square ( maxd , center = false ) ;
}
}
2019-02-27 11:56:34 +00:00
}
}
2018-10-04 01:22:26 +00:00
}
}
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-02-27 11:56:34 +00:00
2019-03-23 04:13:18 +00:00
// Module: xcyl()
//
// Description:
// Creates a cylinder oriented along the X axis.
//
// Usage:
// xcyl(l|h, r|d, [align|center]);
// xcyl(l|h, r1|d1, r2|d2, [align|center]);
//
// Arguments:
// l / h = Length of cylinder along oriented axis. (Default: `1.0`)
// r = Radius of cylinder.
// r1 = Optional radius of left (X-) end of cylinder.
// r2 = Optional radius of right (X+) end of cylinder.
// d = Optional diameter of cylinder. (use instead of `r`)
// d1 = Optional diameter of left (X-) end of cylinder.
// d2 = Optional diameter of right (X+) end of cylinder.
2019-04-19 06:32:17 +00:00
// align = The side of the origin to align to. Use constants from `constants.scad`. Default: `CENTER`
2019-04-22 08:08:41 +00:00
// center = If given, overrides `align`. A `true` value sets `align=CENTER`, `false` sets `align=BOTTOM`.
2019-03-23 04:13:18 +00:00
//
// Example: By Radius
// ydistribute(50) {
// xcyl(l=35, r=10);
// xcyl(l=35, r1=15, r2=5);
// }
//
// Example: By Diameter
// ydistribute(50) {
// xcyl(l=35, d=20);
// xcyl(l=35, d1=30, d2=10);
// }
2019-04-19 06:32:17 +00:00
module xcyl ( l = undef , r = undef , d = undef , r1 = undef , r2 = undef , d1 = undef , d2 = undef , h = undef , align = CENTER , center = undef )
2019-02-10 11:12:46 +00:00
{
2019-04-17 02:16:50 +00:00
cyl ( l = l , h = h , r = r , r1 = r1 , r2 = r2 , d = d , d1 = d1 , d2 = d2 , orient = ORIENT_X , align = align , center = center ) children ( ) ;
2019-02-10 11:12:46 +00:00
}
2019-03-23 04:13:18 +00:00
// Module: ycyl()
//
// Description:
// Creates a cylinder oriented along the Y axis.
//
// Usage:
// ycyl(l|h, r|d, [align|center]);
// ycyl(l|h, r1|d1, r2|d2, [align|center]);
//
// Arguments:
// l / h = Length of cylinder along oriented axis. (Default: `1.0`)
// r = Radius of cylinder.
// r1 = Radius of front (Y-) end of cone.
// r2 = Radius of back (Y+) end of one.
// d = Diameter of cylinder.
// d1 = Diameter of front (Y-) end of one.
// d2 = Diameter of back (Y+) end of one.
2019-04-19 06:32:17 +00:00
// align = The side of the origin to align to. Use constants from `constants.scad`. Default: `CENTER`
// center = Overrides `align` if given. If true, `align=CENTER`, if false, `align=UP`.
2019-03-23 04:13:18 +00:00
//
// Example: By Radius
// xdistribute(50) {
// ycyl(l=35, r=10);
// ycyl(l=35, r1=15, r2=5);
// }
//
// Example: By Diameter
// xdistribute(50) {
// ycyl(l=35, d=20);
// ycyl(l=35, d1=30, d2=10);
// }
2019-04-19 06:32:17 +00:00
module ycyl ( l = undef , r = undef , d = undef , r1 = undef , r2 = undef , d1 = undef , d2 = undef , h = undef , align = CENTER , center = undef )
2019-02-10 11:12:46 +00:00
{
2019-04-17 02:16:50 +00:00
cyl ( l = l , h = h , r = r , r1 = r1 , r2 = r2 , d = d , d1 = d1 , d2 = d2 , orient = ORIENT_Y , align = align , center = center ) children ( ) ;
2019-02-10 11:12:46 +00:00
}
2019-03-23 04:13:18 +00:00
// Module: zcyl()
//
// Description:
// Creates a cylinder oriented along the Z axis.
//
// Usage:
// zcyl(l|h, r|d, [align|center]);
// zcyl(l|h, r1|d1, r2|d2, [align|center]);
//
// Arguments:
// l / h = Length of cylinder along oriented axis. (Default: 1.0)
// r = Radius of cylinder.
// r1 = Radius of front (Y-) end of cone.
// r2 = Radius of back (Y+) end of one.
// d = Diameter of cylinder.
// d1 = Diameter of front (Y-) end of one.
// d2 = Diameter of back (Y+) end of one.
2019-04-19 06:32:17 +00:00
// align = The side of the origin to align to. Use constants from `constants.scad`. Default: `CENTER`
// center = Overrides `align` if given. If true, `align=CENTER`, if false, `align=UP`.
2019-03-23 04:13:18 +00:00
//
// Example: By Radius
// xdistribute(50) {
// zcyl(l=35, r=10);
// zcyl(l=35, r1=15, r2=5);
// }
//
// Example: By Diameter
// xdistribute(50) {
// zcyl(l=35, d=20);
// zcyl(l=35, d1=30, d2=10);
// }
2019-04-19 06:32:17 +00:00
module zcyl ( l = undef , r = undef , d = undef , r1 = undef , r2 = undef , d1 = undef , d2 = undef , h = undef , align = CENTER , center = undef )
2019-02-10 11:12:46 +00:00
{
2019-04-17 02:16:50 +00:00
cyl ( l = l , h = h , r = r , r1 = r1 , r2 = r2 , d = d , d1 = d1 , d2 = d2 , orient = ORIENT_Z , align = align , center = center ) children ( ) ;
2019-01-30 00:38:02 +00:00
}
2019-03-23 04:13:18 +00:00
// Module: tube()
//
// Description:
// Makes a hollow tube with the given outer size and wall thickness.
//
// Usage:
// tube(h, ir|id, wall, [realign], [orient], [align]);
// tube(h, or|od, wall, [realign], [orient], [align]);
// tube(h, ir|id, or|od, [realign], [orient], [align]);
// tube(h, ir1|id1, ir2|id2, wall, [realign], [orient], [align]);
// tube(h, or1|od1, or2|od2, wall, [realign], [orient], [align]);
// tube(h, ir1|id1, ir2|id2, or1|od1, or2|od2, [realign], [orient], [align]);
//
// Arguments:
2017-08-30 00:00:16 +00:00
// h = height of tube. (Default: 1)
2019-03-23 04:13:18 +00:00
// or = Outer radius of tube.
// or1 = Outer radius of bottom of tube. (Default: value of r)
// or2 = Outer radius of top of tube. (Default: value of r)
// od = Outer diameter of tube.
// od1 = Outer diameter of bottom of tube.
// od2 = Outer diameter of top of tube.
2017-08-30 00:00:16 +00:00
// wall = horizontal thickness of tube wall. (Default 0.5)
2019-02-24 07:26:15 +00:00
// ir = Inner radius of tube.
2019-02-24 12:35:40 +00:00
// ir1 = Inner radius of bottom of tube.
// ir2 = Inner radius of top of tube.
2019-02-24 07:26:15 +00:00
// id = Inner diameter of tube.
// id1 = Inner diameter of bottom of tube.
// id2 = Inner diameter of top of tube.
2019-03-23 04:13:18 +00:00
// realign = If true, rotate the tube by half the angle of one face.
// orient = Orientation of the tube. Use the `ORIENT_` constants from `constants.scad`. Default: vertical.
2019-04-19 06:32:17 +00:00
// align = Alignment of the tube. Use the constants from `constants.scad`. Default: centered.
2019-03-23 04:13:18 +00:00
//
// Example: These all Produce the Same Tube
// tube(h=30, or=40, wall=5);
// tube(h=30, ir=35, wall=5);
// tube(h=30, or=40, ir=35);
// tube(h=30, od=80, id=70);
// Example: These all Produce the Same Conical Tube
// tube(h=30, or1=40, or2=25, wall=5);
// tube(h=30, ir1=35, or2=20, wall=5);
// tube(h=30, or1=40, or2=25, ir1=35, ir2=20);
// Example: Circular Wedge
// tube(h=30, or1=40, or2=30, ir1=20, ir2=30);
2019-04-22 08:08:41 +00:00
// Example: Standard Connectors
// tube(h=30, or=40, wall=5) show_connectors();
2019-02-27 11:56:34 +00:00
module tube (
h = 1 , wall = undef ,
r = undef , r1 = undef , r2 = undef ,
d = undef , d1 = undef , d2 = undef ,
2019-03-23 04:13:18 +00:00
or = undef , or1 = undef , or2 = undef ,
od = undef , od1 = undef , od2 = undef ,
2019-02-27 11:56:34 +00:00
ir = undef , id = undef , ir1 = undef ,
ir2 = undef , id1 = undef , id2 = undef ,
2019-04-19 06:32:17 +00:00
center = undef , orient = ORIENT_Z , align = UP ,
2019-03-23 04:13:18 +00:00
realign = false
2019-02-27 11:56:34 +00:00
) {
2019-03-23 04:13:18 +00:00
r1 = first_defined ( [ or1 , od1 / 2 , r1 , d1 / 2 , or , od / 2 , r , d / 2 , ir1 + wall , id1 / 2 + wall , ir + wall , id / 2 + wall ] ) ;
r2 = first_defined ( [ or2 , od2 / 2 , r2 , d2 / 2 , or , od / 2 , r , d / 2 , ir2 + wall , id2 / 2 + wall , ir + wall , id / 2 + wall ] ) ;
2019-02-27 11:56:34 +00:00
ir1 = first_defined ( [ ir1 , id1 / 2 , ir , id / 2 , r1 - wall , d1 / 2 - wall , r - wall , d / 2 - wall ] ) ;
ir2 = first_defined ( [ ir2 , id2 / 2 , ir , id / 2 , r2 - wall , d2 / 2 - wall , r - wall , d / 2 - wall ] ) ;
2019-04-20 00:02:17 +00:00
assert ( ir1 < = r1 , "Inner radius is larger than outer radius." ) ;
assert ( ir2 < = r2 , "Inner radius is larger than outer radius." ) ;
2019-03-23 04:13:18 +00:00
sides = segs ( max ( r1 , r2 ) ) ;
2019-04-17 02:16:50 +00:00
size = [ r1 * 2 , r1 * 2 , h ] ;
size2 = [ r2 * 2 , r2 * 2 , h ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , center = center , size2 = size2 , geometry = "cylinder" , chain = true ) {
2019-03-23 04:13:18 +00:00
zrot ( realign ? 180 / sides : 0 ) {
difference ( ) {
2019-04-17 02:16:50 +00:00
cyl ( h = h , r1 = r1 , r2 = r2 , $fn = sides ) children ( ) ;
cyl ( h = h + 0.05 , r1 = ir1 , r2 = ir2 ) ;
2019-03-23 04:13:18 +00:00
}
2018-09-01 09:36:47 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: torus()
//
// Descriptiom:
// Creates a torus shape.
//
// Usage:
// torus(r|d, r2|d2, [orient], [align]);
// torus(or|od, ir|id, [orient], [align]);
//
// Arguments:
2018-09-04 17:10:14 +00:00
// r = major radius of torus ring. (use with of 'r2', or 'd2')
// r2 = minor radius of torus ring. (use with of 'r', or 'd')
// d = major diameter of torus ring. (use with of 'r2', or 'd2')
// d2 = minor diameter of torus ring. (use with of 'r', or 'd')
// or = outer radius of the torus. (use with 'ir', or 'id')
// ir = inside radius of the torus. (use with 'or', or 'od')
// od = outer diameter of the torus. (use with 'ir' or 'id')
// id = inside diameter of the torus. (use with 'or' or 'od')
2019-03-23 04:13:18 +00:00
// orient = Orientation of the torus. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the torus. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// // These all produce the same torus.
// torus(r=22.5, r2=7.5);
// torus(d=45, d2=15);
// torus(or=30, ir=15);
// torus(od=60, id=30);
2019-04-22 08:08:41 +00:00
// Example: Standard Connectors
// torus(od=60, id=30) show_connectors();
2019-02-27 11:56:34 +00:00
module torus (
r = undef , d = undef ,
r2 = undef , d2 = undef ,
or = undef , od = undef ,
2019-03-23 04:13:18 +00:00
ir = undef , id = undef ,
2019-04-19 06:32:17 +00:00
orient = ORIENT_Z , align = CENTER , center = undef
2019-02-27 11:56:34 +00:00
) {
orr = get_radius ( r = or , d = od , dflt = 1.0 ) ;
irr = get_radius ( r = ir , d = id , dflt = 0.5 ) ;
majrad = get_radius ( r = r , d = d , dflt = ( orr + irr ) / 2 ) ;
minrad = get_radius ( r = r2 , d = d2 , dflt = ( orr - irr ) / 2 ) ;
2019-04-17 02:16:50 +00:00
size = [ ( majrad + minrad ) * 2 , ( majrad + minrad ) * 2 , minrad * 2 ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , center = center , geometry = "cylinder" , chain = true ) {
2019-03-23 04:13:18 +00:00
rotate_extrude ( convexity = 4 ) {
right ( majrad ) circle ( minrad ) ;
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2018-09-04 17:10:14 +00:00
}
2017-08-30 00:00:16 +00:00
}
2019-03-23 04:13:18 +00:00
// Section: Spheroids
2019-04-17 02:16:50 +00:00
// Module: spheroid()
// Description:
// An version of `sphere()` with connector points, orientation, and alignment.
// Usage:
// spheroid(r|d, [circum])
// Arguments:
// r = Radius of the sphere.
// d = Diameter of the sphere.
// circum = If true, circumscribes the perfect sphere of the given radius/diameter.
// orient = Orientation of the sphere, if you don't like where the vertices lay. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the sphere. Use the constants from `constants.scad`. Default: `CENTER`.
2019-04-22 08:08:41 +00:00
// Example: By Radius
// spheroid(r=50, circum=true);
// Example: By Diameter
// spheroid(d=100, circum=true);
// Example: Standard Connectors
// spheroid(d=40, circum=true) show_connectors();
2019-04-19 06:32:17 +00:00
module spheroid ( r = undef , d = undef , circum = false , orient = UP , align = CENTER )
2019-04-17 02:16:50 +00:00
{
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 ;
size = [ 2 * rr , 2 * rr , 2 * rr ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , geometry = "sphere" , chain = true ) {
2019-04-17 02:16:50 +00:00
sphere ( r = rr ) ;
children ( ) ;
}
}
2019-03-23 04:13:18 +00:00
// 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.
2019-04-17 02:16:50 +00:00
// orient = Orientation of the sphere, if you don't like where the vertices lay. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the sphere. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
2019-04-22 08:08:41 +00:00
// 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_connectors();
2019-04-19 06:32:17 +00:00
module staggered_sphere ( r = undef , d = undef , circum = false , orient = UP , align = CENTER ) {
2019-03-23 04:13:18 +00:00
r = get_radius ( r = r , d = d , dflt = 1 ) ;
sides = segs ( r ) ;
vsides = max ( 3 , ceil ( sides / 2 ) ) + 1 ;
step = 360 / sides ;
vstep = 180 / ( vsides - 1 ) ;
2019-04-17 02:16:50 +00:00
rr = circum ? ( r / cos ( 180 / sides ) / cos ( 90 / vsides ) ) : r ;
2018-12-22 21:17:04 +00:00
pts = concat (
2019-03-23 04:13:18 +00:00
[ [ 0 , 0 , rr ] ] ,
[
for ( p = [ 1 : vsides - 2 ] , t = [ 0 : sides - 1 ] ) let (
ta = ( t + ( p % 2 / 2 ) ) * step ,
pa = p * vstep
) spherical_to_xyz ( rr , ta , pa )
] ,
[ [ 0 , 0 , - rr ] ]
2018-12-22 21:17:04 +00:00
) ;
2019-03-23 04:13:18 +00:00
pcnt = len ( pts ) ;
faces = concat (
[
for ( i = [ 1 : sides ] ) each [
[ 0 , i % sides + 1 , i ] ,
[ pcnt - 1 , pcnt - 1 - ( i % sides + 1 ) , pcnt - 1 - i ]
]
] ,
[
for ( p = [ 0 : vsides - 4 ] , i = [ 0 : 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 ] ]
]
) ;
2019-04-17 02:16:50 +00:00
size = [ 2 * rr , 2 * rr , 2 * rr ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , geometry = "sphere" , chain = true ) {
2019-04-17 02:16:50 +00:00
polyhedron ( points = pts , faces = faces ) ;
children ( ) ;
}
2018-12-22 21:17:04 +00:00
}
2019-03-23 04:13:18 +00:00
// Section: 3D Printing Shapes
// Module: teardrop2d()
//
// Description:
// Makes a 2D teardrop shape. Useful for extruding into 3D printable holes.
//
// Usage:
// teardrop2d(r|d, [ang], [cap_h]);
//
// Arguments:
// r = radius of circular part of teardrop. (Default: 1)
// d = diameter of spherical portion of bottom. (Use instead of r)
// ang = angle of hat walls from the Y axis. (Default: 45 degrees)
// cap_h = if given, height above center where the shape will be truncated.
//
// Example(2D): Typical Shape
// teardrop2d(r=30, ang=30);
// Example(2D): Crop Cap
// teardrop2d(r=30, ang=30, cap_h=40);
// Example(2D): Close Crop
// teardrop2d(r=30, ang=30, cap_h=20);
module teardrop2d ( r = 1 , d = undef , ang = 45 , cap_h = undef )
{
eps = 0.01 ;
r = get_radius ( r = r , d = d , dflt = 1 ) ;
cord = 2 * r * cos ( ang ) ;
cord_h = r * sin ( ang ) ;
tip_y = ( cord / 2 ) / tan ( ang ) ;
2019-04-20 00:02:17 +00:00
cap_h = min ( ( ! is_undef ( cap_h ) ? cap_h : tip_y + cord_h ) , tip_y + cord_h ) ;
2019-03-23 04:13:18 +00:00
cap_w = cord * ( 1 - ( cap_h - cord_h ) / tip_y ) ;
difference ( ) {
2018-11-20 00:31:27 +00:00
hull ( ) {
2019-03-23 04:13:18 +00:00
zrot ( 90 ) circle ( r = r ) ;
back ( cap_h - eps / 2 ) square ( [ max ( eps , cap_w ) , eps ] , center = true ) ;
2018-11-20 00:31:27 +00:00
}
2019-03-23 04:13:18 +00:00
back ( r + cap_h ) square ( 2 * r , center = true ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: teardrop()
//
// Description:
// Makes a teardrop shape in the XZ plane. Useful for 3D printable holes.
//
// Usage:
// teardrop(r|d, l|h, [ang], [cap_h], [orient], [align])
//
// Arguments:
// r = Radius of circular part of teardrop. (Default: 1)
// d = Diameter of circular portion of bottom. (Use instead of r)
// l = Thickness of teardrop. (Default: 1)
// ang = Angle of hat walls from the Z axis. (Default: 45 degrees)
// cap_h = If given, height above center where the shape will be truncated.
// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// teardrop(r=30, h=10, ang=30);
// Example: Crop Cap
// teardrop(r=30, h=10, ang=30, cap_h=40);
// Example: Close Crop
// teardrop(r=30, h=10, ang=30, cap_h=20);
2019-04-19 06:32:17 +00:00
module teardrop ( r = undef , d = undef , l = undef , h = undef , ang = 45 , cap_h = undef , orient = ORIENT_Y , align = CENTER )
2019-03-23 04:13:18 +00:00
{
r = get_radius ( r = r , d = d , dflt = 1 ) ;
l = first_defined ( [ l , h , 1 ] ) ;
2019-04-17 02:16:50 +00:00
size = [ r * 2 , r * 2 , l ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , geometry = "cylinder" , chain = true ) {
2019-03-23 04:13:18 +00:00
linear_extrude ( height = l , center = true , slices = 2 ) {
teardrop2d ( r = r , ang = ang , cap_h = cap_h ) ;
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
// Module: onion()
//
// Description:
// Creates a sphere with a conical hat, to make a 3D teardrop.
//
// Usage:
// onion(r|d, [maxang], [cap_h], [orient], [align]);
//
// Arguments:
// r = radius of spherical portion of the bottom. (Default: 1)
// d = diameter of spherical portion of bottom.
// cap_h = height above sphere center to truncate teardrop shape.
// maxang = angle of cone on top from vertical.
// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// onion(r=30, maxang=30);
// Example: Crop Cap
// onion(r=30, maxang=30, cap_h=40);
// Example: Close Crop
// onion(r=30, maxang=30, cap_h=20);
2019-04-22 08:08:41 +00:00
// Example: Standard Connectors
// onion(r=30, maxang=30, cap_h=40) show_connectors();
2019-04-19 06:32:17 +00:00
module onion ( cap_h = undef , r = undef , d = undef , maxang = 45 , h = undef , orient = ORIENT_Z , align = CENTER )
2019-03-23 04:13:18 +00:00
{
r = get_radius ( r = r , d = d , dflt = 1 ) ;
h = first_defined ( [ cap_h , h ] ) ;
maxd = 3 * r / tan ( maxang ) ;
2019-04-17 02:16:50 +00:00
size = [ r * 2 , r * 2 , r * 2 ] ;
2019-04-22 08:08:41 +00:00
alignments = [
[ "cap" , [ 0 , 0 , h ] , UP , 0 ]
] ;
orient_and_align ( size , orient , align , geometry = "sphere" , alignments = alignments , chain = true ) {
2019-03-23 04:13:18 +00:00
rotate_extrude ( convexity = 2 ) {
difference ( ) {
teardrop2d ( r = r , ang = maxang , cap_h = h ) ;
left ( r ) square ( size = [ 2 * r , maxd ] , center = true ) ;
2018-11-30 22:01:53 +00:00
}
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: narrowing_strut()
//
// Description:
// Makes a rectangular strut with the top side narrowing in a triangle.
// The shape created may be likened to an extruded home plate from baseball.
// This is useful for constructing parts that minimize the need to support
// overhangs.
//
// Usage:
// narrowing_strut(w, l, wall, [ang], [orient], [align]);
//
// Arguments:
2017-08-30 00:00:16 +00:00
// w = Width (thickness) of the strut.
// l = Length of the strut.
// wall = height of rectangular portion of the strut.
// ang = angle that the trianglar side will converge at.
2019-03-23 04:13:18 +00:00
// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
// narrowing_strut(w=10, l=100, wall=5, ang=30);
2019-04-19 06:32:17 +00:00
module narrowing_strut ( w = 10 , l = 100 , wall = 5 , ang = 30 , orient = ORIENT_Y , align = UP )
2017-08-30 00:00:16 +00:00
{
2019-03-23 04:13:18 +00:00
h = wall + w / 2 / tan ( ang ) ;
2019-04-17 02:16:50 +00:00
size = [ w , h , l ] ;
orient_and_align ( size , orient , align , chain = true ) {
2019-03-23 04:13:18 +00:00
fwd ( h / 2 ) {
linear_extrude ( height = l , center = true , slices = 2 ) {
back ( wall / 2 ) square ( [ w , wall ] , center = true ) ;
back ( wall - 0.001 ) {
yscale ( 1 / tan ( ang ) ) {
difference ( ) {
zrot ( 45 ) square ( w / sqrt ( 2 ) , center = true ) ;
fwd ( w / 2 ) square ( w , center = true ) ;
}
}
}
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: thinning_wall()
//
// Description:
// Makes a rectangular wall which thins to a smaller width in the center,
// with angled supports to prevent critical overhangs.
//
// Usage:
// thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [align]);
//
// Arguments:
2017-08-30 00:00:16 +00:00
// h = height of wall.
2019-03-23 04:13:18 +00:00
// l = length of wall. If given as a vector of two numbers, specifies bottom and top lengths, respectively.
2017-08-30 00:00:16 +00:00
// thick = thickness of wall.
// ang = maximum overhang angle of diagonal brace.
// strut = the width of the diagonal brace.
// wall = the thickness of the thinned portion of the wall.
2019-03-23 04:13:18 +00:00
// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// thinning_wall(h=50, l=80, thick=4);
// Example: Trapezoidal
// thinning_wall(h=50, l=[80,50], thick=4);
2019-04-19 06:32:17 +00:00
module thinning_wall ( h = 50 , l = 100 , thick = 5 , ang = 30 , strut = 5 , wall = 2 , orient = ORIENT_Z , align = CENTER )
2017-08-30 00:00:16 +00:00
{
l1 = ( l [ 0 ] = = undef ) ? l : l [ 0 ] ;
l2 = ( l [ 1 ] = = undef ) ? l : l [ 1 ] ;
trap_ang = atan2 ( ( l2 - l1 ) / 2 , h ) ;
corr1 = 1 + sin ( trap_ang ) ;
corr2 = 1 - sin ( trap_ang ) ;
z1 = h / 2 ;
z2 = max ( 0.1 , z1 - strut ) ;
z3 = max ( 0.05 , z2 - ( thick - wall ) / 2 * sin ( 90 - ang ) / sin ( ang ) ) ;
x1 = l2 / 2 ;
x2 = max ( 0.1 , x1 - strut * corr1 ) ;
x3 = max ( 0.05 , x2 - ( thick - wall ) / 2 * sin ( 90 - ang ) / sin ( ang ) * corr1 ) ;
x4 = l1 / 2 ;
x5 = max ( 0.1 , x4 - strut * corr2 ) ;
x6 = max ( 0.05 , x5 - ( thick - wall ) / 2 * sin ( 90 - ang ) / sin ( ang ) * corr2 ) ;
y1 = thick / 2 ;
y2 = y1 - min ( z2 - z3 , x2 - x3 ) * sin ( ang ) ;
2019-04-17 02:16:50 +00:00
size = [ l1 , thick , h ] ;
orient_and_align ( size , orient , align , size2 = [ l2 , thick ] , chain = true ) {
2017-08-30 00:00:16 +00:00
polyhedron (
points = [
[ - x4 , - y1 , - z1 ] ,
[ x4 , - y1 , - z1 ] ,
[ x1 , - y1 , z1 ] ,
[ - x1 , - y1 , z1 ] ,
[ - x5 , - y1 , - z2 ] ,
[ x5 , - y1 , - z2 ] ,
[ x2 , - y1 , z2 ] ,
[ - x2 , - y1 , z2 ] ,
[ - x6 , - y2 , - z3 ] ,
[ x6 , - y2 , - z3 ] ,
[ x3 , - y2 , z3 ] ,
[ - x3 , - y2 , z3 ] ,
[ - x4 , y1 , - z1 ] ,
[ x4 , y1 , - z1 ] ,
[ x1 , y1 , z1 ] ,
[ - x1 , y1 , z1 ] ,
[ - x5 , y1 , - z2 ] ,
[ x5 , y1 , - z2 ] ,
[ x2 , y1 , z2 ] ,
[ - x2 , y1 , z2 ] ,
[ - x6 , y2 , - z3 ] ,
[ x6 , y2 , - z3 ] ,
[ x3 , y2 , z3 ] ,
[ - x3 , y2 , z3 ] ,
] ,
faces = [
[ 4 , 5 , 1 ] ,
[ 5 , 6 , 2 ] ,
[ 6 , 7 , 3 ] ,
[ 7 , 4 , 0 ] ,
[ 4 , 1 , 0 ] ,
[ 5 , 2 , 1 ] ,
[ 6 , 3 , 2 ] ,
[ 7 , 0 , 3 ] ,
[ 8 , 9 , 5 ] ,
[ 9 , 10 , 6 ] ,
[ 10 , 11 , 7 ] ,
[ 11 , 8 , 4 ] ,
[ 8 , 5 , 4 ] ,
[ 9 , 6 , 5 ] ,
[ 10 , 7 , 6 ] ,
[ 11 , 4 , 7 ] ,
[ 11 , 10 , 9 ] ,
[ 20 , 21 , 22 ] ,
[ 11 , 9 , 8 ] ,
[ 20 , 22 , 23 ] ,
[ 16 , 17 , 21 ] ,
[ 17 , 18 , 22 ] ,
[ 18 , 19 , 23 ] ,
[ 19 , 16 , 20 ] ,
[ 16 , 21 , 20 ] ,
[ 17 , 22 , 21 ] ,
[ 18 , 23 , 22 ] ,
[ 19 , 20 , 23 ] ,
[ 12 , 13 , 17 ] ,
[ 13 , 14 , 18 ] ,
[ 14 , 15 , 19 ] ,
[ 15 , 12 , 16 ] ,
[ 12 , 17 , 16 ] ,
[ 13 , 18 , 17 ] ,
[ 14 , 19 , 18 ] ,
[ 15 , 16 , 19 ] ,
[ 0 , 1 , 13 ] ,
[ 1 , 2 , 14 ] ,
[ 2 , 3 , 15 ] ,
[ 3 , 0 , 12 ] ,
[ 0 , 13 , 12 ] ,
[ 1 , 14 , 13 ] ,
[ 2 , 15 , 14 ] ,
[ 3 , 12 , 15 ] ,
] ,
2018-12-22 21:17:04 +00:00
convexity = 6
2017-08-30 00:00:16 +00:00
) ;
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: braced_thinning_wall()
//
// Description:
// Makes a rectangular wall with cross-bracing, which thins to a smaller width in the center,
// with angled supports to prevent critical overhangs.
//
// Usage:
// braced_thinning_wall(h, l, thick, [ang], [strut], [wall], [orient], [align]);
//
// Arguments:
// h = height of wall.
// l = length of wall.
// thick = thickness of wall.
// ang = maximum overhang angle of diagonal brace.
// strut = the width of the diagonal brace.
// wall = the thickness of the thinned portion of the wall.
// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// braced_thinning_wall(h=50, l=100, thick=5);
2019-04-19 06:32:17 +00:00
module braced_thinning_wall ( h = 50 , l = 100 , thick = 5 , ang = 30 , strut = 5 , wall = 2 , orient = ORIENT_Y , align = CENTER )
2017-08-30 00:00:16 +00:00
{
dang = atan ( ( h - 2 * strut ) / ( l - 2 * strut ) ) ;
dlen = ( h - 2 * strut ) / sin ( dang ) ;
2019-04-17 02:16:50 +00:00
size = [ l , thick , h ] ;
orient_and_align ( size , orient , align , orig_orient = ORIENT_Y , chain = true ) {
union ( ) {
xrot_copies ( [ 0 , 180 ] ) {
down ( h / 2 ) narrowing_strut ( w = thick , l = l , wall = strut , ang = ang ) ;
fwd ( l / 2 ) xrot ( - 90 ) narrowing_strut ( w = thick , l = h - 0.1 , wall = strut , ang = ang ) ;
intersection ( ) {
cube ( size = [ thick , l , h ] , center = true ) ;
xrot_copies ( [ - dang , dang ] ) {
zspread ( strut / 2 ) {
scale ( [ 1 , 1 , 1.5 ] ) yrot ( 45 ) {
cube ( size = [ thick / sqrt ( 2 ) , dlen , thick / sqrt ( 2 ) ] , center = true ) ;
}
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
cube ( size = [ thick , dlen , strut / 2 ] , center = true ) ;
2017-08-30 00:00:16 +00:00
}
}
}
2019-04-17 02:16:50 +00:00
cube ( size = [ wall , l - 0.1 , h - 0.1 ] , center = true ) ;
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: thinning_triangle()
//
// Description:
// Makes a triangular wall with thick edges, which thins to a smaller width in
// the center, with angled supports to prevent critical overhangs.
//
// Usage:
// thinning_triangle(h, l, thick, [ang], [strut], [wall], [diagonly], [orient], [align|center]);
//
// Arguments:
2017-08-30 00:00:16 +00:00
// h = height of wall.
// l = length of wall.
// thick = thickness of wall.
// ang = maximum overhang angle of diagonal brace.
// strut = the width of the diagonal brace.
// wall = the thickness of the thinned portion of the wall.
2018-09-01 09:36:47 +00:00
// diagonly = boolean, which denotes only the diagonal side (hypotenuse) should be thick.
2019-03-23 04:13:18 +00:00
// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
// center = If true, centers shape. If false, overrides `align` with `UP+BACK`.
2019-03-23 04:13:18 +00:00
//
// Example: Centered
// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=true);
// Example: All Braces
// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=false);
// Example: Diagonal Brace Only
// thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, diagonly=true, center=false);
2019-04-19 06:32:17 +00:00
module thinning_triangle ( h = 50 , l = 100 , thick = 5 , ang = 30 , strut = 5 , wall = 3 , diagonly = false , center = undef , orient = ORIENT_Y , align = CENTER )
2017-08-30 00:00:16 +00:00
{
dang = atan ( h / l ) ;
dlen = h / sin ( dang ) ;
2019-04-17 02:16:50 +00:00
size = [ thick , l , h ] ;
2019-04-19 06:32:17 +00:00
orient_and_align ( size , orient , align , center = center , noncentered = UP + BACK , orig_orient = ORIENT_Y , chain = true ) {
2018-11-21 20:56:35 +00:00
difference ( ) {
union ( ) {
if ( ! diagonly ) {
translate ( [ 0 , 0 , - h / 2 ] )
narrowing_strut ( w = thick , l = l , wall = strut , ang = ang ) ;
translate ( [ 0 , - l / 2 , 0 ] )
xrot ( - 90 ) narrowing_strut ( w = thick , l = h - 0.1 , wall = strut , ang = ang ) ;
2017-08-30 00:00:16 +00:00
}
2018-11-21 20:56:35 +00:00
intersection ( ) {
cube ( size = [ thick , l , h ] , center = true ) ;
xrot ( - dang ) yrot ( 180 ) {
narrowing_strut ( w = thick , l = dlen * 1.2 , wall = strut , ang = ang ) ;
}
}
cube ( size = [ wall , l - 0.1 , h - 0.1 ] , center = true ) ;
2017-08-30 00:00:16 +00:00
}
2018-11-21 20:56:35 +00:00
xrot ( - dang ) {
translate ( [ 0 , 0 , h / 2 ] ) {
cube ( size = [ thick + 0.1 , l * 2 , h ] , center = true ) ;
}
2017-08-30 00:00:16 +00:00
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: sparse_strut()
//
// Description:
// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce
// the need for support material in 3D printing.
//
// Usage:
// sparse_strut(h, l, thick, [strut], [maxang], [max_bridge], [orient], [align])
//
// Arguments:
// h = height of strut wall.
// l = length of strut wall.
// thick = thickness of strut wall.
// maxang = maximum overhang angle of cross-braces.
// max_bridge = maximum bridging distance between cross-braces.
// strut = the width of the cross-braces.
// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// sparse_strut(h=40, l=100, thick=3);
// Example: Thinner Strut
// sparse_strut(h=40, l=100, thick=3, strut=2);
// Example: Larger maxang
// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45);
// Example: Longer max_bridge
// sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45, max_bridge=30);
2019-04-19 06:32:17 +00:00
module sparse_strut ( h = 50 , l = 100 , thick = 4 , maxang = 30 , strut = 5 , max_bridge = 20 , orient = ORIENT_Y , align = CENTER )
2019-03-23 04:13:18 +00:00
{
zoff = h / 2 - strut / 2 ;
yoff = l / 2 - strut / 2 ;
maxhyp = 1.5 * ( max_bridge + strut ) / 2 / sin ( maxang ) ;
maxz = 2 * maxhyp * cos ( maxang ) ;
zreps = ceil ( 2 * zoff / maxz ) ;
zstep = 2 * zoff / zreps ;
hyp = zstep / 2 / cos ( maxang ) ;
maxy = min ( 2 * hyp * sin ( maxang ) , max_bridge + strut ) ;
yreps = ceil ( 2 * yoff / maxy ) ;
ystep = 2 * yoff / yreps ;
ang = atan ( ystep / zstep ) ;
len = zstep / cos ( ang ) ;
2019-04-17 02:16:50 +00:00
size = [ thick , l , h ] ;
orient_and_align ( size , orient , align , orig_orient = ORIENT_Y , chain = true ) {
union ( ) {
zspread ( zoff * 2 )
cube ( size = [ thick , l , strut ] , center = true ) ;
yspread ( yoff * 2 )
cube ( size = [ thick , strut , h ] , center = true ) ;
yspread ( ystep , n = yreps ) {
zspread ( zstep , n = zreps ) {
xrot ( ang ) cube ( size = [ thick , strut , len ] , center = true ) ;
xrot ( - ang ) cube ( size = [ thick , strut , len ] , center = true ) ;
}
2019-03-23 04:13:18 +00:00
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
// Module: sparse_strut3d()
//
// Usage:
// sparse_strut3d(h, w, l, [thick], [maxang], [max_bridge], [strut], [orient], [align]);
//
// Description:
// Makes an open rectangular strut with X-shaped cross-bracing, designed to reduce the
// need for support material in 3D printing.
//
// Arguments:
2017-08-30 00:00:16 +00:00
// h = Z size of strut.
// w = X size of strut.
// l = Y size of strut.
// thick = thickness of strut walls.
// maxang = maximum overhang angle of cross-braces.
// max_bridge = maximum bridging distance between cross-braces.
// strut = the width of the cross-braces.
2019-03-23 04:13:18 +00:00
// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// sparse_strut3d(h=30, w=30, l=100);
// Example: Thinner strut
// sparse_strut3d(h=30, w=30, l=100, strut=2);
// Example: Larger maxang
// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50);
// Example: Smaller max_bridge
// sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50, max_bridge=20);
2019-04-19 06:32:17 +00:00
module sparse_strut3d ( h = 50 , l = 100 , w = 50 , thick = 3 , maxang = 40 , strut = 3 , max_bridge = 30 , orient = ORIENT_Y , align = CENTER )
2017-08-30 00:00:16 +00:00
{
xoff = w - thick ;
yoff = l - thick ;
zoff = h - thick ;
xreps = ceil ( xoff / yoff ) ;
yreps = ceil ( yoff / xoff ) ;
2018-11-21 19:34:32 +00:00
zreps = ceil ( zoff / min ( xoff , yoff ) ) ;
2017-08-30 00:00:16 +00:00
xstep = xoff / xreps ;
ystep = yoff / yreps ;
2018-11-21 19:34:32 +00:00
zstep = zoff / zreps ;
2017-08-30 00:00:16 +00:00
cross_ang = atan2 ( xstep , ystep ) ;
cross_len = hypot ( xstep , ystep ) ;
2018-11-21 19:34:32 +00:00
supp_ang = min ( maxang , min ( atan2 ( max_bridge , zstep ) , atan2 ( cross_len / 2 , zstep ) ) ) ;
supp_reps = floor ( cross_len / 2 / ( zstep * sin ( supp_ang ) ) ) ;
supp_step = cross_len / 2 / supp_reps ;
2019-04-17 02:16:50 +00:00
size = [ w , l , h ] ;
orient_and_align ( size , orient , align , orig_orient = ORIENT_Y , chain = true ) {
2019-03-23 04:13:18 +00:00
intersection ( ) {
union ( ) {
ybridge = ( l - ( yreps + 1 ) * strut ) / yreps ;
xspread ( xoff ) sparse_strut ( h = h , l = l , thick = thick , maxang = maxang , strut = strut , max_bridge = ybridge / ceil ( ybridge / max_bridge ) ) ;
yspread ( yoff ) zrot ( 90 ) sparse_strut ( h = h , l = w , thick = thick , maxang = maxang , strut = strut , max_bridge = max_bridge ) ;
for ( zs = [ 0 : zreps - 1 ] ) {
for ( xs = [ 0 : xreps - 1 ] ) {
for ( ys = [ 0 : yreps - 1 ] ) {
translate ( [ ( xs + 0.5 ) * xstep - xoff / 2 , ( ys + 0.5 ) * ystep - yoff / 2 , ( zs + 0.5 ) * zstep - zoff / 2 ] ) {
zflip_copy ( offset = - ( zstep - strut ) / 2 ) {
xflip_copy ( ) {
zrot ( cross_ang ) {
down ( strut / 2 ) {
cube ( [ strut , cross_len , strut ] , center = true ) ;
2018-11-21 20:40:58 +00:00
}
2019-03-23 04:13:18 +00:00
if ( zreps > 1 ) {
back ( cross_len / 2 ) {
zrot ( - cross_ang ) {
down ( strut ) upcube ( [ strut , strut , zstep + strut ] ) ;
}
}
}
for ( soff = [ 0 : supp_reps - 1 ] ) {
yflip_copy ( ) {
back ( soff * supp_step ) {
skew_xy ( ya = supp_ang ) {
upcube ( [ strut , strut , zstep ] ) ;
}
}
2018-11-21 19:34:32 +00:00
}
}
}
}
}
}
}
}
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
cube ( [ w , l , h ] , center = true ) ;
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: corrugated_wall()
//
// Description:
// Makes a corrugated wall which relieves contraction stress while still
// providing support strength. Designed with 3D printing in mind.
//
// Usage:
// corrugated_wall(h, l, thick, [strut], [wall], [orient], [align]);
//
// Arguments:
2017-08-30 00:00:16 +00:00
// h = height of strut wall.
// l = length of strut wall.
// thick = thickness of strut wall.
// strut = the width of the cross-braces.
2019-03-23 04:13:18 +00:00
// wall = thickness of corrugations.
// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
// Example: Typical Shape
// corrugated_wall(h=50, l=100);
// Example: Wider Strut
// corrugated_wall(h=50, l=100, strut=8);
// Example: Thicker Wall
// corrugated_wall(h=50, l=100, strut=8, wall=3);
2019-04-19 06:32:17 +00:00
module corrugated_wall ( h = 50 , l = 100 , thick = 5 , strut = 5 , wall = 2 , orient = ORIENT_Y , align = CENTER )
2017-08-30 00:00:16 +00:00
{
2019-03-23 04:13:18 +00:00
amplitude = ( thick - wall ) / 2 ;
period = min ( 15 , thick * 2 ) ;
steps = quantup ( segs ( thick / 2 ) , 4 ) ;
step = period / steps ;
il = l - 2 * strut + 2 * step ;
2019-04-17 02:16:50 +00:00
size = [ thick , l , h ] ;
orient_and_align ( size , orient , align , orig_orient = ORIENT_Y , chain = true ) {
union ( ) {
linear_extrude ( height = h - 2 * strut + 0.1 , slices = 2 , convexity = ceil ( 2 * il / period ) , center = true ) {
polygon (
points = concat (
[ for ( y = [ - il / 2 : step : il / 2 ] ) [ amplitude * sin ( y / period * 360 ) - wall / 2 , y ] ] ,
[ for ( y = [ il / 2 : - step : - il / 2 ] ) [ amplitude * sin ( y / period * 360 ) + wall / 2 , y ] ]
)
) ;
}
difference ( ) {
cube ( [ thick , l , h ] , center = true ) ;
cube ( [ thick + 0.5 , l - 2 * strut , h - 2 * strut ] , center = true ) ;
}
2019-03-23 04:13:18 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2019-03-23 04:13:18 +00:00
}
}
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
// Section: Miscellaneous
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
// Module: nil()
//
// Description:
// Useful when you MUST pass a child to a module, but you want it to be nothing.
2019-04-22 08:08:41 +00:00
module nil ( ) union ( ) { }
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
// Module: noop()
//
// Description:
// Passes through the children passed to it, with no action at all.
// Useful while debugging when you want to replace a command.
2019-04-22 08:08:41 +00:00
module noop ( orient = ORIENT_Z ) orient_and_align ( [ 0 , 0 , 0 ] , orient , CENTER , chain = true ) { nil ( ) ; children ( ) ; }
2019-03-23 04:13:18 +00:00
// Module: pie_slice()
//
// Description:
// Creates a pie slice shape.
//
// Usage:
// pie_slice(ang, l|h, r|d, [orient], [align|center]);
// pie_slice(ang, l|h, r1|d1, r2|d2, [orient], [align|center]);
//
// Arguments:
// ang = pie slice angle in degrees.
// h = height of pie slice.
// r = radius of pie slice.
// r1 = bottom radius of pie slice.
// r2 = top radius of pie slice.
// d = diameter of pie slice.
// d1 = bottom diameter of pie slice.
// d2 = top diameter of pie slice.
// orient = Orientation of the pie slice. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the pie slice. Use the constants from `constants.scad`. Default: `CENTER`.
// center = If given, overrides `align`. A true value sets `align=CENTER`, false sets `align=UP`.
2019-03-23 04:13:18 +00:00
//
// Example: Cylindrical Pie Slice
// pie_slice(ang=45, l=20, r=30);
// Example: Conical Pie Slice
// pie_slice(ang=60, l=20, d1=50, d2=70);
module pie_slice (
ang = 30 , l = undef ,
r = 10 , r1 = undef , r2 = undef ,
d = undef , d1 = undef , d2 = undef ,
2019-04-19 06:32:17 +00:00
orient = ORIENT_Z , align = UP ,
2019-03-23 04:13:18 +00:00
center = undef , h = undef
) {
l = first_defined ( [ l , h , 1 ] ) ;
r1 = get_radius ( r1 , r , d1 , d , 10 ) ;
r2 = get_radius ( r2 , r , d2 , d , 10 ) ;
maxd = max ( r1 , r2 ) + 0.1 ;
2019-04-17 02:16:50 +00:00
size = [ 2 * r1 , 2 * r1 , l ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , center = center , geometry = "cylinder" , chain = true ) {
2019-03-23 04:13:18 +00:00
difference ( ) {
cylinder ( r1 = r1 , r2 = r2 , h = l , center = true ) ;
if ( ang < 180 ) rotate ( ang ) back ( maxd / 2 ) cube ( [ 2 * maxd , maxd , l + 0.1 ] , center = true ) ;
difference ( ) {
fwd ( maxd / 2 ) cube ( [ 2 * maxd , maxd , l + 0.2 ] , center = true ) ;
if ( ang > 180 ) rotate ( ang - 180 ) back ( maxd / 2 ) cube ( [ 2 * maxd , maxd , l + 0.1 ] , center = true ) ;
}
2017-08-30 00:00:16 +00:00
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
2019-03-23 04:13:18 +00:00
// Module: interior_fillet()
//
// Description:
// Creates a shape that can be unioned into a concave joint between two faces, to fillet them.
// Center this part along the concave edge to be chamferred and union it in.
//
// Usage:
// interior_fillet(l, r, [ang], [overlap], [orient], [align]);
//
// Arguments:
// l = length of edge to fillet.
// r = radius of fillet.
// ang = angle between faces to fillet.
// overlap = overlap size for unioning with faces.
// orient = Orientation of the fillet. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the fillet. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// union() {
// translate([0,2,-4]) upcube([20, 4, 24]);
// translate([0,-10,-4]) upcube([20, 20, 4]);
// color("green") interior_fillet(l=20, r=10, orient=ORIENT_XNEG);
// }
//
// Example:
// interior_fillet(l=40, r=10, orient=ORIENT_Y_90);
2019-04-19 06:32:17 +00:00
module interior_fillet ( l = 1.0 , r = 1.0 , ang = 90 , overlap = 0.01 , orient = ORIENT_X , align = CENTER ) {
2019-03-23 04:13:18 +00:00
dy = r / tan ( ang / 2 ) ;
2019-04-17 02:16:50 +00:00
size = [ l , r , r ] ;
orient_and_align ( size , orient , align , orig_orient = ORIENT_X , chain = true ) {
2019-03-23 04:13:18 +00:00
difference ( ) {
translate ( [ 0 , - overlap / tan ( ang / 2 ) , - overlap ] ) {
if ( ang = = 90 ) {
translate ( [ 0 , r / 2 , r / 2 ] ) cube ( [ l , r , r ] , center = true ) ;
} else {
rotate ( [ 90 , 0 , 90 ] ) pie_slice ( ang = ang , r = dy + overlap , h = l , center = true ) ;
}
}
translate ( [ 0 , dy , r ] ) xcyl ( l = l + 0.1 , r = r ) ;
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
2019-03-23 04:13:18 +00:00
}
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
// Module: slot()
//
// Description:
// Makes a linear slot with rounded ends, appropriate for bolts to slide along.
//
// Usage:
// slot(h, l, r|d, [orient], [align|center]);
// slot(h, p1, p2, r|d, [orient], [align|center]);
// slot(h, l, r1|d1, r2|d2, [orient], [align|center]);
// slot(h, p1, p2, r1|d1, r2|d2, [orient], [align|center]);
//
// Arguments:
// p1 = center of starting circle of slot.
// p2 = center of ending circle of slot.
// l = length of slot along the X axis.
// h = height of slot shape. (default: 10)
// r = radius of slot circle. (default: 5)
// r1 = bottom radius of slot cone.
// r2 = top radius of slot cone.
// d = diameter of slot circle.
// d1 = bottom diameter of slot cone.
// d2 = top diameter of slot cone.
//
// Example: Between Two Points
// slot([0,0,0], [50,50,0], r1=5, r2=10, h=5);
// Example: By Length
// slot(l=50, r1=5, r2=10, h=5);
module slot (
p1 = undef , p2 = undef , h = 10 , l = undef ,
r = undef , r1 = undef , r2 = undef ,
d = undef , d1 = undef , d2 = undef
) {
r1 = get_radius ( r1 = r1 , r = r , d1 = d1 , d = d , dflt = 5 ) ;
r2 = get_radius ( r1 = r2 , r = r , d1 = d2 , d = d , dflt = 5 ) ;
sides = quantup ( segs ( max ( r1 , r2 ) ) , 4 ) ;
2019-04-17 02:16:50 +00:00
// TODO: implement orient and align.
// TODO: implement connectors.
2019-03-23 04:13:18 +00:00
hull ( ) spread ( p1 = p1 , p2 = p2 , l = l , n = 2 ) cyl ( l = h , r1 = r1 , r2 = r2 , center = true , $fn = sides ) ;
}
// Module: arced_slot()
//
// Description:
// Makes an arced slot, appropriate for bolts to slide along.
//
// Usage:
// arced_slot(h, r|d, sr|sd, [sa], [ea], [orient], [align|center], [$fn2]);
// arced_slot(h, r|d, sr1|sd1, sr2|sd2, [sa], [ea], [orient], [align|center], [$fn2]);
//
// Arguments:
// cp = centerpoint of slot arc. (default: [0, 0, 0])
// h = height of slot arc shape. (default: 1.0)
// r = radius of slot arc. (default: 0.5)
// d = diameter of slot arc. (default: 1.0)
// sr = radius of slot channel. (default: 0.5)
// sd = diameter of slot channel. (default: 0.5)
// sr1 = bottom radius of slot channel cone. (use instead of sr)
// sr2 = top radius of slot channel cone. (use instead of sr)
// sd1 = bottom diameter of slot channel cone. (use instead of sd)
// sd2 = top diameter of slot channel cone. (use instead of sd)
// sa = starting angle. (Default: 0.0)
// ea = ending angle. (Default: 90.0)
// orient = Orientation of the arced slot. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`.
2019-04-19 06:32:17 +00:00
// align = Alignment of the arced slot. Use the constants from `constants.scad`. Default: `CENTER`.
2019-03-23 04:13:18 +00:00
// center = If true, centers vertically. If false, drops flush with XY plane. Overrides `align`.
// $fn2 = The $fn value to use on the small round endcaps. The major arcs are still based on $fn. Default: $fn
//
// Example: Typical Arced Slot
// arced_slot(d=60, h=5, sd=10, sa=60, ea=280);
// Example: Conical Arced Slot
// arced_slot(r=60, h=5, sd1=10, sd2=15, sa=45, ea=180);
module arced_slot (
r = undef , d = undef , h = 1.0 ,
sr = undef , sr1 = undef , sr2 = undef ,
sd = undef , sd1 = undef , sd2 = undef ,
sa = 0 , ea = 90 , cp = [ 0 , 0 , 0 ] ,
2019-04-19 06:32:17 +00:00
orient = ORIENT_Z , align = CENTER ,
2019-03-23 04:13:18 +00:00
$fn 2 = undef
) {
r = get_radius ( r = r , d = d , dflt = 2 ) ;
sr1 = get_radius ( sr1 , sr , sd1 , sd , 2 ) ;
sr2 = get_radius ( sr2 , sr , sd2 , sd , 2 ) ;
fn_minor = first_defined ( [ $fn 2 , $fn ] ) ;
da = ea - sa ;
2019-04-17 02:16:50 +00:00
size = [ r + sr1 , r + sr1 , h ] ;
2019-04-22 08:08:41 +00:00
orient_and_align ( size , orient , align , geometry = "cylinder" , chain = true ) {
2019-03-23 04:13:18 +00:00
translate ( cp ) {
zrot ( sa ) {
difference ( ) {
2019-04-19 06:32:17 +00:00
pie_slice ( ang = da , l = h , r1 = r + sr1 , r2 = r + sr2 , orient = ORIENT_Z , align = CENTER ) ;
2019-03-23 04:13:18 +00:00
cylinder ( h = h + 0.1 , r1 = r - sr1 , r2 = r - sr2 , center = true ) ;
}
right ( r ) cylinder ( h = h , r1 = sr1 , r2 = sr2 , center = true , $fn = fn_minor ) ;
zrot ( da ) right ( r ) cylinder ( h = h , r1 = sr1 , r2 = sr2 , center = true , $fn = fn_minor ) ;
}
}
2019-04-17 02:16:50 +00:00
children ( ) ;
2017-08-30 00:00:16 +00:00
}
}
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap