add attachable to bottlecaps & mutators

This commit is contained in:
Adrian Mariano 2023-04-27 22:15:10 -04:00
parent 25aef90fc7
commit 1bee8c96f9
3 changed files with 418 additions and 352 deletions

View file

@ -443,15 +443,17 @@ module generic_bottle_neck(
diamMagMult = neck_d / 26.19; diamMagMult = neck_d / 26.19;
heightMagMult = height / 17.00; heightMagMult = height / 17.00;
assert(all_nonnegative([support_d]),"support_d must be a nonnegative number");
sup_r = 0.30 * (heightMagMult > 1 ? heightMagMult : 1); 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_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 : support_rad = (wall == undef || !round_supp) ? support_r :
min(support_r, floor((supp_d - (inner_d + 2 * wall)) * 5000) / 10000); 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 //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); support_width = max(heightMagMult,1) * sign(support_d);
roundover = 0.58 * diamMagMult; roundover = 0.58 * diamMagMult;
lip_roundover_r = (roundover > (neck_d - inner_d) / 2) ? 0 : roundover; lip_roundover_r = (roundover > (neck_d - inner_d) / 2) ? 0 : roundover;
h = height + support_width; h = height + support_width;
echo(h=h);
threadbase_d = neck_d - 0.8 * diamMagMult; threadbase_d = neck_d - 0.8 * diamMagMult;
$fn = segs(33 / 2); $fn = segs(33 / 2);
@ -459,7 +461,7 @@ module generic_bottle_neck(
anchors = [ anchors = [
named_anchor("support-ring", [0, 0, 0 - h / 2]) named_anchor("support-ring", [0, 0, 0 - h / 2])
]; ];
attachable(anchor, spin, orient, d1 = neck_d, d2 = 0, l = h, anchors = anchors) { attachable(anchor, spin, orient, d = neck_d, l = h, anchors = anchors) {
down(h / 2) { down(h / 2) {
rotate_extrude(convexity = 10) { rotate_extrude(convexity = 10) {
polygon(turtle( polygon(turtle(
@ -555,7 +557,7 @@ module generic_bottle_cap(
wall = 2, wall = 2,
texture = "none", texture = "none",
height = 11.2, height = 11.2,
thread_od = 28.58, thread_depth = 2.34,
tolerance = .2, tolerance = .2,
neck_od = 25.5, neck_od = 25.5,
flank_angle = 15, flank_angle = 15,
@ -565,11 +567,10 @@ module generic_bottle_cap(
orient = UP orient = UP
) { ) {
$fn = segs(33 / 2); $fn = segs(33 / 2);
threadOuterDTol = thread_od + 2 * tolerance; threadOuterDTol = neck_od + 2*(thread_depth - 0.8) + 2 * tolerance; // WTF; Engineered for consistency with old code, but
w = threadOuterDTol + 2 * wall; w = threadOuterDTol + 2 * wall; // no clue why this was chosen
h = height + wall; h = height + wall;
neckOuterDTol = neck_od + 2 * tolerance; neckOuterDTol = neck_od + 2 * tolerance;
threadDepth = (thread_od - neck_od) / 2 + .8;
diamMagMult = (w > 32.58) ? w / 32.58 : 1; diamMagMult = (w > 32.58) ? w / 32.58 : 1;
heightMagMult = (height > 11.2) ? height / 11.2 : 1; heightMagMult = (height > 11.2) ? height / 11.2 : 1;
@ -596,8 +597,8 @@ module generic_bottle_cap(
} }
difference(){ difference(){
up(wall + pitch / 2) { up(wall + pitch / 2) {
thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = thread_depth, flank_angle = flank_angle,
turns = ((height - pitch) / pitch), lead_in = -threadDepth, internal = true, anchor = BOTTOM); turns = ((height - pitch) / pitch), lead_in = -thread_depth, internal = true, anchor = BOTTOM);
} }
} }
} }
@ -626,7 +627,7 @@ function generic_bottle_cap(
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none" // 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_wall = Wall thickness of the cap in mm.
// cap_h = Interior height of the cap in mm. // cap_h = Interior height of the cap in mm.
// cap_thread_od = Outer diameter of cap threads in mm. // cap_thread_depth = Cap thread depth. Default: 2.34
// tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius. // 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_od = Inner diameter of the cap threads.
// cap_neck_id = Inner diameter of the hole through the cap. // cap_neck_id = Inner diameter of the hole through the cap.
@ -640,6 +641,9 @@ function generic_bottle_cap(
// 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 // 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 // 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. // taper_lead_in = Length to leave straight before tapering on tube between neck and cap if exists.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Examples: // Examples:
// bottle_adapter_neck_to_cap(); // bottle_adapter_neck_to_cap();
module bottle_adapter_neck_to_cap( module bottle_adapter_neck_to_cap(
@ -647,7 +651,7 @@ module bottle_adapter_neck_to_cap(
texture = "none", texture = "none",
cap_wall = 2, cap_wall = 2,
cap_h = 11.2, cap_h = 11.2,
cap_thread_od = 28.58, cap_thread_depth = 2.34,
tolerance = .2, tolerance = .2,
cap_neck_od = 25.5, cap_neck_od = 25.5,
cap_neck_id, cap_neck_id,
@ -660,16 +664,24 @@ module bottle_adapter_neck_to_cap(
neck_thread_pitch = 3.2, neck_thread_pitch = 3.2,
neck_support_od, neck_support_od,
d = 0, d = 0,
taper_lead_in = 0 taper_lead_in = 0, anchor, spin,orient
) { ) {
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_od = cap_neck_od + 2*(cap_thread_depth - 0.8) + 2 * tolerance;
cap_neck_id = (cap_neck_id == undef) ? neck_id : cap_neck_id; neck_support_od = (neck_support_od == undef || (d == 0 && neck_support_od < cap_od)) ? cap_od+2*cap_wall
wall = (wall == undef) ? neck_support_od + neck_d + cap_thread_od + neck_id : wall; : neck_support_od;
cap_neck_id = default(cap_neck_id,neck_id);
wall = default(wall, neck_support_od + neck_d + cap_od + neck_id - 2*tolerance);
echo(wall=wall);
$fn = segs(33 / 2); $fn = segs(33 / 2);
wallt1 = min(wall, (max(neck_support_od, neck_d) - neck_id) / 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); wallt2 = min(wall, (cap_od + 2 * cap_wall - cap_neck_id) / 2);
top_h = neck_h + max(1,neck_h/17)*sign(neck_support_od);
echo(top_h=top_h);
bot_h = cap_h + cap_wall;
attachable(anchor=anchor,orient=orient,spin=spin, r=max([neck_id/2+wallt1, cap_neck_id/2+wallt2, neck_support_od/2]), h=top_h+bot_h+d) {
zmove((bot_h-top_h)/2)
difference(){ difference(){
union(){ union(){
up(d / 2) { up(d / 2) {
@ -680,7 +692,7 @@ module bottle_adapter_neck_to_cap(
support_d = neck_support_od, support_d = neck_support_od,
pitch = neck_thread_pitch, 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)))), 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)) wall = (d > 0) ? wallt1 : min(wallt1, ((cap_od + 2 * (cap_wall) - neck_id) / 2))
); );
} }
if (d != 0) { if (d != 0) {
@ -699,7 +711,7 @@ module bottle_adapter_neck_to_cap(
generic_bottle_cap(wall = cap_wall, generic_bottle_cap(wall = cap_wall,
texture = texture, texture = texture,
height = cap_h, height = cap_h,
thread_od = cap_thread_od, thread_depth = cap_thread_depth,
tolerance = tolerance, tolerance = tolerance,
neck_od = cap_neck_od, neck_od = cap_neck_od,
flank_angle = cap_thread_taper, flank_angle = cap_thread_taper,
@ -719,10 +731,12 @@ module bottle_adapter_neck_to_cap(
]); ]);
} }
} }
children();
}
} }
function bottle_adapter_neck_to_cap( function bottle_adapter_neck_to_cap(
wall, texture, cap_wall, cap_h, cap_thread_od, wall, texture, cap_wall, cap_h, cap_thread_depth1,
tolerance, cap_neck_od, cap_neck_id, cap_thread_taper, tolerance, cap_neck_od, cap_neck_id, cap_thread_taper,
cap_thread_pitch, neck_d, neck_id, neck_thread_od, cap_thread_pitch, neck_d, neck_id, neck_thread_od,
neck_h, neck_thread_pitch, neck_support_od, d, taper_lead_in neck_h, neck_thread_pitch, neck_support_od, d, taper_lead_in
@ -734,53 +748,64 @@ function bottle_adapter_neck_to_cap(
// Topics: Bottles, Threading // Topics: Bottles, Threading
// See Also: bottle_adapter_neck_to_cap(), bottle_adapter_neck_to_neck() // See Also: bottle_adapter_neck_to_cap(), bottle_adapter_neck_to_neck()
// Usage: // Usage:
// bottle_adapter_cap_to_cap(wall, [texture]); // bottle_adapter_cap_to_cap(wall, [texture]) [ATTACHMENTS];
// Description: // Description:
// Creates a threaded cap to cap adapter. // Creates a threaded cap to cap adapter.
// Arguments: // Arguments:
// wall = Wall thickness in mm. // wall = Wall thickness in mm.
// texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none" // texture = The surface texture of the cap. Valid values are "none", "knurled", or "ribbed". Default: "none"
// cap_h1 = Interior height of top cap. // cap_h1 = Interior height of top cap.
// cap_thread_od1 = Outer diameter of threads on top cap. // cap_thread_depth1 = Thread depth on top cap. Default: 2.34
// tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius. // 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_neck_od1 = Inner diameter of threads on top cap.
// cap_thread_pitch1 = Thread pitch of top cap in mm. // cap_thread_pitch1 = Thread pitch of top cap in mm.
// cap_h2 = Interior height of bottom cap. Leave undefined to duplicate cap_h1. // 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_thread_depth2 = Thread depth on bottom cap. Default: same as cap_thread_depth1
// cap_neck_od2 = Inner diameter of threads on top cap. Leave undefined to duplicate cap_neck_od1. // 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. // cap_thread_pitch2 = Thread pitch of bottom cap in mm. Leave undefinced to duplicate cap_thread_pitch1.
// d = Distance between caps. // d = Distance between caps.
// neck_id1 = Inner diameter of cutout in top cap. // neck_id1 = Inner diameter of cutout in top cap.
// neck_id2 = Inner diameter of cutout in bottom 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. // taper_lead_in = Length to leave straight before tapering on tube between caps if exists.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Examples: // Examples:
// bottle_adapter_cap_to_cap(); // bottle_adapter_cap_to_cap();
module bottle_adapter_cap_to_cap( module bottle_adapter_cap_to_cap(
wall = 2, wall = 2,
texture = "none", texture = "none",
cap_h1 = 11.2, cap_h1 = 11.2,
cap_thread_od1 = 28.58, cap_thread_depth1 = 2.34,
tolerance = .2, tolerance = .2,
cap_neck_od1 = 25.5, cap_neck_od1 = 25.5,
cap_thread_pitch1 = 4, cap_thread_pitch1 = 4,
cap_h2, cap_h2,
cap_thread_od2, cap_thread_depth2,
cap_neck_od2, cap_neck_od2,
cap_thread_pitch2, cap_thread_pitch2,
d = 0, d = 0,
neck_id1, neck_id2, neck_id,
taper_lead_in = 0 taper_lead_in = 0, anchor, spin,orient
) { ) {
cap_h2 = (cap_h2 == undef) ? cap_h1 : cap_h2; cap_h2 = default(cap_h2,cap_h1);
cap_thread_od2 = (cap_thread_od2 == undef) ? cap_thread_od1 : cap_thread_od2; cap_thread_depth2 = default(cap_thread_depth2,cap_thread_depth1);
cap_neck_od2 = (cap_neck_od2 == undef) ? cap_neck_od1 : cap_neck_od2; cap_neck_od2 = default(cap_neck_od2,cap_neck_od1);
cap_thread_pitch2 = (cap_thread_pitch2 == undef) ? cap_thread_pitch1 : cap_thread_pitch2; cap_thread_pitch2 = default(cap_thread_pitch2,cap_thread_pitch1);
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; taper_lead_in = (d >= taper_lead_in * 2) ? taper_lead_in : d / 2;
neck_id = min(cap_neck_od1 - cap_thread_depth1, cap_neck_od2-cap_thread_depth2);
top_h = cap_h1+wall;
bot_h = cap_h2+wall;
cap_od1 = cap_neck_od1 + 2*(cap_thread_depth1 - 0.8) + 2 * tolerance; // WTF; Engineered for consistency with old code, but
cap_od2 = cap_neck_od2 + 2*(cap_thread_depth2 - 0.8) + 2 * tolerance; // WTF; Engineered for consistency with old code, but
$fn = segs(33 / 2); $fn = segs(33 / 2);
attachable(anchor=anchor,spin=spin,orient=orient, h=top_h+bot_h+d, d=max(cap_od1,cap_od2)+2*wall){
zmove((bot_h-top_h)/2)
difference(){ difference(){
union(){ union(){
up(d / 2){ up(d / 2){
@ -789,7 +814,7 @@ module bottle_adapter_cap_to_cap(
wall = wall, wall = wall,
texture = texture, texture = texture,
height = cap_h1, height = cap_h1,
thread_od = cap_thread_od1, thread_depth = cap_thread_depth1,
tolerance = tolerance, tolerance = tolerance,
neck_od = cap_neck_od1, neck_od = cap_neck_od1,
pitch = cap_thread_pitch1 pitch = cap_thread_pitch1
@ -799,10 +824,10 @@ module bottle_adapter_cap_to_cap(
rotate_extrude() { rotate_extrude() {
polygon(points = [ polygon(points = [
[0, d / 2], [0, d / 2],
[cap_thread_od1 / 2 + (wall + tolerance), d / 2], [cap_od1 / 2 + wall, d / 2],
[cap_thread_od1 / 2 + (wall + tolerance), d / 2 - taper_lead_in], [cap_od1 / 2 + wall, d / 2 - taper_lead_in],
[cap_thread_od2 / 2 + (wall + tolerance), taper_lead_in - d / 2], [cap_od2 / 2 + wall, taper_lead_in - d / 2],
[cap_thread_od2 / 2 + (wall + tolerance), -d / 2], [cap_od2 / 2 + wall, -d / 2],
[0, -d / 2] [0, -d / 2]
]); ]);
} }
@ -813,28 +838,25 @@ module bottle_adapter_cap_to_cap(
wall = wall, wall = wall,
texture = texture, texture = texture,
height = cap_h2, height = cap_h2,
thread_od = cap_thread_od2, thread_depth = cap_thread_depth2,
tolerance = tolerance, tolerance = tolerance,
neck_od = cap_neck_od2, neck_od = cap_neck_od2,
pitch = cap_thread_pitch2 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() { rotate_extrude() {
polygon(points = [ polygon(points = [
[0, wall + d / 2 + 0.1], [0, wall + d / 2 + 0.1],
[neck_id1 / 2, wall + d / 2], [neck_id / 2, wall + d / 2],
[neck_id1 / 2, wall + d / 2 - taper_lead_in], [neck_id / 2, wall + d / 2 - taper_lead_in],
[neck_id2 / 2, taper_lead_in - d / 2 - wall], [neck_id / 2, taper_lead_in - d / 2 - wall],
[neck_id2 / 2, -d / 2 - wall], [neck_id / 2, -d / 2 - wall],
[0, -d / 2 - wall - 0.1] [0, -d / 2 - wall - 0.1]
]); ]);
} }
} }
children();
} }
} }
@ -850,7 +872,7 @@ function bottle_adapter_cap_to_cap(
// Topics: Bottles, Threading // Topics: Bottles, Threading
// See Also: bottle_adapter_neck_to_cap(), bottle_adapter_cap_to_cap() // See Also: bottle_adapter_neck_to_cap(), bottle_adapter_cap_to_cap()
// Usage: // Usage:
// bottle_adapter_neck_to_neck(...); // bottle_adapter_neck_to_neck(...) [ATTACHMENTS];
// Description: // Description:
// Creates a threaded neck to neck adapter. // Creates a threaded neck to neck adapter.
// Arguments: // Arguments:
@ -870,6 +892,9 @@ function bottle_adapter_cap_to_cap(
// pitch2 = Thread pitch of bottom neck. Leave undefined to duplicate thread_pitch1 // 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. // 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. // wall = Thickness of tube wall between necks. Leave undefined to match outer diameters with the neckODs/supportODs.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Examples: // Examples:
// bottle_adapter_neck_to_neck(); // bottle_adapter_neck_to_neck();
module bottle_adapter_neck_to_neck( module bottle_adapter_neck_to_neck(
@ -883,9 +908,8 @@ module bottle_adapter_neck_to_neck(
neck_od2, neck_id2, neck_od2, neck_id2,
thread_od2, height2, thread_od2, height2,
support_od2, pitch2, support_od2, pitch2,
taper_lead_in = 0, wall taper_lead_in = 0, wall, anchor, spin, orient
) { ) {
no_children($children);
neck_od2 = (neck_od2 == undef) ? neck_od1 : neck_od2; neck_od2 = (neck_od2 == undef) ? neck_od1 : neck_od2;
neck_id2 = (neck_id2 == undef) ? neck_id1 : neck_id2; neck_id2 = (neck_id2 == undef) ? neck_id1 : neck_id2;
thread_od2 = (thread_od2 == undef) ? thread_od1 : thread_od2; thread_od2 = (thread_od2 == undef) ? thread_od1 : thread_od2;
@ -903,6 +927,11 @@ module bottle_adapter_neck_to_neck(
taper_lead_in = (d >= taper_lead_in * 2) ? taper_lead_in : d / 2; taper_lead_in = (d >= taper_lead_in * 2) ? taper_lead_in : d / 2;
top_h = height1 + max(1,height1/17)*sign(support_od1);
bot_h = height2 + max(1,height2/17)*sign(support_od2);
attachable(anchor=anchor,orient=orient,spin=spin, h=top_h+bot_h+d, d=max(neck_od1,neck_od2)){
zmove((bot_h-top_h)/2)
difference(){ difference(){
union(){ union(){
up(d / 2){ up(d / 2){
@ -958,6 +987,8 @@ module bottle_adapter_neck_to_neck(
} }
} }
} }
children();
}
} }
function bottle_adapter_neck_to_neck( function bottle_adapter_neck_to_neck(

View file

@ -85,6 +85,8 @@ module bounding_box(excess=0, planar=false) {
} }
} }
req_children($children);
attachable(){
if(planar) { if(planar) {
offset(excess-1/2) _oversize_bbox() children(); offset(excess-1/2) _oversize_bbox() children();
} else { } else {
@ -95,6 +97,8 @@ module bounding_box(excess=0, planar=false) {
_shrink_cube() _oversize_bbox() children(); _shrink_cube() _oversize_bbox() children();
} }
} }
union();
}
} }
@ -137,10 +141,12 @@ module bounding_box(excess=0, planar=false) {
// } // }
module chain_hull() module chain_hull()
{ {
union() { req_children($children);
attachable(){
if ($children == 1) { if ($children == 1) {
children(); children();
} else if ($children > 1) { }
else {
for (i =[1:1:$children-1]) { for (i =[1:1:$children-1]) {
$idx = i; $idx = i;
hull() { hull() {
@ -149,6 +155,7 @@ module chain_hull()
} }
} }
} }
union();
} }
} }
@ -203,6 +210,7 @@ module chain_hull()
// move_copies([[-3.5,1.5],[0.0,3.0],[3.5,1.5]]) // move_copies([[-3.5,1.5],[0.0,3.0],[3.5,1.5]])
// circle(r=1.5); // circle(r=1.5);
module path_extrude2d(path, caps=false, closed=false, s, convexity=10) { module path_extrude2d(path, caps=false, closed=false, s, convexity=10) {
req_children($children);
extra_ang = 0.1; // Extra angle for overlap of joints extra_ang = 0.1; // Extra angle for overlap of joints
check = check =
assert(caps==false || closed==false, "Cannot have caps on a closed extrusion") assert(caps==false || closed==false, "Cannot have caps on a closed extrusion")
@ -213,6 +221,8 @@ module path_extrude2d(path, caps=false, closed=false, s, convexity=10) {
norm(b[1]-b[0]); norm(b[1]-b[0]);
check2 = assert(is_finite(s)); check2 = assert(is_finite(s));
L = len(path); L = len(path);
attachable(){
union(){
for (i = [0:1:L-(closed?1:2)]) { for (i = [0:1:L-(closed?1:2)]) {
seg = select(path, i, i+1); seg = select(path, i, i+1);
segv = seg[1] - seg[0]; segv = seg[1] - seg[0];
@ -266,6 +276,9 @@ module path_extrude2d(path, caps=false, closed=false, s, convexity=10) {
rotate_extrude(angle=180) rotate_extrude(angle=180)
right_half(planar=true) children(); right_half(planar=true) children();
} }
}
union();
}
} }
@ -298,6 +311,7 @@ module path_extrude2d(path, caps=false, closed=false, s, convexity=10) {
// cylindrical_extrude(or=40, ir=35, orient=BACK) // cylindrical_extrude(or=40, ir=35, orient=BACK)
// text(text="Hello World!", size=10, halign="center", valign="center"); // text(text="Hello World!", size=10, halign="center", valign="center");
module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orient=UP) { module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orient=UP) {
req_children($children);
check1 = assert(is_num(size) || is_vector(size,2)); check1 = assert(is_num(size) || is_vector(size,2));
size = is_num(size)? [size,size] : size; size = is_num(size)? [size,size] : size;
ir = get_radius(r=ir,d=id); ir = get_radius(r=ir,d=id);
@ -310,6 +324,7 @@ module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orie
sides = segs(or); sides = segs(or);
step = circumf / sides; step = circumf / sides;
steps = ceil(width / step); steps = ceil(width / step);
attachable() {
rot(from=UP, to=orient) rot(spin) { rot(from=UP, to=orient) rot(spin) {
for (i=[0:1:steps-2]) { for (i=[0:1:steps-2]) {
x = (i+0.5-steps/2) * step; x = (i+0.5-steps/2) * step;
@ -328,6 +343,8 @@ module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orie
} }
} }
} }
union();
}
} }
@ -353,6 +370,7 @@ module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orie
// xcopies(3) circle(3, $fn=32); // xcopies(3) circle(3, $fn=32);
// } // }
module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) { module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) {
req_children($children);
check = check =
assert(is_vector(pt1),"First point must be a vector") assert(is_vector(pt1),"First point must be a vector")
assert(is_vector(pt2),"Second point must be a vector"); assert(is_vector(pt2),"Second point must be a vector");
@ -391,6 +409,7 @@ module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) {
// path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ]; // path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ];
// path_extrude(path) circle(r=10, $fn=6); // path_extrude(path) circle(r=10, $fn=6);
module path_extrude(path, convexity=10, clipsize=100) { module path_extrude(path, convexity=10, clipsize=100) {
req_children($children);
rotmats = cumprod([ rotmats = cumprod([
for (i = idx(path,e=-2)) let( for (i = idx(path,e=-2)) let(
vec1 = i==0? UP : unit(path[i]-path[i-1], UP), vec1 = i==0? UP : unit(path[i]-path[i-1], UP),
@ -401,6 +420,7 @@ module path_extrude(path, convexity=10, clipsize=100) {
interp = rot_resample(rotmats,n=2,method="count"); interp = rot_resample(rotmats,n=2,method="count");
epsilon = 0.0001; // Make segments ever so slightly too long so they overlap. epsilon = 0.0001; // Make segments ever so slightly too long so they overlap.
ptcount = len(path); ptcount = len(path);
attachable(){
for (i = [0:1:ptcount-2]) { for (i = [0:1:ptcount-2]) {
pt1 = path[i]; pt1 = path[i];
pt2 = path[i+1]; pt2 = path[i+1];
@ -428,6 +448,8 @@ module path_extrude(path, convexity=10, clipsize=100) {
} }
} }
} }
union();
}
} }
@ -459,6 +481,8 @@ module path_extrude(path, convexity=10, clipsize=100) {
// sphere(r=10); // sphere(r=10);
// } // }
module minkowski_difference(planar=false) { module minkowski_difference(planar=false) {
req_children($children);
attachable(){
difference() { difference() {
bounding_box(excess=0, planar=planar) children(0); bounding_box(excess=0, planar=planar) children(0);
render(convexity=20) { render(convexity=20) {
@ -471,6 +495,8 @@ module minkowski_difference(planar=false) {
} }
} }
} }
union();
}
} }
@ -491,7 +517,9 @@ module minkowski_difference(planar=false) {
// size = Maximum size of object to be contracted, given as a scalar. Default: 100 // size = Maximum size of object to be contracted, given as a scalar. Default: 100
// convexity = Max number of times a line could intersect the walls of the object. Default: 10 // convexity = Max number of times a line could intersect the walls of the object. Default: 10
module offset3d(r, size=100, convexity=10) { module offset3d(r, size=100, convexity=10) {
req_children($children);
n = quant(max(8,segs(abs(r))),4); n = quant(max(8,segs(abs(r))),4);
attachable(){
if (r==0) { if (r==0) {
children(); children();
} else if (r>0) { } else if (r>0) {
@ -515,6 +543,8 @@ module offset3d(r, size=100, convexity=10) {
} }
} }
} }
union();
}
} }
@ -540,12 +570,16 @@ module offset3d(r, size=100, convexity=10) {
// ir = Radius to round only inside (concave) corners to. Use instead of `r`. // ir = Radius to round only inside (concave) corners to. Use instead of `r`.
module round3d(r, or, ir, size=100) module round3d(r, or, ir, size=100)
{ {
req_children($children);
or = get_radius(r1=or, r=r, dflt=0); or = get_radius(r1=or, r=r, dflt=0);
ir = get_radius(r1=ir, r=r, dflt=0); ir = get_radius(r1=ir, r=r, dflt=0);
attachable(){
offset3d(or, size=size) offset3d(or, size=size)
offset3d(-ir-or, size=size) offset3d(-ir-or, size=size)
offset3d(ir, size=size) offset3d(ir, size=size)
children(); children();
union();
}
} }

View file

@ -329,20 +329,20 @@ module regular_polyhedron(
faces = entry[3]; faces = entry[3];
face_normals = entry[4]; face_normals = entry[4];
in_radius = entry[5]; in_radius = entry[5];
translate(translation){
if (draw){ if (draw){
if (rounding==0) if (rounding==0)
polyhedron(move(translation, p=scaled_points), faces = face_triangles); polyhedron(scaled_points, faces = face_triangles);
else { else {
fn = segs(rounding); fn = segs(rounding);
rounding = rounding/cos(180/fn); rounding = rounding/cos(180/fn);
adjusted_scale = 1 - rounding / in_radius; adjusted_scale = 1 - rounding / in_radius;
minkowski(){ minkowski(){
sphere(r=rounding, $fn=fn); sphere(r=rounding, $fn=fn);
polyhedron(move(translation,p=adjusted_scale*scaled_points), faces = face_triangles); polyhedron(adjusted_scale*scaled_points, faces = face_triangles);
} }
} }
} }
translate(translation)
if ($children>0) { if ($children>0) {
maxrange = repeat ? len(faces)-1 : $children-1; maxrange = repeat ? len(faces)-1 : $children-1;
for(i=[0:1:maxrange]) { for(i=[0:1:maxrange]) {
@ -363,6 +363,7 @@ module regular_polyhedron(
} }
} }
} }
}
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////