2019-09-19 10:21:23 +00:00
//////////////////////////////////////////////////////////////////////
// LibFile: bottlecaps.scad
// Bottle caps and necks for PCO18XX standard plastic beverage bottles.
2021-01-05 09:20:01 +00:00
// Includes:
2019-09-19 10:21:23 +00:00
// include <BOSL2/std.scad>
// include <BOSL2/bottlecaps.scad>
//////////////////////////////////////////////////////////////////////
2019-09-19 10:26:04 +00:00
include < threading.scad >
2019-09-19 10:21:23 +00:00
include < knurling.scad >
2021-08-24 22:00:36 +00:00
include < structs.scad >
include < rounding.scad >
2019-09-19 10:21:23 +00:00
// Section: PCO-1810 Bottle Threading
// Module: pco1810_neck()
// Usage:
2021-06-27 03:59:33 +00:00
// pco1810_neck([wall])
2019-09-19 10:21:23 +00:00
// Description:
// Creates an approximation of a standard PCO-1810 threaded beverage bottle neck.
// Arguments:
// wall = Wall thickness in mm.
2021-01-28 01:18:06 +00:00
// ---
2019-09-19 10:21:23 +00:00
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "tamper-ring" = Centered at the top of the anti-tamper ring channel.
// "support-ring" = Centered at the bottom of the support ring.
// Example:
// pco1810_neck();
2021-01-28 01:18:06 +00:00
// Example: Standard Anchors
// pco1810_neck() show_anchors(custom=false);
// Example: Custom Named Anchors
// expose_anchors(0.3)
// pco1810_neck()
// show_anchors(std=false);
2019-09-19 10:21:23 +00:00
module pco1810_neck ( wall = 2 , anchor = "support-ring" , spin = 0 , orient = UP )
{
2020-05-30 02:04:34 +00:00
inner_d = 21.74 ;
neck_d = 26.19 ;
neck_h = 5.00 ;
support_d = 33.00 ;
support_width = 1.45 ;
support_rad = 0.40 ;
support_h = 21.00 ;
support_ang = 16 ;
tamper_ring_d = 27.97 ;
tamper_ring_width = 0.50 ;
tamper_ring_r = 1.60 ;
tamper_base_d = 25.71 ;
tamper_base_h = 14.10 ;
threadbase_d = 24.51 ;
thread_pitch = 3.18 ;
2021-08-24 03:03:25 +00:00
flank_angle = 20 ;
2020-05-30 02:04:34 +00:00
thread_od = 27.43 ;
lip_d = 25.07 ;
lip_h = 1.70 ;
lip_leadin_r = 0.20 ;
lip_recess_d = 24.94 ;
lip_recess_h = 1.00 ;
lip_roundover_r = 0.58 ;
2019-09-19 10:21:23 +00:00
2020-05-30 02:04:34 +00:00
$fn = segs ( support_d / 2 ) ;
h = support_h + neck_h ;
thread_h = ( thread_od - threadbase_d ) / 2 ;
anchors = [
anchorpt ( "support-ring" , [ 0 , 0 , neck_h - h / 2 ] ) ,
anchorpt ( "tamper-ring" , [ 0 , 0 , h / 2 - tamper_base_h ] )
] ;
2021-01-28 01:18:06 +00:00
attachable ( anchor , spin , orient , d1 = neck_d , d2 = lip_recess_d + 2 * lip_leadin_r , l = h , anchors = anchors ) {
2020-05-30 02:04:34 +00:00
down ( h / 2 ) {
rotate_extrude ( convexity = 10 ) {
polygon ( turtle (
state = [ inner_d / 2 , 0 ] , [
"untilx" , neck_d / 2 ,
"left" , 90 ,
"move" , neck_h - 1 ,
"arcright" , 1 , 90 ,
"untilx" , support_d / 2 - support_rad ,
"arcleft" , support_rad , 90 ,
"move" , support_width ,
"arcleft" , support_rad , 90 - support_ang ,
"untilx" , tamper_base_d / 2 ,
"right" , 90 - support_ang ,
"untily" , h - tamper_base_h , // Tamper ring holder base.
"right" , 90 ,
"untilx" , tamper_ring_d / 2 ,
"left" , 90 ,
"move" , tamper_ring_width ,
"arcleft" , tamper_ring_r , 90 ,
"untilx" , threadbase_d / 2 ,
"right" , 90 ,
"untily" , h - lip_h - lip_leadin_r , // Lip base.
"arcright" , lip_leadin_r , 90 ,
"untilx" , lip_d / 2 ,
"left" , 90 ,
"untily" , h - lip_recess_h ,
"left" , 90 ,
"untilx" , lip_recess_d / 2 ,
"right" , 90 ,
"untily" , h - lip_roundover_r ,
"arcleft" , lip_roundover_r , 90 ,
"untilx" , inner_d / 2
]
) ) ;
}
up ( h - lip_h ) {
bottom_half ( ) {
difference ( ) {
thread_helix (
2021-01-31 23:43:50 +00:00
d = threadbase_d - 0.1 ,
2020-05-30 02:04:34 +00:00
pitch = thread_pitch ,
thread_depth = thread_h + 0.1 ,
2021-08-24 03:03:25 +00:00
flank_angle = flank_angle ,
2020-05-30 02:04:34 +00:00
twist = 810 ,
2021-01-31 23:43:50 +00:00
higbee = thread_h * 2 ,
2020-05-30 02:04:34 +00:00
anchor = TOP
) ;
zrot_copies ( rots = [ 90 , 270 ] ) {
zrot_copies ( rots = [ - 28 , 28 ] , r = threadbase_d / 2 ) {
prismoid ( [ 20 , 1.82 ] , [ 20 , 1.82 + 2 * sin ( 29 ) * thread_h ] , h = thread_h + 0.1 , anchor = BOT , orient = RIGHT ) ;
}
}
}
}
}
}
children ( ) ;
}
2019-09-19 10:21:23 +00:00
}
2021-01-29 00:59:46 +00:00
function pco1810_neck ( wall = 2 , anchor = "support-ring" , spin = 0 , orient = UP ) =
no_function ( "pco1810_neck" ) ;
2019-09-19 10:21:23 +00:00
// Module: pco1810_cap()
// Usage:
2021-06-27 03:59:33 +00:00
// pco1810_cap([wall], [texture]);
2019-09-19 10:21:23 +00:00
// Description:
// Creates a basic cap for a PCO1810 threaded beverage bottle.
// Arguments:
// wall = Wall thickness in mm.
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
2021-01-28 01:18:06 +00:00
// ---
2019-09-19 10:21:23 +00:00
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "inside-top" = Centered on the inside top of the cap.
// Examples:
// pco1810_cap();
// pco1810_cap(texture="knurled");
// pco1810_cap(texture="ribbed");
2021-01-28 01:22:26 +00:00
// Example: Standard Anchors
2021-01-28 01:18:06 +00:00
// pco1810_cap(texture="ribbed") show_anchors(custom=false);
2021-01-28 01:22:26 +00:00
// Example: Custom Named Anchors
2021-01-28 01:18:06 +00:00
// expose_anchors(0.3)
// pco1810_cap(texture="ribbed")
// show_anchors(std=false);
2019-09-19 10:21:23 +00:00
module pco1810_cap ( wall = 2 , texture = "none" , anchor = BOTTOM , spin = 0 , orient = UP )
{
2020-05-30 02:04:34 +00:00
cap_id = 28.58 ;
tamper_ring_h = 14.10 ;
thread_pitch = 3.18 ;
2021-08-24 03:03:25 +00:00
flank_angle = 20 ;
2020-05-30 02:04:34 +00:00
thread_od = cap_id ;
thread_depth = 1.6 ;
2019-09-19 10:21:23 +00:00
2020-05-30 02:04:34 +00:00
$fn = segs ( 33 / 2 ) ;
w = cap_id + 2 * wall ;
h = tamper_ring_h + wall ;
anchors = [
anchorpt ( "inside-top" , [ 0 , 0 , - ( h / 2 - wall ) ] )
] ;
attachable ( anchor , spin , orient , d = w , l = h , anchors = anchors ) {
down ( h / 2 ) zrot ( 45 ) {
difference ( ) {
union ( ) {
if ( texture = = "knurled" ) {
knurled_cylinder ( d = w , helix = 45 , l = tamper_ring_h + wall , anchor = BOTTOM ) ;
cyl ( d = w - 1.5 , l = tamper_ring_h + wall , anchor = BOTTOM ) ;
} else if ( texture = = "ribbed" ) {
zrot_copies ( n = 30 , r = ( w - 1 ) / 2 ) {
cube ( [ 1 , 1 , tamper_ring_h + wall ] , anchor = BOTTOM ) ;
}
cyl ( d = w - 1 , l = tamper_ring_h + wall , anchor = BOTTOM ) ;
} else {
cyl ( d = w , l = tamper_ring_h + wall , anchor = BOTTOM ) ;
}
}
up ( wall ) cyl ( d = cap_id , h = tamper_ring_h + wall , anchor = BOTTOM ) ;
}
2021-08-24 03:03:25 +00:00
up ( wall + 2 ) thread_helix ( d = thread_od - thread_depth * 2 , pitch = thread_pitch , thread_depth = thread_depth , flank_angle = flank_angle , twist = 810 , higbee = thread_depth , internal = true , anchor = BOTTOM ) ;
2020-05-30 02:04:34 +00:00
}
children ( ) ;
}
2019-09-19 10:21:23 +00:00
}
2021-01-29 00:59:46 +00:00
function pco1810_cap ( wall = 2 , texture = "none" , anchor = BOTTOM , spin = 0 , orient = UP ) =
no_function ( "pco1810_cap" ) ;
2019-09-19 10:21:23 +00:00
// Section: PCO-1881 Bottle Threading
// Module: pco1881_neck()
// Usage:
2021-06-27 03:59:33 +00:00
// pco1881_neck([wall])
2019-09-19 10:21:23 +00:00
// Description:
// Creates an approximation of a standard PCO-1881 threaded beverage bottle neck.
// Arguments:
// wall = Wall thickness in mm.
2021-01-28 01:18:06 +00:00
// ---
2019-09-19 10:21:23 +00:00
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "tamper-ring" = Centered at the top of the anti-tamper ring channel.
// "support-ring" = Centered at the bottom of the support ring.
// Example:
// pco1881_neck();
2021-01-28 01:18:06 +00:00
// Example:
// pco1881_neck() show_anchors(custom=false);
// Example:
// expose_anchors(0.3)
// pco1881_neck()
// show_anchors(std=false);
2019-09-19 10:21:23 +00:00
module pco1881_neck ( wall = 2 , anchor = "support-ring" , spin = 0 , orient = UP )
{
2020-05-30 02:04:34 +00:00
inner_d = 21.74 ;
neck_d = 26.19 ;
neck_h = 5.00 ;
support_d = 33.00 ;
support_width = 0.58 ;
support_rad = 0.30 ;
support_h = 17.00 ;
support_ang = 15 ;
tamper_ring_d = 28.00 ;
tamper_ring_width = 0.30 ;
tamper_ring_ang = 45 ;
tamper_base_d = 25.71 ;
tamper_base_h = 11.20 ;
tamper_divot_r = 1.08 ;
threadbase_d = 24.20 ;
thread_pitch = 2.70 ;
2021-08-24 03:03:25 +00:00
flank_angle = 15 ;
2020-05-30 02:04:34 +00:00
thread_od = 27.4 ;
lip_d = 25.07 ;
lip_h = 1.70 ;
lip_leadin_r = 0.30 ;
lip_recess_d = 24.94 ;
lip_recess_h = 1.00 ;
lip_roundover_r = 0.58 ;
2019-09-19 10:21:23 +00:00
2020-05-30 02:04:34 +00:00
$fn = segs ( support_d / 2 ) ;
h = support_h + neck_h ;
thread_h = ( thread_od - threadbase_d ) / 2 ;
anchors = [
anchorpt ( "support-ring" , [ 0 , 0 , neck_h - h / 2 ] ) ,
anchorpt ( "tamper-ring" , [ 0 , 0 , h / 2 - tamper_base_h ] )
] ;
2021-01-28 01:18:06 +00:00
attachable ( anchor , spin , orient , d1 = neck_d , d2 = lip_recess_d + 2 * lip_leadin_r , l = h , anchors = anchors ) {
2020-05-30 02:04:34 +00:00
down ( h / 2 ) {
rotate_extrude ( convexity = 10 ) {
polygon ( turtle (
state = [ inner_d / 2 , 0 ] , [
"untilx" , neck_d / 2 ,
"left" , 90 ,
"move" , neck_h - 1 ,
"arcright" , 1 , 90 ,
"untilx" , support_d / 2 - support_rad ,
"arcleft" , support_rad , 90 ,
"move" , support_width ,
"arcleft" , support_rad , 90 - support_ang ,
"untilx" , tamper_base_d / 2 ,
"arcright" , tamper_divot_r , 180 - support_ang * 2 ,
"left" , 90 - support_ang ,
"untily" , h - tamper_base_h , // Tamper ring holder base.
"right" , 90 ,
"untilx" , tamper_ring_d / 2 ,
"left" , 90 ,
"move" , tamper_ring_width ,
"left" , tamper_ring_ang ,
"untilx" , threadbase_d / 2 ,
"right" , tamper_ring_ang ,
"untily" , h - lip_h - lip_leadin_r , // Lip base.
"arcright" , lip_leadin_r , 90 ,
"untilx" , lip_d / 2 ,
"left" , 90 ,
"untily" , h - lip_recess_h ,
"left" , 90 ,
"untilx" , lip_recess_d / 2 ,
"right" , 90 ,
"untily" , h - lip_roundover_r ,
"arcleft" , lip_roundover_r , 90 ,
"untilx" , inner_d / 2
]
) ) ;
}
up ( h - lip_h ) {
difference ( ) {
thread_helix (
2021-01-31 23:43:50 +00:00
d = threadbase_d - 0.1 ,
2020-05-30 02:04:34 +00:00
pitch = thread_pitch ,
thread_depth = thread_h + 0.1 ,
2021-08-24 03:03:25 +00:00
flank_angle = flank_angle ,
2020-05-30 02:04:34 +00:00
twist = 650 ,
2021-01-31 23:43:50 +00:00
higbee = thread_h * 2 ,
2020-05-30 02:04:34 +00:00
anchor = TOP
) ;
zrot_copies ( rots = [ 90 , 270 ] ) {
zrot_copies ( rots = [ - 28 , 28 ] , r = threadbase_d / 2 ) {
prismoid ( [ 20 , 1.82 ] , [ 20 , 1.82 + 2 * sin ( 29 ) * thread_h ] , h = thread_h + 0.1 , anchor = BOT , orient = RIGHT ) ;
}
}
}
}
}
children ( ) ;
}
2019-09-19 10:21:23 +00:00
}
2021-01-29 00:59:46 +00:00
function pco1881_neck ( wall = 2 , anchor = "support-ring" , spin = 0 , orient = UP ) =
no_function ( "pco1881_neck" ) ;
2019-09-19 10:21:23 +00:00
// Module: pco1881_cap()
// Usage:
2021-06-27 03:59:33 +00:00
// pco1881_cap(wall, [texture]);
2019-09-19 10:21:23 +00:00
// Description:
// Creates a basic cap for a PCO1881 threaded beverage bottle.
// Arguments:
// wall = Wall thickness in mm.
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "inside-top" = Centered on the inside top of the cap.
// Examples:
// pco1881_cap();
// pco1881_cap(texture="knurled");
// pco1881_cap(texture="ribbed");
2021-01-28 01:18:06 +00:00
// Example: Standard Anchors
// pco1881_cap(texture="ribbed") show_anchors(custom=false);
// Example: Custom Named Anchors
// expose_anchors(0.5)
// pco1881_cap(texture="ribbed")
// show_anchors(std=false);
2019-09-19 10:21:23 +00:00
module pco1881_cap ( wall = 2 , texture = "none" , anchor = BOTTOM , spin = 0 , orient = UP )
{
2020-05-30 02:04:34 +00:00
$fn = segs ( 33 / 2 ) ;
w = 28.58 + 2 * wall ;
h = 11.2 + wall ;
anchors = [
anchorpt ( "inside-top" , [ 0 , 0 , - ( h / 2 - wall ) ] )
] ;
attachable ( anchor , spin , orient , d = w , l = h , anchors = anchors ) {
down ( h / 2 ) zrot ( 45 ) {
difference ( ) {
union ( ) {
if ( texture = = "knurled" ) {
knurled_cylinder ( d = w , helix = 45 , l = 11.2 + wall , anchor = BOTTOM ) ;
cyl ( d = w - 1.5 , l = 11.2 + wall , anchor = BOTTOM ) ;
} else if ( texture = = "ribbed" ) {
zrot_copies ( n = 30 , r = ( w - 1 ) / 2 ) {
cube ( [ 1 , 1 , 11.2 + wall ] , anchor = BOTTOM ) ;
}
cyl ( d = w - 1 , l = 11.2 + wall , anchor = BOTTOM ) ;
} else {
cyl ( d = w , l = 11.2 + wall , anchor = BOTTOM ) ;
}
}
up ( wall ) cyl ( d = 28.58 , h = 11.2 + wall , anchor = BOTTOM ) ;
}
2021-08-24 03:03:25 +00:00
up ( wall + 2 ) thread_helix ( d = 25.5 , pitch = 2.7 , thread_depth = 1.6 , flank_angle = 15 , twist = 650 , higbee = 1.6 , internal = true , anchor = BOTTOM ) ;
2020-05-30 02:04:34 +00:00
}
children ( ) ;
}
2019-09-19 10:21:23 +00:00
}
2021-01-29 00:59:46 +00:00
function pco1881_cap ( wall = 2 , texture = "none" , anchor = BOTTOM , spin = 0 , orient = UP ) =
no_function ( "pco1881_cap" ) ;
2019-09-19 10:21:23 +00:00
2021-05-09 23:43:48 +00:00
// Section: Generic Bottle Connectors
// Module: generic_bottle_neck()
// Usage:
2021-06-27 03:59:33 +00:00
// generic_bottle_neck([wall], ...)
2021-05-09 23:43:48 +00:00
// Description:
// Creates a bottle neck given specifications.
// Arguments:
// wall = distance between ID and any wall that may be below the support
// neck_d = Outer diameter of neck without threads
// id = Inner diameter of neck
// thread_od = Outer diameter of thread
// height = Height of neck above support
// support_d = Outer diameter of support ring. Set to 0 for no support.
// pitch = Thread pitch
// round_supp = True to round the lower edge of the support ring
// ---
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "support-ring" = Centered at the bottom of the support ring.
// Example:
// generic_bottle_neck();
module generic_bottle_neck (
wall ,
neck_d = 25 ,
id = 21.4 ,
thread_od = 27.2 ,
height = 17 ,
support_d = 33.0 ,
pitch = 3.2 ,
round_supp = false ,
anchor = "support-ring" ,
spin = 0 ,
orient = UP
) {
inner_d = id ;
neck_d = neck_d ;
supp_d = max ( neck_d , support_d ) ;
thread_pitch = pitch ;
2021-08-24 03:03:25 +00:00
flank_angle = 15 ;
2021-05-09 23:43:48 +00:00
diamMagMult = neck_d / 26.19 ;
heightMagMult = height / 17.00 ;
sup_r = 0.30 * ( heightMagMult > 1 ? heightMagMult : 1 ) ;
support_r = floor ( ( ( supp_d = = neck_d ) ? sup_r : min ( sup_r , ( supp_d - neck_d ) / 2 ) ) * 5000 ) / 10000 ;
support_rad = ( wall = = undef || ! round_supp ) ? support_r :
min ( support_r , floor ( ( supp_d - ( inner_d + 2 * wall ) ) * 5000 ) / 10000 ) ;
//Too small of a radius will cause errors with the arc, this limits granularity to .0001mm
support_width = 1 * ( heightMagMult > 1 ? heightMagMult : 1 ) * sign ( support_d ) ;
roundover = 0.58 * diamMagMult ;
lip_roundover_r = ( roundover > ( neck_d - inner_d ) / 2 ) ? 0 : roundover ;
h = height + support_width ;
threadbase_d = neck_d - 0.8 * diamMagMult ;
$fn = segs ( 33 / 2 ) ;
thread_h = ( thread_od - threadbase_d ) / 2 ;
anchors = [
anchorpt ( "support-ring" , [ 0 , 0 , 0 - h / 2 ] )
] ;
attachable ( anchor , spin , orient , d1 = neck_d , d2 = 0 , l = h , anchors = anchors ) {
down ( h / 2 ) {
rotate_extrude ( convexity = 10 ) {
polygon ( turtle (
state = [ inner_d / 2 , 0 ] , ( supp_d ! = neck_d ) ? [
"untilx" , supp_d / 2 - ( ( round_supp ) ? support_rad : 0 ) ,
"arcleft" , ( ( round_supp ) ? support_rad : 0 ) , 90 ,
"untily" , support_width - support_rad ,
"arcleft" , support_rad , 90 ,
"untilx" , neck_d / 2 ,
"right" , 90 ,
"untily" , h - lip_roundover_r ,
"arcleft" , lip_roundover_r , 90 ,
"untilx" , inner_d / 2
] : [
"untilx" , supp_d / 2 - ( ( round_supp ) ? support_rad : 0 ) ,
"arcleft" , ( ( round_supp ) ? support_rad : 0 ) , 90 ,
"untily" , h - lip_roundover_r ,
"arcleft" , lip_roundover_r , 90 ,
"untilx" , inner_d / 2
]
) ) ;
}
up ( h - pitch / 2 - lip_roundover_r ) {
difference ( ) {
thread_helix (
d = threadbase_d - 0.1 * diamMagMult ,
pitch = thread_pitch ,
thread_depth = thread_h + 0.1 * diamMagMult ,
2021-08-24 03:03:25 +00:00
flank_angle = flank_angle ,
2021-05-09 23:43:48 +00:00
twist = 360 * ( height - pitch - lip_roundover_r ) * . 6167 / pitch ,
higbee = thread_h * 2 ,
anchor = TOP
) ;
zrot_copies ( rots = [ 90 , 270 ] ) {
zrot_copies ( rots = [ - 28 , 28 ] , r = threadbase_d / 2 ) {
prismoid (
[ 20 * heightMagMult , 1.82 * diamMagMult ] ,
[ 20 * heightMagMult , 1.82 * diamMagMult * . 6 + 2 * sin ( 29 ) * thread_h ] ,
h = thread_h + 0.1 * diamMagMult ,
anchor = BOT ,
orient = RIGHT
) ;
}
}
}
}
}
children ( ) ;
}
}
function generic_bottle_neck (
2021-06-23 00:20:08 +00:00
neck_d ,
2021-05-09 23:43:48 +00:00
id ,
thread_od ,
height ,
support_d ,
pitch ,
round_supp ,
wall ,
anchor , spin , orient
) = no_function ( "generic_bottle_neck" ) ;
// Module: generic_bottle_cap()
// Usage:
2021-06-27 03:59:33 +00:00
// generic_bottle_cap(wall, [texture], ...);
2021-05-09 23:43:48 +00:00
// Description:
// Creates a basic threaded cap given specifications.
// Arguments:
// wall = Wall thickness in mm.
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
// ---
// height = Interior height of the cap in mm.
// thread_od = Outer diameter of the threads in mm.
// tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius.
// neck_od = Outer diameter of neck in mm.
2021-08-24 03:03:25 +00:00
// flank_angle = Angle of taper on threads.
2021-05-09 23:43:48 +00:00
// pitch = Thread pitch in mm.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Extra Anchors:
// "inside-top" = Centered on the inside top of the cap.
// Examples:
// generic_bottle_cap();
// generic_bottle_cap(texture="knurled");
// generic_bottle_cap(texture="ribbed");
module generic_bottle_cap (
wall = 2 ,
texture = "none" ,
height = 11.2 ,
thread_od = 28.58 ,
tolerance = . 2 ,
neck_od = 25.5 ,
2021-08-24 03:03:25 +00:00
flank_angle = 15 ,
2021-05-09 23:43:48 +00:00
pitch = 4 ,
anchor = BOTTOM ,
spin = 0 ,
orient = UP
) {
$fn = segs ( 33 / 2 ) ;
threadOuterDTol = thread_od + 2 * tolerance ;
w = threadOuterDTol + 2 * wall ;
h = height + wall ;
neckOuterDTol = neck_od + 2 * tolerance ;
threadDepth = ( thread_od - neck_od ) / 2 + . 8 ;
diamMagMult = ( w > 32.58 ) ? w / 32.58 : 1 ;
heightMagMult = ( height > 11.2 ) ? height / 11.2 : 1 ;
anchors = [
anchorpt ( "inside-top" , [ 0 , 0 , - ( h / 2 - wall ) ] )
] ;
attachable ( anchor , spin , orient , d = w , l = h , anchors = anchors ) {
down ( h / 2 ) {
difference ( ) {
union ( ) {
// For the knurled and ribbed caps the PCO caps in BOSL2 cut into the wall
// thickness so the wall+texture are the specified wall thickness. That
// seems wrong so this does specified thickness+texture
if ( texture = = "knurled" ) {
knurled_cylinder ( d = w + 1.5 * diamMagMult , helix = 45 , l = h , anchor = BOTTOM ) ;
cyl ( d = w , l = h , anchor = BOTTOM ) ;
} else if ( texture = = "ribbed" ) {
zrot_copies ( n = 30 , r = ( w + . 2 * diamMagMult ) / 2 ) {
cube ( [ 1 * diamMagMult , 1 * diamMagMult , h ] , anchor = BOTTOM ) ;
}
cyl ( d = w , l = h , anchor = BOTTOM ) ;
} else {
cyl ( d = w , l = h , anchor = BOTTOM ) ;
}
}
up ( wall ) cyl ( d = threadOuterDTol , h = h , anchor = BOTTOM ) ;
}
difference ( ) {
up ( wall + pitch / 2 ) {
2021-08-24 03:03:25 +00:00
thread_helix ( d = neckOuterDTol , pitch = pitch , thread_depth = threadDepth , flank_angle = flank_angle , twist = 360 * ( ( height - pitch ) / pitch ) , higbee = threadDepth , internal = true , anchor = BOTTOM ) ;
2021-05-09 23:43:48 +00:00
}
}
}
children ( ) ;
}
}
function generic_bottle_cap (
wall , texture , height ,
thread_od , tolerance ,
2021-08-24 03:03:25 +00:00
neck_od , flank_angle , pitch ,
2021-05-09 23:43:48 +00:00
anchor , spin , orient
) = no_function ( "generic_bottle_cap" ) ;
2021-06-20 04:33:29 +00:00
// Module: bottle_adapter_neck_to_cap()
2021-05-09 23:43:48 +00:00
// Usage:
2021-06-27 03:59:33 +00:00
// bottle_adapter_neck_to_cap(wall, [texture]);
2021-05-09 23:43:48 +00:00
// Description:
// Creates a threaded neck to cap adapter
// Arguments:
// wall = Thickness of wall between neck and cap when d=0. Leave undefined to have the outside of the tube go from the OD of the neck support ring to the OD of the cap. Default: undef
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
// cap_wall = Wall thickness of the cap in mm.
// cap_h = Interior height of the cap in mm.
// cap_thread_od = Outer diameter of cap threads in mm.
// tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius.
// cap_neck_od = Inner diameter of the cap threads.
// cap_neck_id = Inner diameter of the hole through the cap.
// cap_thread_taper = Angle of taper on threads.
// cap_thread_pitch = Thread pitch in mm
// neck_d = Outer diameter of neck w/o threads
// neck_id = Inner diameter of neck
// neck_thread_od = 27.2
// neck_h = Height of neck down to support ring
// neck_thread_pitch = Thread pitch in mm.
// neck_support_od = Outer diameter of neck support ring. Leave undefined to set equal to OD of cap. Set to 0 for no ring. Default: undef
// d = Distance between bottom of neck and top of cap
// taper_lead_in = Length to leave straight before tapering on tube between neck and cap if exists.
// Examples:
2021-06-20 04:33:29 +00:00
// bottle_adapter_neck_to_cap();
module bottle_adapter_neck_to_cap (
2021-05-09 23:43:48 +00:00
wall ,
texture = "none" ,
cap_wall = 2 ,
cap_h = 11.2 ,
cap_thread_od = 28.58 ,
tolerance = . 2 ,
cap_neck_od = 25.5 ,
cap_neck_id ,
cap_thread_taper = 15 ,
cap_thread_pitch = 4 ,
neck_d = 25 ,
neck_id = 21.4 ,
neck_thread_od = 27.2 ,
neck_h = 17 ,
neck_thread_pitch = 3.2 ,
neck_support_od ,
d = 0 ,
taper_lead_in = 0
) {
neck_support_od = ( neck_support_od = = undef || ( d = = 0 && neck_support_od < cap_thread_od + 2 * tolerance ) ) ? cap_thread_od + 2 * ( cap_wall + tolerance ) : neck_support_od ;
cap_neck_id = ( cap_neck_id = = undef ) ? neck_id : cap_neck_id ;
wall = ( wall = = undef ) ? neck_support_od + neck_d + cap_thread_od + neck_id : wall ;
$fn = segs ( 33 / 2 ) ;
wallt1 = min ( wall , ( max ( neck_support_od , neck_d ) - neck_id ) / 2 ) ;
wallt2 = min ( wall , ( cap_thread_od + 2 * ( cap_wall + tolerance ) - cap_neck_id ) / 2 ) ;
difference ( ) {
union ( ) {
up ( d / 2 ) {
generic_bottle_neck ( neck_d = neck_d ,
id = neck_id ,
thread_od = neck_thread_od ,
height = neck_h ,
support_d = neck_support_od ,
pitch = neck_thread_pitch ,
round_supp = ( ( wallt1 < ( neck_support_od - neck_id ) / 2 ) && ( d > 0 || neck_support_od > ( cap_thread_od + 2 * ( cap_wall + tolerance ) ) ) ) ,
wall = ( d > 0 ) ? wallt1 : min ( wallt1 , ( ( cap_thread_od + 2 * ( cap_wall + tolerance ) - neck_id ) / 2 ) )
) ;
}
if ( d ! = 0 ) {
rotate_extrude ( ) {
polygon ( points = [
[ 0 , d / 2 ] ,
[ neck_id / 2 + wallt1 , d / 2 ] ,
[ neck_id / 2 + wallt1 , d / 2 - taper_lead_in ] ,
[ cap_neck_id / 2 + wallt2 , taper_lead_in - d / 2 ] ,
[ cap_neck_id / 2 + wallt2 , - d / 2 ] ,
[ 0 , - d / 2 ]
] ) ;
}
}
down ( d / 2 ) {
generic_bottle_cap ( wall = cap_wall ,
texture = texture ,
height = cap_h ,
thread_od = cap_thread_od ,
tolerance = tolerance ,
neck_od = cap_neck_od ,
2021-08-24 03:03:25 +00:00
flank_angle = cap_thread_taper ,
2021-05-09 23:43:48 +00:00
orient = DOWN ,
pitch = cap_thread_pitch
) ;
}
}
rotate_extrude ( ) {
polygon ( points = [
[ 0 , d / 2 + 0.1 ] ,
[ neck_id / 2 , d / 2 ] ,
[ neck_id / 2 , d / 2 - taper_lead_in ] ,
[ cap_neck_id / 2 , taper_lead_in - d / 2 ] ,
[ cap_neck_id / 2 , - d / 2 - cap_wall ] ,
[ 0 , - d / 2 - cap_wall - 0.1 ]
] ) ;
}
}
}
2021-06-20 04:33:29 +00:00
function bottle_adapter_neck_to_cap (
2021-05-09 23:43:48 +00:00
wall , texture , cap_wall , cap_h , cap_thread_od ,
tolerance , cap_neck_od , cap_neck_id , cap_thread_taper ,
cap_thread_pitch , neck_d , neck_id , neck_thread_od ,
neck_h , neck_thread_pitch , neck_support_od , d , taper_lead_in
2021-06-20 04:33:29 +00:00
) = no_fuction ( "bottle_adapter_neck_to_cap" ) ;
2021-05-09 23:43:48 +00:00
2021-06-20 04:33:29 +00:00
// Module: bottle_adapter_cap_to_cap()
2021-05-09 23:43:48 +00:00
// Usage:
2021-06-27 03:59:33 +00:00
// bottle_adapter_cap_to_cap(wall, [texture]);
2021-05-09 23:43:48 +00:00
// Description:
// Creates a threaded cap to cap adapter.
// Arguments:
// wall = Wall thickness in mm.
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
// cap_h1 = Interior height of top cap.
// cap_thread_od1 = Outer diameter of threads on top cap.
// tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius.
// cap_neck_od1 = Inner diameter of threads on top cap.
// cap_thread_pitch1 = Thread pitch of top cap in mm.
// cap_h2 = Interior height of bottom cap. Leave undefined to duplicate cap_h1.
// cap_thread_od2 = Outer diameter of threads on bottom cap. Leave undefined to duplicate capThread1.
// cap_neck_od2 = Inner diameter of threads on top cap. Leave undefined to duplicate cap_neck_od1.
// cap_thread_pitch2 = Thread pitch of bottom cap in mm. Leave undefinced to duplicate cap_thread_pitch1.
// d = Distance between caps.
// neck_id1 = Inner diameter of cutout in top cap.
// neck_id2 = Inner diameter of cutout in bottom cap.
// taper_lead_in = Length to leave straight before tapering on tube between caps if exists.
// Examples:
2021-06-20 04:33:29 +00:00
// bottle_adapter_cap_to_cap();
module bottle_adapter_cap_to_cap (
2021-05-09 23:43:48 +00:00
wall = 2 ,
texture = "none" ,
cap_h1 = 11.2 ,
cap_thread_od1 = 28.58 ,
tolerance = . 2 ,
cap_neck_od1 = 25.5 ,
cap_thread_pitch1 = 4 ,
cap_h2 ,
cap_thread_od2 ,
cap_neck_od2 ,
cap_thread_pitch2 ,
d = 0 ,
neck_id1 , neck_id2 ,
taper_lead_in = 0
) {
cap_h2 = ( cap_h2 = = undef ) ? cap_h1 : cap_h2 ;
cap_thread_od2 = ( cap_thread_od2 = = undef ) ? cap_thread_od1 : cap_thread_od2 ;
cap_neck_od2 = ( cap_neck_od2 = = undef ) ? cap_neck_od1 : cap_neck_od2 ;
cap_thread_pitch2 = ( cap_thread_pitch2 = = undef ) ? cap_thread_pitch1 : cap_thread_pitch2 ;
neck_id2 = ( neck_id2 = = undef && neck_id1 ! = undef ) ? neck_id1 : neck_id2 ;
taper_lead_in = ( d >= taper_lead_in * 2 ) ? taper_lead_in : d / 2 ;
$fn = segs ( 33 / 2 ) ;
difference ( ) {
union ( ) {
up ( d / 2 ) {
generic_bottle_cap (
orient = UP ,
wall = wall ,
texture = texture ,
height = cap_h1 ,
thread_od = cap_thread_od1 ,
tolerance = tolerance ,
neck_od = cap_neck_od1 ,
pitch = cap_thread_pitch1
) ;
}
if ( d ! = 0 ) {
rotate_extrude ( ) {
polygon ( points = [
[ 0 , d / 2 ] ,
[ cap_thread_od1 / 2 + ( wall + tolerance ) , d / 2 ] ,
[ cap_thread_od1 / 2 + ( wall + tolerance ) , d / 2 - taper_lead_in ] ,
[ cap_thread_od2 / 2 + ( wall + tolerance ) , taper_lead_in - d / 2 ] ,
[ cap_thread_od2 / 2 + ( wall + tolerance ) , - d / 2 ] ,
[ 0 , - d / 2 ]
] ) ;
}
}
down ( d / 2 ) {
generic_bottle_cap (
orient = DOWN ,
wall = wall ,
texture = texture ,
height = cap_h2 ,
thread_od = cap_thread_od2 ,
tolerance = tolerance ,
neck_od = cap_neck_od2 ,
pitch = cap_thread_pitch2
) ;
}
}
if ( neck_id1 ! = undef || neck_id2 ! = undef ) {
neck_id1 = ( neck_id1 = = undef ) ? neck_id2 : neck_id1 ;
neck_id2 = ( neck_id2 = = undef ) ? neck_id1 : neck_id2 ;
rotate_extrude ( ) {
polygon ( points = [
[ 0 , wall + d / 2 + 0.1 ] ,
[ neck_id1 / 2 , wall + d / 2 ] ,
[ neck_id1 / 2 , wall + d / 2 - taper_lead_in ] ,
[ neck_id2 / 2 , taper_lead_in - d / 2 - wall ] ,
[ neck_id2 / 2 , - d / 2 - wall ] ,
[ 0 , - d / 2 - wall - 0.1 ]
] ) ;
}
}
}
}
2021-06-20 04:33:29 +00:00
function bottle_adapter_cap_to_cap (
2021-05-09 23:43:48 +00:00
wall , texture , cap_h1 , cap_thread_od1 , tolerance ,
cap_neck_od1 , cap_thread_pitch1 , cap_h2 , cap_thread_od2 ,
cap_neck_od2 , cap_thread_pitch2 , d , neck_id1 , neck_id2 , taper_lead_in
2021-06-20 04:33:29 +00:00
) = no_function ( "bottle_adapter_cap_to_cap" ) ;
2021-05-09 23:43:48 +00:00
2021-06-20 04:33:29 +00:00
// Module: bottle_adapter_neck_to_neck()
2021-05-09 23:43:48 +00:00
// Usage:
2021-06-20 04:33:29 +00:00
// bottle_adapter_neck_to_neck();
2021-05-09 23:43:48 +00:00
// Description:
// Creates a threaded neck to neck adapter.
// Arguments:
// d = Distance between bottoms of necks
// neck_od1 = Outer diameter of top neck w/o threads
// neck_id1 = Inner diameter of top neck
// thread_od1 = Outer diameter of threads on top neck
// height1 = Height of top neck above support ring.
// support_od1 = Outer diameter of the support ring on the top neck. Set to 0 for no ring.
// thread_pitch1 = Thread pitch of top neck.
// neck_od2 = Outer diameter of bottom neck w/o threads. Leave undefined to duplicate neck_od1
// neck_id2 = Inner diameter of bottom neck. Leave undefined to duplicate neck_id1
// thread_od2 = Outer diameter of threads on bottom neck. Leave undefined to duplicate thread_od1
// height2 = Height of bottom neck above support ring. Leave undefined to duplicate height1
// support_od2 = Outer diameter of the support ring on bottom neck. Set to 0 for no ring. Leave undefined to duplicate support_od1
// pitch2 = Thread pitch of bottom neck. Leave undefined to duplicate thread_pitch1
// taper_lead_in = Length to leave straight before tapering on tube between necks if exists.
// wall = Thickness of tube wall between necks. Leave undefined to match outer diameters with the neckODs/supportODs.
// Examples:
2021-06-20 04:33:29 +00:00
// bottle_adapter_neck_to_neck();
module bottle_adapter_neck_to_neck (
2021-05-09 23:43:48 +00:00
d = 0 ,
neck_od1 = 25 ,
neck_id1 = 21.4 ,
thread_od1 = 27.2 ,
height1 = 17 ,
support_od1 = 33.0 ,
thread_pitch1 = 3.2 ,
neck_od2 , neck_id2 ,
thread_od2 , height2 ,
support_od2 , pitch2 ,
taper_lead_in = 0 , wall
) {
neck_od2 = ( neck_od2 = = undef ) ? neck_od1 : neck_od2 ;
neck_id2 = ( neck_id2 = = undef ) ? neck_id1 : neck_id2 ;
thread_od2 = ( thread_od2 = = undef ) ? thread_od1 : thread_od2 ;
height2 = ( height2 = = undef ) ? height1 : height2 ;
support_od2 = ( support_od2 = = undef ) ? support_od1 : support_od2 ;
pitch2 = ( pitch2 = = undef ) ? thread_pitch1 : pitch2 ;
wall = ( wall = = undef ) ? support_od1 + support_od2 + neck_id1 + neck_id2 : wall ;
supprtOD2 = ( d = = 0 && support_od2 ! = 0 ) ? max ( neck_od1 , support_od2 ) : support_od2 ;
supprtOD1 = ( d = = 0 && support_od1 ! = 0 ) ? max ( neck_od2 , support_od1 ) : support_od1 ;
$fn = segs ( 33 / 2 ) ;
wallt1 = min ( wall , ( max ( supprtOD1 , neck_od1 ) - neck_id1 ) / 2 ) ;
wallt2 = min ( wall , ( max ( supprtOD2 , neck_od2 ) - neck_id2 ) / 2 ) ;
taper_lead_in = ( d >= taper_lead_in * 2 ) ? taper_lead_in : d / 2 ;
difference ( ) {
union ( ) {
up ( d / 2 ) {
generic_bottle_neck ( orient = UP ,
neck_d = neck_od1 ,
id = neck_id1 ,
thread_od = thread_od1 ,
height = height1 ,
support_d = supprtOD1 ,
pitch = thread_pitch1 ,
round_supp = ( ( wallt1 < ( supprtOD1 - neck_id1 ) / 2 ) || ( support_od1 > max ( neck_od2 , support_od2 ) && d = = 0 ) ) ,
wall = ( d > 0 ) ? wallt1 : min ( wallt1 , ( ( max ( neck_od2 , support_od2 ) ) - neck_id1 ) / 2 )
) ;
}
if ( d ! = 0 ) {
rotate_extrude ( ) {
polygon ( points = [
[ 0 , d / 2 ] ,
[ neck_id1 / 2 + wallt1 , d / 2 ] ,
[ neck_id1 / 2 + wallt1 , d / 2 - taper_lead_in ] ,
[ neck_id2 / 2 + wallt2 , taper_lead_in - d / 2 ] ,
[ neck_id2 / 2 + wallt2 , - d / 2 ] ,
[ 0 , - d / 2 ]
] ) ;
}
}
down ( d / 2 ) {
generic_bottle_neck ( orient = DOWN ,
neck_d = neck_od2 ,
id = neck_id2 ,
thread_od = thread_od2 ,
height = height2 ,
support_d = supprtOD2 ,
pitch = pitch2 ,
round_supp = ( ( wallt2 < ( supprtOD2 - neck_id2 ) / 2 ) || ( support_od2 > max ( neck_od1 , support_od1 ) && d = = 0 ) ) ,
wall = ( d > 0 ) ? wallt2 : min ( wallt2 , ( ( max ( neck_od1 , support_od1 ) ) - neck_id2 ) / 2 )
) ;
}
}
if ( neck_id1 ! = undef || neck_id2 ! = undef ) {
neck_id1 = ( neck_id1 = = undef ) ? neck_id2 : neck_id1 ;
neck_id2 = ( neck_id2 = = undef ) ? neck_id1 : neck_id2 ;
rotate_extrude ( ) {
polygon ( points = [
[ 0 , d / 2 ] ,
[ neck_id1 / 2 , d / 2 ] ,
[ neck_id1 / 2 , d / 2 - taper_lead_in ] ,
[ neck_id2 / 2 , taper_lead_in - d / 2 ] ,
[ neck_id2 / 2 , - d / 2 ] ,
[ 0 , - d / 2 ]
] ) ;
}
}
}
}
2021-06-20 04:33:29 +00:00
function bottle_adapter_neck_to_neck (
2021-05-09 23:43:48 +00:00
d , neck_od1 , neck_id1 , thread_od1 , height1 ,
support_od1 , thread_pitch1 , neck_od2 , neck_id2 ,
thread_od2 , height2 , support_od2 ,
pitch2 , taper_lead_in , wall
2021-06-20 04:33:29 +00:00
) = no_fuction ( "bottle_adapter_neck_to_neck" ) ;
2021-05-09 23:43:48 +00:00
2021-08-24 22:00:36 +00:00
// Section: SPI Bottle Threading
// Module: sp_neck()
// Usage:
// sp_neck(diam, type, wall|id, [style], [bead], [anchor], [spin], [orient])
// Description:
// Make a SPI (Society of Plastics Industry) threaded bottle neck. You must
// supply the nominal outer diameter of the threads and the thread type, one of
// 400, 410 and 415. The 400 type neck has 360 degrees of thread, the 410
// neck has 540 degrees of thread, and the 415 neck has 720 degrees of thread.
// You can also choose between the L style thread, which is symmetric and
// the M style thread, which is an asymmetric buttress thread. You can
// specify the wall thickness (measured from the base of the threads) or
// the inner diameter, and you can specify an optional bead at the base of the threads.
// Arguments:
// diam = nominal outer diameter of threads
// type = thread type, one of 400, 410 and 415
// wall = wall thickness
// ---
// id = inner diameter
// style = Either "L" or "M" to specify the thread style. Default: "L"
// bead = if true apply a bad to the neck. Default: false
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// Examples:
// sp_neck(48,400,2);
// sp_neck(48,400,2,bead=true);
// sp_neck(22,410,2);
// sp_neck(22,410,2,bead=true);
// sp_neck(28,415,id=20,style="M");
// sp_neck(13,415,wall=1,style="M",bead=true);
// Thread specs from https://www.isbt.com/threadspecs-downloads.asp
_sp_specs = [
[ 400 , //diam T I H S tpi
[ [ 18 , [ 17.68 , 8.26 , 9.42 , 0.94 , 8 ] ] ,
[ 20 , [ 19.69 , 10.26 , 9.42 , 0.94 , 8 ] ] ,
[ 22 , [ 21.69 , 12.27 , 9.42 , 0.94 , 8 ] ] ,
[ 24 , [ 23.67 , 13.11 , 10.16 , 1.17 , 8 ] ] ,
[ 28 , [ 27.38 , 15.60 , 10.16 , 1.17 , 6 ] ] ,
[ 30 , [ 28.37 , 16.59 , 10.24 , 1.17 , 6 ] ] ,
[ 33 , [ 31.83 , 20.09 , 10.24 , 1.17 , 6 ] ] ,
[ 35 , [ 34.34 , 22.23 , 10.24 , 1.17 , 6 ] ] ,
[ 38 , [ 37.19 , 25.07 , 10.24 , 1.17 , 6 ] ] ,
[ 40 , [ 39.75 , 27.71 , 10.24 , 1.17 , 6 ] ] ,
[ 43 , [ 41.63 , 29.59 , 10.24 , 1.17 , 6 ] ] ,
[ 45 , [ 43.82 , 31.78 , 10.24 , 1.17 , 6 ] ] ,
[ 48 , [ 47.12 , 35.08 , 10.24 , 1.17 , 6 ] ] ,
[ 51 , [ 49.56 , 37.57 , 10.36 , 1.17 , 6 ] ] ,
[ 53 , [ 52.07 , 40.08 , 10.36 , 1.17 , 6 ] ] ,
[ 58 , [ 56.06 , 44.07 , 10.36 , 1.17 , 6 ] ] ,
[ 60 , [ 59.06 , 47.07 , 10.36 , 1.17 , 6 ] ] ,
[ 63 , [ 62.08 , 50.09 , 10.36 , 1.17 , 6 ] ] ,
[ 66 , [ 65.07 , 53.09 , 10.36 , 1.17 , 6 ] ] ,
[ 70 , [ 69.06 , 57.07 , 10.36 , 1.17 , 6 ] ] ,
[ 75 , [ 73.56 , 61.57 , 10.36 , 1.17 , 6 ] ] ,
[ 77 , [ 76.66 , 64.67 , 12.37 , 1.52 , 6 ] ] ,
[ 83 , [ 82.58 , 69.93 , 12.37 , 1.52 , 5 ] ] ,
[ 89 , [ 88.75 , 74.12 , 13.59 , 1.52 , 5 ] ] ,
[ 100 , [ 99.57 , 84.94 , 15.16 , 1.52 , 5 ] ] ,
[ 110 , [ 109.58 , 94.92 , 15.16 , 1.52 , 5 ] ] ,
[ 120 , [ 119.56 , 104.93 , 17.40 , 1.52 , 5 ] ] ,
] ] ,
[ 410 , //diam T I H S tpi L W
[ [ 18 , [ 17.68 , 8.26 , 13.28 , 0.94 , 8 , 9.17 , 2.13 ] ] ,
[ 20 , [ 19.59 , 10.26 , 14.07 , 0.94 , 8 , 9.17 , 2.13 ] ] ,
[ 22 , [ 21.69 , 12.27 , 14.86 , 0.94 , 8 , 9.55 , 2.13 ] ] ,
[ 24 , [ 23.67 , 13.11 , 16.41 , 1.17 , 8 , 11.10 , 2.13 ] ] ,
[ 28 , [ 27.38 , 15.60 , 17.98 , 1.17 , 6 , 11.76 , 2.39 ] ] ,
] ] ,
[ 415 , //diam T I H S tpi L W
[ [ 13 , [ 12.90 , 5.54 , 11.48 , 0.94 , 12 , 7.77 , 1.14 ] ] ,
[ 15 , [ 14.61 , 6.55 , 14.15 , 0.94 , 12 , 8.84 , 1.14 ] ] ,
[ 18 , [ 17.68 , 8.26 , 15.67 , 0.94 , 8 , 10.90 , 2.13 ] ] ,
[ 20 , [ 19.69 , 10.26 , 18.85 , 0.94 , 8 , 11.58 , 2.13 ] ] ,
[ 22 , [ 21.69 , 12.27 , 21.26 , 0.94 , 8 , 13.87 , 2.13 ] ] ,
[ 24 , [ 23.67 , 13.11 , 24.31 , 1.17 , 8 , 14.25 , 2.13 ] ] ,
[ 28 , [ 27.38 , 15.60 , 27.48 , 1.17 , 6 , 16.64 , 2.39 ] ] ,
[ 33 , [ 31.83 , 20.09 , 32.36 , 1.17 , 6 , 19.61 , 2.39 ] ] ,
] ]
] ;
_sp_twist = [ [ 400 , 360 ] ,
[ 410 , 540 ] ,
[ 415 , 720 ]
] ;
// profile data: tpi, total width, depth,
_sp_thread_width = [
[ 5 , 3.05 ] ,
[ 6 , 2.39 ] ,
[ 8 , 2.13 ] ,
[ 12 , 1.14 ] , // But note style M is different
] ;
function _sp_thread_profile ( tpi , a , S , style ) =
let (
pitch = 1 / tpi * INCH ,
cL = a * ( 1 - 1 / sqrt ( 3 ) ) ,
cM = ( 1 - tan ( 10 ) ) * a / 2 ,
// SP specified roundings for the thread profile have special case for tpi=12
roundings = style = = "L" && tpi < 12 ? 0.5
: style = = "M" && tpi < 12 ? [ 0.25 , 0.25 , 0.75 , 0.75 ]
: style = = "L" ? [ 0.38 , 0.13 , 0.13 , 0.38 ]
: /* style=="M" */ [ 0.25 , 0.25 , 0.2 , 0.5 ] ,
path = style = = "L"
? round_corners ( [ [ - 1 / 2 * pitch , - a / 2 ] ,
[ - a / 2 , - a / 2 ] ,
[ - cL / 2 , 0 ] ,
[ cL / 2 , 0 ] ,
[ a / 2 , - a / 2 ] ,
[ 1 / 2 * pitch , - a / 2 ] ] , radius = roundings , closed = false , $fn = 24 )
: round_corners (
[ [ - 1 / 2 * pitch , - a / 2 ] ,
[ - a / 2 , - a / 2 ] ,
[ - cM , 0 ] ,
[ 0 , 0 ] ,
[ a / 2 , - a / 2 ] ,
[ 1 / 2 * pitch , - a / 2 ] ] , radius = roundings , closed = false , $fn = 24 )
)
// Shift so that the profile is S mm from the right end to create proper length S top gap
select ( right ( - a / 2 + 1 / 2 - S , p = path ) , 1 , - 2 ) / pitch ;
function sp_neck ( diam , type , wall , id , style = "L" , bead = false , anchor , spin , orient ) = no_function ( "sp_neck" ) ;
module sp_neck ( diam , type , wall , id , style = "L" , bead = false , anchor , spin , orient )
{
assert ( num_defined ( [ wall , id ] ) = = 1 , "Must define exactly one of wall and id" ) ;
table = struct_val ( _sp_specs , type ) ;
dum1 = assert ( is_def ( table ) , "Unknown SP closure type. Type must be one of 400, 410, or 415" ) ;
entry = struct_val ( table , diam ) ;
dum2 = assert ( is_def ( entry ) , str ( "Unknown closure nominal diameter. Allowed diameters for SP" , type , ": " , struct_keys ( table ) ) )
assert ( style = = "L" || style = = "M" , "style must be \"L\" or \"M\"" ) ;
T = entry [ 0 ] ;
I = entry [ 1 ] ;
H = entry [ 2 ] ;
S = entry [ 3 ] ;
tpi = entry [ 4 ] ;
a = ( style = = "M" && tpi = = 12 ) ? 1.3 : struct_val ( _sp_thread_width , tpi ) ;
twist = struct_val ( _sp_twist , type ) ;
profile = _sp_thread_profile ( tpi , a , S , style ) ;
depth = a / 2 ;
higlen = 2 * a ;
higang = higlen / ( ( T - 2 * depth ) * PI ) * 360 ;
beadmax = type = = 400 ? ( T / 2 - depth ) + depth * 1.25
: diam < = 15 ? ( T - . 15 ) / 2 : ( T - . 05 ) / 2 ;
W = type = = 400 ? a * 1.5 // arbitrary decision for type 400
: entry [ 6 ] ; // specified width for 410 and 415
beadpts = [
[ 0 , - W / 2 ] ,
each arc ( 16 , points = [ [ T / 2 - depth , - W / 2 ] ,
[ beadmax , 0 ] ,
[ T / 2 - depth , W / 2 ] ] ) ,
[ 0 , W / 2 ]
] ;
isect400 = [ for ( seg = pair ( beadpts ) ) let ( segisect = line_segment_intersection ( [ [ T / 2 , 0 ] , [ T / 2 , 1 ] ] , seg ) ) if ( is_def ( segisect ) ) segisect . y ] ;
extra_bot = type = = 400 && bead ? - min ( subindex ( beadpts , 1 ) ) + max ( isect400 ) : 0 ;
bead_shift = type = = 400 ? H + max ( isect400 ) : entry [ 5 ] + W / 2 ; // entry[5] is L
attachable ( anchor , spin , orient , r = bead ? beadmax : T / 2 , l = H + extra_bot ) {
up ( ( H + extra_bot ) / 2 ) {
difference ( ) {
union ( ) {
thread_helix ( d = T - . 01 , profile = profile , pitch = INCH / tpi , twist = twist + 2 * higang , higbee = higlen , anchor = TOP ) ;
cylinder ( d = T - depth * 2 , l = H , anchor = TOP ) ;
if ( bead )
down ( bead_shift )
rotate_extrude ( )
polygon ( beadpts ) ;
}
up ( . 5 ) cyl ( d = is_def ( id ) ? id : T - a - 2 * wall , l = H - extra_bot + 1 , anchor = TOP ) ;
}
}
children ( ) ;
}
}
// Function: sp_diameter()
// Usage:
// true_diam = sp_diameter(diam,type)
// Description:
// Returns the actual base diameter (root of the threads) for a SPI plastic bottle neck given the nominal diameter and type number (400, 410, 415).
function sp_diameter ( diam , type ) =
let (
table = struct_val ( _sp_specs , type )
)
assert ( is_def ( table ) , "Unknown SP closure type. Type must be one of 400, 410, or 415" )
let (
entry = struct_val ( table , diam )
)
assert ( is_def ( entry ) , str ( "Unknown closure nominal diameter. Allowed diameters for SP" , type , ": " , struct_keys ( table ) ) )
entry [ 0 ] ;
2020-05-30 02:04:34 +00:00
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap