mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
commit
b9151f25c6
7 changed files with 237 additions and 112 deletions
|
@ -367,14 +367,14 @@ function ycopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// Example: Cubic sphere packing
|
||||
// s = 20;
|
||||
// s2 = s * sin(45);
|
||||
// zcopies(s2,n=8) union()
|
||||
// zcopies(s2,n=8)
|
||||
// grid_copies([s2,s2],n=8,stagger=($idx%2)? true : "alt")
|
||||
// sphere(d=s);
|
||||
// Example: Hexagonal sphere packing
|
||||
// s = 20;
|
||||
// xyr = adj_ang_to_hyp(s/2,30);
|
||||
// h = hyp_adj_to_opp(s,xyr);
|
||||
// zcopies(h,n=8) union()
|
||||
// zcopies(h,n=8)
|
||||
// back(($idx%2)*xyr*cos(60))
|
||||
// grid_copies(s,n=[12,7],stagger=($idx%2)? "alt" : true)
|
||||
// sphere(d=s);
|
||||
|
@ -613,18 +613,15 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) =
|
|||
// color(($row+$col)%2?"black":"red")
|
||||
// cube([8,8,0.01], center=false);
|
||||
//
|
||||
// Example:
|
||||
// // Makes a grid of hexagon pillars whose tops are all
|
||||
// // angled to reflect light at [0,0,50], if they were shiny.
|
||||
// Example: Makes a grid of hexagon pillars whose tops are all angled to reflect light at [0,0,50], if they were shiny.
|
||||
// hexregion = circle(r=50.01,$fn=6);
|
||||
// grid_copies(spacing=10, stagger=true, inside=hexregion) union() {
|
||||
// // Note: The union() is needed or else $pos will be
|
||||
// // inexplicably unreadable.
|
||||
// grid_copies(spacing=10, stagger=true, inside=hexregion)
|
||||
// union() { // Needed for OpenSCAD 2021.01 as noted above
|
||||
// ref_v = (unit([0,0,50]-point3d($pos)) + UP)/2;
|
||||
// half_of(v=-ref_v, cp=[0,0,5])
|
||||
// zrot(180/6)
|
||||
// cylinder(h=20, d=10/cos(180/6)+0.01, $fn=6);
|
||||
// }
|
||||
// }
|
||||
|
||||
module grid2d(spacing, n, size, stagger=false, inside=undef, nonzero)
|
||||
{
|
||||
|
|
182
hinges.scad
182
hinges.scad
|
@ -23,9 +23,17 @@ include <screws.scad>
|
|||
// The offset is the distance from a vertical mounting point to the center of the hinge pin. The hinge barrel is held by an angled support and
|
||||
// vertical support. The length of the angled support is determined by its angle and the offset. You specify the length of the vertical support with the
|
||||
// arm_height parameter.
|
||||
//
|
||||
// .
|
||||
// A hinge requires clearance so its parts don't interfere. If the hinge pin is exactly centered on the top of your part, then the hinge may not close all the way
|
||||
// due to interference at the edge. A small clearance, specified with `clearance=`, raises the hinge up and can ease this interference. It should probably be equal to a layer thickness or two.
|
||||
// If the hinge knuckle is close to the hinged part then the mating part may interfere. You can create clearance to address this problem by increasing the offset
|
||||
// to move the hinge knuckles farther away. Another method is to cut out a curved recess on the parts to allow space for the other hinges. This is possible
|
||||
// using the `knuckle_clearance=` parameter, which specifies the extra space to cut away to leave room for the hinge knuckles. It must be positive for any space
|
||||
// to be cut, and to use this option you must make the hinge a child of some object and specify {{diff()}} for the parent object of the hinge.
|
||||
// Figure(2D,Med,NoScales): The basic hinge form appears on the left. If fill is set to true the gap between the mount surface and hinge arm is filled as shown on the right.
|
||||
// _hinge_profile(4, 5, $fn=32, fill=false);
|
||||
// right(13)_hinge_profile(4, 5, $fn=32, fill=true);
|
||||
// _knuckle_hinge_profile(4, 5, $fn=32, fill=false);
|
||||
// right(13)_knuckle_hinge_profile(4, 5, $fn=32, fill=true);
|
||||
// fwd(9)stroke([[0,0],[4,4],[4,9]], width=.3,color="black");
|
||||
// stroke([[5,-5],[5,0]], endcaps="arrow2", color="blue",width=.15);
|
||||
// color("blue"){move([6.2,-2.5])text("arm_height",size=.75,valign="center");
|
||||
|
@ -37,27 +45,47 @@ include <screws.scad>
|
|||
// As shown in the above figure, the fill option fills the gap between the hinge arm and the mount surface to make a stronger connection. When the
|
||||
// arm height is set to zero, only a single segment connects the hinge barrel to the mount surface.
|
||||
// Figure(2D,Med,NoScales): Zero arm height with 45 deg arm
|
||||
// right(10) _hinge_profile(4, 0, $fn=32);
|
||||
// _hinge_profile(4, 0, $fn=32,fill=false);
|
||||
// right(10) _knuckle_hinge_profile(4, 0, $fn=32);
|
||||
// _knuckle_hinge_profile(4, 0, $fn=32,fill=false);
|
||||
// right(11)fwd(-3)color("blue")text("fill=true",size=1);
|
||||
// right(.5)fwd(-3)color("blue")text("fill=false",size=1);
|
||||
// Continues:
|
||||
// Figure(2D,Med,NoScales): Zero arm height with 90 deg arm. The clear_top parameter removes the hinge support material that is above the x axis
|
||||
// _hinge_profile(4, 0, 90, $fn=32);
|
||||
// right(10) _hinge_profile(4, 0, 90, $fn=32,clear_top=true);
|
||||
// _knuckle_hinge_profile(4, 0, 90, $fn=32);
|
||||
// right(10) _knuckle_hinge_profile(4, 0, 90, $fn=32,clear_top=true);
|
||||
// right(9.5)fwd(-3)color("blue")text("clear_top=true",size=.76);
|
||||
// right(.5)fwd(-3)color("blue")text("clear_top=false",size=.76);
|
||||
// Figure(2D,Med,NoScales): An excessively large clearance value raises up the hinge center. Note that the hinge mounting remains bounded by the X axis, so when `fill=true` or `clear_top=true` this is different than simply raising up the entire hinge.
|
||||
// right(10) _knuckle_hinge_profile(4, 0, 90, $fn=32,clear_top=true,clearance=.5);
|
||||
// _knuckle_hinge_profile(4, 0, $fn=32,fill=true,clearance=.5);
|
||||
// Continues:
|
||||
// For 3D printability, you may prefer a teardrop shaped hole, which you can get with `teardrop=true`;
|
||||
// if necessary you can specify the teardrop direction to be UP, DOWN, FORWARD, or BACK.
|
||||
// (These directions assume that the base of the hinge is mounted on the back of something.)
|
||||
// Another option for printability is to use an octagonal hole, though it does seem more
|
||||
// difficult to size these for robust printability. To get an octagonal hole set `pin_fn=8`.
|
||||
// Figure(2D,Med,NoScales): Alternate hole shapes for improved 3D printabililty
|
||||
// right(10) _knuckle_hinge_profile(4, 0, $fn=32,pin_fn=8);
|
||||
// _knuckle_hinge_profile(4, 0, $fn=32,tearspin=0);
|
||||
// right(11)fwd(-3)color("blue")text("octagonal",size=1);
|
||||
// right(1.5)fwd(-3)color("blue")text("teardrop",size=1);
|
||||
// Continues:
|
||||
// For 3D printability, you may want to make the hinge pin hole octagonal. To do this without
|
||||
// changing the other parts of the design, set `pin_fn=8`. You can round off the joint to the
|
||||
// mount surface with `round_top` and `round_bot`. You specify the amount of thickness to add.
|
||||
// If you make this parameter too large you will get an error that the rounding doesn't fit.
|
||||
// The default pin hole size admits a piece of 1.75 mm filament. If you prefer to use a machine
|
||||
// screw you can set the pin_diam to a screw specification like `"M3"` or "#6". In this case,
|
||||
// a clearance hole is created through most of the hinge with a self-tap hole for the last segment.
|
||||
// If the last segment is very long you may shrink the self-tap portion using the tap_depth parameter.
|
||||
// The pin hole diameter is enlarged by the `2*$slop` for numerically specified holes.
|
||||
// Screw holes are made using {{screw_hole()} which enlarges the hole by `4*$slop`.
|
||||
// Screw holes are made using {{screw_hole()}} which enlarges the hole by `4*$slop`.
|
||||
// .
|
||||
// To blend hinges better with a model you can round off the joint with the mounting surface using
|
||||
// the `round_top` and `round_bot` parameters, which specify the cut distance, the amount of material to add.
|
||||
// They make a continuous curvature "smooth" roundover with `k=0.8`. See [smooth roundovers](rounding.scad#section-types-of-roundovers) for more
|
||||
// information. If you specify too large of a roundover you will get an error that the rounding doesn't fit.
|
||||
// Figure(2D,Med,NoScales): Top and bottom roundovers for smooth hinge attachment
|
||||
// right(12)_knuckle_hinge_profile(6, 0, $fn=32,fill=false,round_top=1.5);
|
||||
// _knuckle_hinge_profile(4, 0, $fn=32,fill=false,round_bot=1.5);
|
||||
// right(12)fwd(11)color("blue")text("round_top=1.8",size=1);
|
||||
// right(.5)fwd(-3)color("blue")text("round_bot=1.5",size=1);
|
||||
// Arguments:
|
||||
// length = total length of the entire hinge
|
||||
// offset = horizontal offset of the hinge pin center from the mount point
|
||||
|
@ -73,18 +101,22 @@ include <screws.scad>
|
|||
// round_bot = rounding amount to add where bottom of hinge arm joins the mount surface. Default: 0
|
||||
// knuckle_diam = diameter of hinge barrel. Default: 4
|
||||
// pin_diam = diameter of hinge pin hole as a number of screw specification. Default: 1.75
|
||||
// pin_fn = $fn value to use for the pin.
|
||||
// teardrop = Set to true or UP/DOWN/FWD/BACK to specify teardrop shape for the pin hole. Default: false
|
||||
// screw_head = screw head to use for countersink
|
||||
// screw_tolerance = screw hole tolerance. Default: "close"
|
||||
// tap_depth = Don't make the tapped part of the screw hole larger than this.
|
||||
// $slop = increases pin hole diameter
|
||||
// clearance = raises pin hole to create clearance at the edge of the mounted surface. Default: 0.15
|
||||
// clear_knuckle = clear space for hinge knuckle of mating part. Must use with {{diff()}}. Default: 0
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `BOTTOM`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Example: Basic hinge, inner=false in front and inner=true in the back
|
||||
// $fn=32;
|
||||
// ydistribute(30){
|
||||
// knuckle_hinge(length=35, segs=4, offset=3, arm_height=1);
|
||||
// knuckle_hinge(length=35, segs=4, offset=3, arm_height=1,inner=true);
|
||||
// knuckle_hinge(length=35, segs=5, offset=3, arm_height=1);
|
||||
// knuckle_hinge(length=35, segs=5, offset=3, arm_height=1,inner=true);
|
||||
// }
|
||||
// Example(NoScales): Basic hinge, mounted. Odd segment count means the "outside" hinge is on the outside at both ends.
|
||||
// $fn=32;
|
||||
|
@ -163,23 +195,35 @@ include <screws.scad>
|
|||
// position(TOP+RIGHT) orient(anchor=RIGHT)
|
||||
// knuckle_hinge(length=35, segs=3, offset=5, knuckle_diam=9, pin_diam="#6",
|
||||
// fill=false, inner=false, tap_depth=6, screw_head="socket");
|
||||
function knuckle_hinge(length, offset, segs, inner=false, arm_height=0, arm_angle=45, gap=0.2,
|
||||
// Example(NoScales): This hinge has a small offset, so the hinged parts may interfere. To prevent this, use `knuckle_clearance`. This example shows an excessive clearance value to make the effect obvious. Note that you **must** use {{diff()}} when you set `knuckle_clearance`, and the hinge must be a child of the object it mounts to. Otherwise the cylinders that are supposed to be subtracted will appear as extra objects. This is an inner hinge, so it has clearance zones for the larger outer hinge that will mate with it.
|
||||
// $fn=32;
|
||||
// diff()
|
||||
// cuboid([4,40,15])
|
||||
// position(TOP+RIGHT) orient(anchor=RIGHT)
|
||||
// knuckle_hinge(length=35, segs=5, offset=2, inner=true, knuckle_clearance=1);
|
||||
// Example(NoScales): Oh no! Forgot to use {{diff()}} with knuckle_clearance!
|
||||
// $fn=32;
|
||||
// cuboid([4,40,15])
|
||||
// position(TOP+RIGHT) orient(anchor=RIGHT)
|
||||
// knuckle_hinge(length=35, segs=5, offset=2, inner=true, knuckle_clearance=1);
|
||||
|
||||
function knuckle_hinge(length, segs, offset, inner=false, arm_height=0, arm_angle=45, gap=0.2,
|
||||
seg_ratio=1, knuckle_diam=4, pin_diam=1.75, fill=true, clear_top=false,
|
||||
round_bot=0, round_top=0, pin_fn,
|
||||
round_bot=0, round_top=0, pin_fn, clearance,
|
||||
tap_depth, screw_head, screw_tolerance="close",
|
||||
anchor=BOT,orient,spin) = no_function("hinge");
|
||||
|
||||
module knuckle_hinge(length, offset, segs, inner=false, arm_height=0, arm_angle=45, gap=0.2,
|
||||
module knuckle_hinge(length, segs, offset, inner=false, arm_height=0, arm_angle=45, gap=0.2,
|
||||
seg_ratio=1, knuckle_diam=4, pin_diam=1.75, fill=true, clear_top=false,
|
||||
round_bot=0, round_top=0, pin_fn,
|
||||
tap_depth, screw_head, screw_tolerance="close",
|
||||
round_bot=0, round_top=0, pin_fn, clearance=0, teardrop,
|
||||
tap_depth, screw_head, screw_tolerance="close", knuckle_clearance,
|
||||
anchor=BOT,orient,spin)
|
||||
{
|
||||
dummy =
|
||||
assert(is_str(pin_diam) || all_positive([pin_diam]), "pin_diam must be a screw spec string or a positive number")
|
||||
assert(all_positive(length), "length must be a postive number")
|
||||
assert(is_int(segs) && segs>=1, "segs must be an integer 1 or greater")
|
||||
assert(is_finite(offset) && offset>=knuckle_diam/2, "offset must be a valid number that is not smaller than radius of the hinge barrel")
|
||||
assert(is_int(segs) && segs>=2, "segs must be an integer 2 or greater")
|
||||
assert(is_finite(offset) && offset>=knuckle_diam/2, "offset must be a valid number that is not smaller than radius of the hinge knuckle")
|
||||
assert(is_finite(arm_angle) && arm_angle>0 && arm_angle<=90, "arm_angle must be greater than zero and less than or equal to 90");
|
||||
segs1 = ceil(segs/2);
|
||||
segs2 = floor(segs/2);
|
||||
|
@ -188,6 +232,42 @@ module knuckle_hinge(length, offset, segs, inner=false, arm_height=0, arm_angle=
|
|||
z_adjust = segs%2==1 ? 0
|
||||
: inner? seglen1/2
|
||||
: seglen2/2;
|
||||
tearspin = is_undef(teardrop) || teardrop==false ? undef
|
||||
: teardrop==UP || teardrop==true ? 0
|
||||
: teardrop==DOWN ? 180
|
||||
: teardrop==BACK ? 270
|
||||
: teardrop==FWD ? 90
|
||||
: assert(false, "Illegal value for teardrop");
|
||||
knuckle_segs = segs(knuckle_diam);
|
||||
transform = down(offset)*yrot(-90)*zmove(z_adjust);
|
||||
|
||||
if(knuckle_clearance){
|
||||
knuckle_clearance_diam = knuckle_diam / cos(180/knuckle_segs) + 2*knuckle_clearance;
|
||||
tag("remove")
|
||||
attachable(anchor,spin,orient,
|
||||
size=[length,
|
||||
arm_height+offset/tan(arm_angle)+knuckle_diam/2+knuckle_diam/2/sin(arm_angle),
|
||||
offset+knuckle_diam/2],
|
||||
offset=[0,
|
||||
-arm_height/2-offset/tan(arm_angle)/2-knuckle_diam/sin(arm_angle)/4+knuckle_diam/4,
|
||||
-offset/2+knuckle_diam/4]
|
||||
)
|
||||
{
|
||||
multmatrix(transform) down(segs%2==1? 0 : (seglen1+seglen2)/2){
|
||||
move([offset,clearance])
|
||||
intersection(){
|
||||
n = inner && segs%2==1 ? segs1
|
||||
|
||||
: inner ? segs1
|
||||
: segs2;
|
||||
zcopies(n=n, spacing=seglen1+seglen2)
|
||||
cyl(h=(inner?seglen1:seglen2)+gap-.01, d=knuckle_clearance_diam, circum=true, $fn=knuckle_segs, realign=true);
|
||||
//cyl(h=length+2*gap, d=knuckle_clearance_diam, circum=true, $fn=knuckle_segs, realign=true);
|
||||
}
|
||||
}
|
||||
union(){}
|
||||
}
|
||||
}
|
||||
attachable(anchor,spin,orient,
|
||||
size=[length,
|
||||
arm_height+offset/tan(arm_angle)+knuckle_diam/2+knuckle_diam/2/sin(arm_angle),
|
||||
|
@ -197,33 +277,31 @@ module knuckle_hinge(length, offset, segs, inner=false, arm_height=0, arm_angle=
|
|||
-offset/2+knuckle_diam/4]
|
||||
)
|
||||
{
|
||||
down(offset)
|
||||
yrot(-90)
|
||||
zmove(z_adjust)
|
||||
difference()
|
||||
{
|
||||
zcopies(n=inner?segs2:segs1, spacing=seglen1+seglen2)
|
||||
linear_extrude((inner?seglen2:seglen1)-gap,center=true)
|
||||
_hinge_profile(offset=offset, arm_height=arm_height, arm_angle=arm_angle, knuckle_diam=knuckle_diam, pin_diam=pin_diam,
|
||||
fill=fill, clear_top=clear_top, round_bot=round_bot, round_top=round_top, pin_fn=pin_fn);
|
||||
if (is_str(pin_diam)) right(offset) up(length/2-(inner?1:1)*z_adjust){
|
||||
tap_depth = min(segs%2==1?seglen1-gap/2:seglen2-gap/2, default(tap_depth, length));
|
||||
screw_hole(pin_diam, length=length+.01, tolerance="self tap", bevel=false, anchor=TOP);
|
||||
multmatrix(inner ? zflip(z=-length/2) : IDENT)
|
||||
if (is_undef(screw_head) || screw_head=="none" || starts_with(screw_head,"flat"))
|
||||
screw_hole(pin_diam, length=length-tap_depth, tolerance=screw_tolerance, bevel=false, anchor=TOP, head=screw_head);
|
||||
else {
|
||||
screw_hole(pin_diam, length=length-tap_depth, tolerance=screw_tolerance, bevel=false, anchor=TOP);
|
||||
screw_hole(pin_diam, length=.01, tolerance=screw_tolerance, bevel=false, anchor=TOP, head=screw_head);
|
||||
}
|
||||
multmatrix(transform)
|
||||
force_tag() difference() {
|
||||
zcopies(n=inner?segs2:segs1, spacing=seglen1+seglen2)
|
||||
linear_extrude((inner?seglen2:seglen1)-gap,center=true)
|
||||
_knuckle_hinge_profile(offset=offset, arm_height=arm_height, arm_angle=arm_angle, knuckle_diam=knuckle_diam, pin_diam=pin_diam,
|
||||
fill=fill, clear_top=clear_top, round_bot=round_bot, round_top=round_top, pin_fn=pin_fn,clearance=clearance,tearspin=tearspin);
|
||||
if (is_str(pin_diam)) back(clearance)right(offset) up(length/2-(inner?1:1)*z_adjust) zrot(default(tearspin,0)){
|
||||
$fn = default(pin_fn,$fn);
|
||||
tap_depth = min(segs%2==1?seglen1-gap/2:seglen2-gap/2, default(tap_depth, length));
|
||||
screw_hole(pin_diam, length=length+.01, tolerance="self tap", bevel=false, anchor=TOP, teardrop=is_def(tearspin));
|
||||
multmatrix(inner ? zflip(z=-length/2) : IDENT)
|
||||
if (is_undef(screw_head) || screw_head=="none" || starts_with(screw_head,"flat"))
|
||||
screw_hole(pin_diam, length=length-tap_depth, tolerance=screw_tolerance, bevel=false, anchor=TOP, head=screw_head, teardrop=is_def(tearspin));
|
||||
else {
|
||||
screw_hole(pin_diam, length=length-tap_depth, tolerance=screw_tolerance, bevel=false, anchor=TOP, teardrop=is_def(tearspin));
|
||||
screw_hole(pin_diam, length=.01, tolerance=screw_tolerance, bevel=false, anchor=TOP, head=screw_head, teardrop=is_def(tearspin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module _hinge_profile(offset, arm_height, arm_angle=45, knuckle_diam=4, pin_diam=1.75, fill=true, clear_top=false, round_bot=0, round_top=0, pin_fn)
|
||||
module _knuckle_hinge_profile(offset, arm_height, arm_angle=45, knuckle_diam=4, pin_diam=1.75, fill=true, clear_top=false, round_bot=0, round_top=0, pin_fn, clearance=0, tearspin)
|
||||
{
|
||||
extra = .01;
|
||||
skel = turtle(["left", 90-arm_angle, "untilx", offset+extra, "left", arm_angle,
|
||||
|
@ -231,22 +309,30 @@ module _hinge_profile(offset, arm_height, arm_angle=45, knuckle_diam=4, pin_diam
|
|||
ofs = arm_height+offset/tan(arm_angle);
|
||||
start=round_bot==0 && round_top==0 ? os_flat(abs_angle=90)
|
||||
: os_round(abs_angle=90, cut=[-round_top,-round_bot],k=.8);
|
||||
f=echo(clearance=clearance);
|
||||
back(clearance)
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
fwd(ofs){
|
||||
left(extra)offset_stroke(skel, width=knuckle_diam, start=start);
|
||||
if (fill) polygon([each skel,[-extra,ofs]]);
|
||||
if (fill) polygon([each list_head(skel,-2), fwd(clearance,last(skel)), [-extra,ofs-clearance]]);
|
||||
}
|
||||
if (clear_top) left(.1) rect([offset+knuckle_diam,knuckle_diam+1],anchor=BOT+LEFT);
|
||||
if (clear_top==true || clear_top=="all") left(.1)fwd(clearance) rect([offset+knuckle_diam,knuckle_diam+1+clearance],anchor=BOT+LEFT);
|
||||
if (is_num(clear_top)) left(.1)fwd(clearance) rect([.1+clear_top, knuckle_diam+1+clearance], anchor=BOT+LEFT);
|
||||
}
|
||||
right(offset)ellipse(d=knuckle_diam,realign=true,circum=true);
|
||||
}
|
||||
if (is_num(pin_diam) && pin_diam>0)
|
||||
right(offset)ellipse(d=pin_diam+2*get_slop(), realign=true, circum=true, $fn=default(pin_fn,$fn));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_num(pin_diam) && pin_diam>0){
|
||||
$fn = default(pin_fn,$fn);
|
||||
right(offset)
|
||||
if (is_def(tearspin)){
|
||||
teardrop2d(d=pin_diam+2*get_slop(), realign=true, circum=true, spin=tearspin);
|
||||
}
|
||||
else ellipse(d=pin_diam+2*get_slop(), realign=true, circum=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: living_hinge_mask()
|
||||
|
|
|
@ -853,7 +853,10 @@ function offset(
|
|||
chamfer = is_def(r) ? false : chamfer,
|
||||
quality = max(0,round(quality)),
|
||||
flip_dir = closed && !is_polygon_clockwise(path)? -1 : 1,
|
||||
d = flip_dir * (is_def(r) ? r : delta),
|
||||
d = flip_dir * (is_def(r) ? r : delta)
|
||||
)
|
||||
d==0 && !return_faces ? path :
|
||||
let(
|
||||
// shiftsegs = [for(i=[0:len(path)-1]) _shift_segment(select(path,i,i+1), d)],
|
||||
shiftsegs = [for(i=[0:len(path)-2]) _shift_segment([path[i],path[i+1]], d),
|
||||
if (closed) _shift_segment([last(path),path[0]],d)
|
||||
|
|
98
screws.scad
98
screws.scad
|
@ -166,7 +166,11 @@ include <screw_drive.scad>
|
|||
// .
|
||||
// All of the screw related modules set the variable `$screw_spec` to contain the specification
|
||||
// for their screw. This means that child modules can make use of this variable to create
|
||||
// mating (or identical) parts.
|
||||
// mating (or identical) parts. Note that the `shaft_oversize` and `head_oversize` screw
|
||||
// info fields are only inherited into modules that are the same as the parent module.
|
||||
// This means that if you create an oversized screw hole and then make a screw as s child, the
|
||||
// child screw will **not** inherit the oversize parameters. But a screw_hole will inherit
|
||||
// oversize parameters from a parent screw_hole.
|
||||
|
||||
/*
|
||||
http://mdmetric.com/thddata.htm#idx
|
||||
|
@ -238,9 +242,9 @@ Torx values: https://www.stanleyengineeredfastening.com/-/media/web/sef/resourc
|
|||
// thread_len = length of threaded portion of screw (in mm), for making partly threaded screws. Default: fully threaded
|
||||
// details = toggle some details in rendering. Default: true
|
||||
// tolerance = screw tolerance. Determines actual screw thread geometry based on nominal sizing. See [tolerance](#subsection-tolerance). Default is "2A" for UTS and "6g" for ISO.
|
||||
// undersize = amount to decrease screw diameter, a scalar to apply to all parts, or a 2-vector to control shaft and head. Default: 0
|
||||
// undersize_shaft = amount to decrease diameter of the shaft of screw
|
||||
// undersize_head = amount to decrease the head diameter of the screw
|
||||
// undersize = amount to decrease screw diameter, a scalar to apply to all parts, or a 2-vector to control shaft and head. Replaces rather than adding to the head_oversize value in a screw specification.
|
||||
// shaft_undersize = amount to decrease diameter of the shaft of screw; replaces rather than adding to the shaft_oversize value in a screw specification.
|
||||
// head_undersize = amount to decrease the head diameter of the screw; replaces rather than adding to the head_oversize value in a screw specification.
|
||||
// bevel1 = bevel bottom end of screw. Default: true
|
||||
// bevel2 = bevel top end of threaded section. Default: true for headless, false otherwise
|
||||
// bevel = bevel both ends of the threaded section.
|
||||
|
@ -447,7 +451,10 @@ function _get_spec(spec, needtype, origin, thread, // common parameters
|
|||
in_list(_downcase_if_str(thickness),["thin","normal","thick","undersized","din"]),
|
||||
"thickness must be a positive number of one of \"thin\", \"thick\", \"normal\", \"undersized\", or \"DIN\"")
|
||||
assert(!(is_undef(spec) && is_undef($screw_spec)), "No screw spec given and no parent spec available to inherit")
|
||||
let(spec=is_undef(spec) ? $screw_spec : spec)
|
||||
let(
|
||||
spec=is_undef(spec) ? $screw_spec : spec,
|
||||
spec_origin = is_struct(spec) ? struct_val(spec,"origin") : undef
|
||||
)
|
||||
assert(is_string(spec) || is_struct(spec), "Screw/nut specification must be a string or struct")
|
||||
let(
|
||||
specname = is_struct(spec) ? struct_val(spec,"name") : undef,
|
||||
|
@ -459,11 +466,14 @@ function _get_spec(spec, needtype, origin, thread, // common parameters
|
|||
specname
|
||||
: undef,
|
||||
p = is_struct(spec) ? struct_val(spec,"pitch") : undef,
|
||||
thread = // If the origin of the struct is a hole with pitch zero and we are making a screw, try to find a nonzero pitch
|
||||
is_undef(name) && struct_val(spec,"origin")=="screw_hole" && origin!="screw_hole" && p==0 && is_string(specname)
|
||||
? let(temp_info = screw_info(specname,thread))
|
||||
struct_val(temp_info,"pitch")
|
||||
: thread
|
||||
thread = is_def(name) ? thread
|
||||
// If the origin of the struct is a hole with pitch zero and we are making a screw, try to find a nonzero pitch
|
||||
: spec_origin=="screw_hole" && origin!="screw_hole" && p==0 && is_string(specname) ?
|
||||
let(temp_info = screw_info(specname,thread))
|
||||
struct_val(temp_info,"pitch")
|
||||
// : spec_origin=="screw_hole" && origin=="screw_hole" && all_positive([p]) ? p
|
||||
// : origin=="screw_hole" && is_undef(thread) ? 0
|
||||
: thread
|
||||
)
|
||||
is_def(name) ? (needtype=="screw_info" ? screw_info(name,_origin=origin, thread= origin=="screw_hole" ? default(thread,true) : thread,
|
||||
head=head, drive=drive, drive_size=drive_size)
|
||||
|
@ -479,19 +489,18 @@ function _get_spec(spec, needtype, origin, thread, // common parameters
|
|||
let(
|
||||
spec = _struct_reset(spec,
|
||||
[
|
||||
["origin", origin],
|
||||
if (origin=="screw") ["counterbore",0],
|
||||
if (head=="none") ["head","none"],
|
||||
if (head=="none") ["drive","none"],
|
||||
if (thread==false || thread=="none") ["pitch",0]
|
||||
else if (thread!=true) ["pitch",thread],
|
||||
["thickness", thickness],
|
||||
], grow=false)
|
||||
], grow=true),
|
||||
inherit = is_undef(spec_origin) || spec_origin==origin
|
||||
)
|
||||
origin==struct_val(spec, "origin") ? spec
|
||||
: _struct_reset(spec, [
|
||||
["thread_oversize",0],
|
||||
["head_oversize",0]
|
||||
], grow=false);
|
||||
inherit ? spec
|
||||
: struct_remove(spec, ["shaft_oversize","head_oversize"]);
|
||||
|
||||
|
||||
function _struct_reset(s, keyval, grow=true) =
|
||||
|
@ -501,7 +510,7 @@ function _struct_reset(s, keyval, grow=true) =
|
|||
struct_set(s,flatten(bselect(keyval,good)));
|
||||
|
||||
|
||||
function _nominal_diam(spec) = struct_val(spec,"diameter")+default(struct_val(spec,"threads_oversize"),0);
|
||||
function _nominal_diam(spec) = struct_val(spec,"diameter")+default(struct_val(spec,"shaft_oversize"),0);
|
||||
|
||||
function screw(spec, head, drive, thread, drive_size,
|
||||
length, l, thread_len, tolerance, details=true,
|
||||
|
@ -544,7 +553,7 @@ module screw(spec, head, drive, thread, drive_size,
|
|||
reset_headsize = _internal && flathead ? struct_val(tempspec,"head_size_sharp") : undef;
|
||||
spec=_struct_reset(tempspec,[
|
||||
["length", l],
|
||||
["threads_oversize", u_mul(-1,shaft_undersize)],
|
||||
["shaft_oversize", u_mul(-1,shaft_undersize)],
|
||||
["head_oversize", u_mul(-1,head_undersize)],
|
||||
["counterbore", _counterbore],
|
||||
["thread_len", thread_len],
|
||||
|
@ -651,7 +660,7 @@ module screw(spec, head, drive, thread, drive_size,
|
|||
difference(){
|
||||
union(){
|
||||
screw_head(spec,details,counterbore=counterbore,flat_height=flat_height,
|
||||
oversize=islop,teardrop=_teardrop);
|
||||
slop=islop,teardrop=_teardrop);
|
||||
if (_shoulder_len>0)
|
||||
up(eps_shoulder-flat_height){
|
||||
if (_teardrop)
|
||||
|
@ -737,9 +746,9 @@ module screw(spec, head, drive, thread, drive_size,
|
|||
// ---
|
||||
// thread = thread type or specification for threaded masks, or false to make an unthreaded mask. See [screw pitch](#subsection-standard-screw-pitch). Default: false
|
||||
// teardrop = if true produce teardrop hole. Only compatible with clearance holes, not threaded. Default: false
|
||||
// oversize = amount to increase diameter of all screw parts, a scalar or length 3 vector. Default: 0
|
||||
// hole_oversize = amount to increase diameter of the hole.
|
||||
// head_oversize = amount to increase diameter of head.
|
||||
// oversize = amount to increase diameter of the screw hole (hole and countersink). A scalar or length 2 vector. Default: use computed tolerance
|
||||
// hole_oversize = amount to increase diameter of the hole. Overrides the use of tolerance and replaces any settings given in the screw specification.
|
||||
// head_oversize = amount to increase diameter of head. Overrides the user of tolerance and replaces any settings given in the screw specification.
|
||||
// length / l= length of screw (in mm)
|
||||
// counterbore = set to length of counterbore, or true to make a counterbore equal to head height. Default: false for flat heads and headless, true otherwise
|
||||
// tolerance = threading or clearance hole tolerance. For internal threads, detrmines actual thread geometry based on nominal sizing. See [tolerance](#subsection-tolerance). Default is "2B" for UTS and 6H for ISO. For clearance holes, determines how much clearance to add. Default is "normal".
|
||||
|
@ -807,11 +816,12 @@ module screw_hole(spec, head, thread, oversize, hole_oversize, head_oversize,
|
|||
dummy = _validate_screw_spec(screwspec);
|
||||
threaded = thread==true || (is_finite(thread) && thread>0) || (is_undef(thread) && struct_val(screwspec,"pitch")>0);
|
||||
dummy2 = assert(!threaded || !teardrop, "Cannot make threaded teardrop holes");
|
||||
if (threaded || is_def(oversize) || is_def(hole_oversize) || tolerance==0 || tolerance=="none") {
|
||||
undersize = is_def(oversize) ? -oversize
|
||||
: -[default(hole_oversize,0), default(head_oversize,0)];
|
||||
oversize = force_list(oversize,2);
|
||||
hole_oversize = first_defined([hole_oversize, oversize[0],struct_val(screwspec,"shaft_oversize")]);
|
||||
head_oversize = first_defined([head_oversize, oversize[1],struct_val(screwspec,"head_oversize")]);
|
||||
if (threaded || is_def(hole_oversize) || tolerance==0 || tolerance=="none") {
|
||||
default_tag("remove")
|
||||
screw(spec,head=head,thread=thread,undersize=undersize, higbee=higbee,
|
||||
screw(spec,head=head,thread=thread,shaft_undersize=u_mul(-1,hole_oversize), head_undersize=u_mul(-1,head_oversize), higbee=higbee,
|
||||
length=length,l=l,thread_len=thread_len, tolerance=tolerance, _counterbore=counterbore,
|
||||
bevel=bevel, bevel1=bevel1, bevel2=bevel2,
|
||||
atype=atype, anchor=anchor, spin=spin, orient=orient, _internal=true, _teardrop=teardrop)
|
||||
|
@ -1346,7 +1356,7 @@ function _parse_drive(drive=undef, drive_size=undef) =
|
|||
|
||||
// Module: screw_head()
|
||||
// Usage:
|
||||
// screw_head(screw_info, [details],[counterbore],[flat_height],[oversize],[teardrop])
|
||||
// screw_head(screw_info, [details],[counterbore],[flat_height],[teardrop],[internal])
|
||||
// Description:
|
||||
// Draws the screw head described by the data structure `screw_info`, which
|
||||
// should have the fields produced by {{screw_info()}}. See that function for
|
||||
|
@ -1355,15 +1365,16 @@ function _parse_drive(drive=undef, drive_size=undef) =
|
|||
// Other heads appear sitting on the xy plane.
|
||||
// Arguments:
|
||||
// screw_info = structure produced by {{screw_info()}}
|
||||
// ---
|
||||
// details = true for more detailed model. Default: false
|
||||
// counterbore = counterbore height. Default: no counterbore
|
||||
// flat_height = height of flat head
|
||||
// oversize = amount to oversize the head
|
||||
// teardrop = if true make flathead and counterbores teardrop shaped
|
||||
function screw_head(screw_info,details,counterbore,flat_height) = no_function("screw_head");
|
||||
module screw_head(screw_info,details=false, counterbore=0,flat_height,oversize=0,teardrop=false) {
|
||||
// slop = enlarge diameter by this extra amount (beyond that specified in the screw specification). Default: 0
|
||||
function screw_head(screw_info,details=false, counterbore=0,flat_height,teardrop=false,slop=0) = no_function("screw_head");
|
||||
module screw_head(screw_info,details=false, counterbore=0,flat_height,teardrop=false,slop=0) {
|
||||
no_children($children);
|
||||
head_oversize = struct_val(screw_info, "head_oversize",0) + oversize;
|
||||
head_oversize = struct_val(screw_info, "head_oversize",0) + slop;
|
||||
head = struct_val(screw_info, "head");
|
||||
head_size = struct_val(screw_info, "head_size",0) + head_oversize;
|
||||
head_height = struct_val(screw_info, "head_height");
|
||||
|
@ -1378,6 +1389,7 @@ module screw_head(screw_info,details=false, counterbore=0,flat_height,oversize=0
|
|||
: "Counterbore must be a nonnegative number"));
|
||||
|
||||
counterbore = counterbore_temp==0 && head!="flat" ? counterbore_temp : counterbore_temp + 0.01;
|
||||
adj_diam = struct_val(screw_info, "diameter") + head_oversize; // Used for determining chamfers and ribbing
|
||||
if (head!="flat" && counterbore>0){
|
||||
d = head=="hex"? 2*head_size/sqrt(3) : head_size;
|
||||
if (teardrop)
|
||||
|
@ -1387,7 +1399,6 @@ module screw_head(screw_info,details=false, counterbore=0,flat_height,oversize=0
|
|||
}
|
||||
if (head=="flat") { // For flat head, counterbore is integrated
|
||||
angle = struct_val(screw_info, "head_angle")/2;
|
||||
diam = _nominal_diam(screw_info);
|
||||
sharpsize = struct_val(screw_info, "head_size_sharp")+head_oversize;
|
||||
sidewall_height = (sharpsize - head_size)/2 / tan(angle);
|
||||
cylheight = counterbore + sidewall_height;
|
||||
|
@ -1419,7 +1430,7 @@ module screw_head(screw_info,details=false, counterbore=0,flat_height,oversize=0
|
|||
if (head=="pan flat")
|
||||
cyl(l=head_height, d=head_size, rounding2=0.2*head_size, anchor=BOTTOM);
|
||||
if (head=="socket")
|
||||
cyl(l=head_height, d=head_size, anchor=BOTTOM, chamfer2=details? _nominal_diam(screw_info)/10:undef);
|
||||
cyl(l=head_height, d=head_size, anchor=BOTTOM, chamfer2=details? adj_diam/10:undef);
|
||||
if (head=="socket ribbed"){
|
||||
// These numbers are based on ISO specifications that dictate how much oversizsed a ribbed socket head can be
|
||||
// We are making our ribbed heads the same size as unribbed (by cutting the ribbing away), but these numbers are presumably a good guide
|
||||
|
@ -1428,11 +1439,10 @@ module screw_head(screw_info,details=false, counterbore=0,flat_height,oversize=0
|
|||
[6, .11],
|
||||
[12, .135],
|
||||
[20, .165]];
|
||||
diam = _nominal_diam(screw_info);
|
||||
intersection() {
|
||||
cyl(h=head_height/4, d=head_size, anchor=BOT)
|
||||
attach(TOP) cyl(l=head_height*3/4, d=head_size, anchor=BOT, texture="trunc_ribs", tex_counts=[31,1], tex_scale=-lookup(diam,rib_size));
|
||||
cyl(h=head_height,d=head_size, chamfer2=diam/10, anchor=BOT);
|
||||
attach(TOP) cyl(l=head_height*3/4, d=head_size, anchor=BOT, texture="trunc_ribs", tex_counts=[31,1], tex_scale=-lookup(adj_diam,rib_size));
|
||||
cyl(h=head_height,d=head_size, chamfer2=adj_diam/10, anchor=BOT);
|
||||
}
|
||||
}
|
||||
if (head=="hex")
|
||||
|
@ -1530,12 +1540,12 @@ module nut(spec, shape, thickness, nutwidth, thread, tolerance, hole_oversize,
|
|||
bevel,bevel1,bevel2,bevang=15,ibevel,ibevel1,ibevel2, higbee, higbee1, higbee2, anchor=BOTTOM, spin=0, orient=UP, oversize=0)
|
||||
{
|
||||
dummyA = assert(is_undef(nutwidth) || (is_num(nutwidth) && nutwidth>0));
|
||||
|
||||
|
||||
tempspec = _get_spec(spec, "nut_info", "nut",
|
||||
thread=thread, shape=shape, thickness=thickness);
|
||||
spec=_struct_reset(tempspec,[
|
||||
["width", nutwidth],
|
||||
["threads_oversize", hole_oversize],
|
||||
["shaft_oversize", hole_oversize],
|
||||
]);
|
||||
dummy=_validate_nut_spec(spec);
|
||||
$screw_spec = spec;
|
||||
|
@ -1763,7 +1773,7 @@ module nut_trap_inline(length, spec, shape, l, height, h, nutwidth, anchor, orie
|
|||
// "drive_depth" | Depth of the drive recess.
|
||||
// "length" | Length of the screw in mm measured in the customary fashion. For flat head screws the total length and for other screws, the length from the bottom of the head to the screw tip.
|
||||
// "thread_len" | Length of threaded portion of screw in mm
|
||||
// "threads_oversize"| Amount to oversize the threads
|
||||
// "shaft_oversize"| Amount to oversize the threads
|
||||
// "head_oversize" | Amount to oversize the head
|
||||
// .
|
||||
// If you want to define a custom drive for a screw you will need to provide the drive size and drive depth.
|
||||
|
@ -1775,10 +1785,10 @@ module nut_trap_inline(length, spec, shape, l, height, h, nutwidth, anchor, orie
|
|||
// ---
|
||||
// thread = thread type or specification. See [screw pitch](#subsection-standard-screw-pitch). Default: "coarse"
|
||||
// drive_size = size of drive recess to override computed value
|
||||
// threads_oversize = amount to increase screw diameter for clearance holes. Default: 0
|
||||
// shaft_oversize = amount to increase screw diameter for clearance holes. Default: 0
|
||||
// head_oversize = amount to increase head diameter for countersink holes. Default: 0
|
||||
|
||||
function screw_info(name, head, drive, thread, drive_size, threads_oversize=0, head_oversize=0, _origin) =
|
||||
function screw_info(name, head, drive, thread, drive_size, shaft_oversize, head_oversize, _origin) =
|
||||
assert(is_string(name), "Screw specification must be a string")
|
||||
let(
|
||||
thread = is_undef(thread) || thread==true ? "coarse"
|
||||
|
@ -1799,7 +1809,7 @@ function screw_info(name, head, drive, thread, drive_size, threads_oversize=0, h
|
|||
["length", type[3]],
|
||||
["drive_size", drive_info[1]],
|
||||
["name", name],
|
||||
["threads_oversize", threads_oversize],
|
||||
["shaft_oversize", shaft_oversize],
|
||||
["head_oversize", head_oversize],
|
||||
["origin",_origin]
|
||||
]);
|
||||
|
@ -1828,7 +1838,7 @@ function screw_info(name, head, drive, thread, drive_size, threads_oversize=0, h
|
|||
// "shape" | Shape of the nut, either "hex" or "square"
|
||||
// "width" | Flat to flat width of the nut
|
||||
// "thickness" | Thickness of the nut
|
||||
// "threads_oversize" | amount to oversize the threads (not including $slop)
|
||||
// "shaft_oversize" | amount to oversize the threads (not including $slop)
|
||||
// Arguments:
|
||||
// name = screw name, e.g. "M5x1" or "#8-32". See [screw naming](#subsection-screw-naming).
|
||||
// shape = shape of the nut, either "hex" or "square". Default: "hex"
|
||||
|
@ -1859,7 +1869,7 @@ function nut_info(name, shape, thickness, thread, hole_oversize=0, width, _origi
|
|||
: []
|
||||
)
|
||||
_struct_reset(nutdata, [["name", name],
|
||||
["threads_oversize",hole_oversize],
|
||||
["shaft_oversize",hole_oversize],
|
||||
["width", width],
|
||||
["origin",_origin]
|
||||
]);
|
||||
|
|
|
@ -833,6 +833,11 @@ function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) =
|
|||
// You can only round or chamfer the vertical(ish) edges. For those edges, you can
|
||||
// specify rounding and/or chamferring per-edge, and for top and bottom, inside and
|
||||
// outside separately.
|
||||
// .
|
||||
// By default if you specify a chamfer or rounding then it applies as specified to the
|
||||
// outside, and an inside rounding is calculated that will maintain constant width
|
||||
// if your wall thickness is uniform. If the wall thickness is not uniform, the default
|
||||
// inside rounding is calculated based on the smaller of the two wall thicknesses.
|
||||
// Arguments:
|
||||
// h/l/height/length = The height or length of the rectangular tube. Default: 1
|
||||
// size = The outer [X,Y] size of the rectangular tube.
|
||||
|
@ -851,10 +856,10 @@ function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) =
|
|||
// chamfer = The chamfer size for the outside edges of the rectangular tube.
|
||||
// chamfer1 = The chamfer size for the outside bottom corner of the rectangular tube.
|
||||
// chamfer2 = The chamfer size for the outside top corner of the rectangular tube.
|
||||
// irounding = The roundover radius for the inside edges of the rectangular tube. Default: Same as `rounding`
|
||||
// irounding = The roundover radius for the inside edges of the rectangular tube. Default: Computed for uniform wall thickness (see above)
|
||||
// irounding1 = The roundover radius for the inside bottom corner of the rectangular tube.
|
||||
// irounding2 = The roundover radius for the inside top corner of the rectangular tube.
|
||||
// ichamfer = The chamfer size for the inside edges of the rectangular tube. Default: Same as `chamfer`
|
||||
// ichamfer = The chamfer size for the inside edges of the rectangular tube. Default: Computed for uniform wall thickness (see above)
|
||||
// ichamfer1 = The chamfer size for the inside bottom corner of the rectangular tube.
|
||||
// ichamfer2 = The chamfer size for the inside top corner of the rectangular tube.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `BOTTOM`
|
||||
|
@ -871,6 +876,10 @@ function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) =
|
|||
// size1=[100,60], size2=[70,40],
|
||||
// isize1=[40,20], isize2=[65,35], h=15
|
||||
// );
|
||||
// Example: With rounding
|
||||
// rect_tube(size=100, wall=5, rounding=10, h=30);
|
||||
// Example: With rounding
|
||||
// rect_tube(size=100, wall=5, chamfer=10, h=30);
|
||||
// Example: Outer Rounding Only
|
||||
// rect_tube(size=100, wall=5, rounding=10, irounding=0, h=30);
|
||||
// Example: Outer Chamfer Only
|
||||
|
@ -911,13 +920,22 @@ function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) =
|
|||
// rounding2=[0,5,0,10], irounding2=[0,3,0,8]
|
||||
// );
|
||||
|
||||
|
||||
function _rect_tube_rounding(factor,ir,r,size,isize) =
|
||||
let(wall = min(size-isize)/2*factor
|
||||
)
|
||||
is_def(ir) ? ir
|
||||
: is_undef(r) ? undef
|
||||
: is_num(r) ? max(0,r-wall)
|
||||
: [for(val=r) max(0,val-wall)];
|
||||
|
||||
module rect_tube(
|
||||
h, size, isize, center, shift=[0,0],
|
||||
wall, size1, size2, isize1, isize2,
|
||||
rounding=0, rounding1, rounding2,
|
||||
irounding=0, irounding1, irounding2,
|
||||
irounding, irounding1, irounding2,
|
||||
chamfer=0, chamfer1, chamfer2,
|
||||
ichamfer=0, ichamfer1, ichamfer2,
|
||||
ichamfer, ichamfer1, ichamfer2,
|
||||
anchor, spin=0, orient=UP,
|
||||
l, length, height
|
||||
) {
|
||||
|
@ -958,6 +976,12 @@ module rect_tube(
|
|||
(is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
|
||||
undef;
|
||||
checks2 =
|
||||
assert(is_num(rounding) || is_vector(rounding,4), "rounding must be a number or 4-vector")
|
||||
assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "rounding1 must be a number or 4-vector")
|
||||
assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "rounding2 must be a number or 4-vector")
|
||||
assert(is_undef(irounding) || is_num(irounding) || is_vector(irounding,4), "irounding must be a number or 4-vector")
|
||||
assert(is_undef(irounding1) || is_num(irounding1) || is_vector(irounding1,4), "irounding1 must be a number or 4-vector")
|
||||
assert(is_undef(irounding2) || is_num(irounding2) || is_vector(irounding2,4), "irounding2 must be a number or 4-vector")
|
||||
assert(wall==undef || is_num(wall))
|
||||
assert(size1!=undef, "Bad size/size1 argument.")
|
||||
assert(size2!=undef, "Bad size/size2 argument.")
|
||||
|
@ -967,6 +991,10 @@ module rect_tube(
|
|||
assert(isize1.y < size1.y, "Inner size is larger than outer size.")
|
||||
assert(isize2.x < size2.x, "Inner size is larger than outer size.")
|
||||
assert(isize2.y < size2.y, "Inner size is larger than outer size.");
|
||||
irounding1 = _rect_tube_rounding(1,default(irounding1, irounding), default(rounding1, rounding) , size1, isize1);
|
||||
irounding2 = _rect_tube_rounding(1,default(irounding2, irounding), default(rounding2, rounding) , size2, isize2);
|
||||
ichamfer1 = _rect_tube_rounding(1/sqrt(2),default(ichamfer1, ichamfer), default(chamfer1, chamfer) , size1, isize1);
|
||||
ichamfer2 = _rect_tube_rounding(1/sqrt(2),default(ichamfer2, ichamfer), default(chamfer2, chamfer) , size2, isize2);
|
||||
anchor = get_anchor(anchor, center, BOT, BOT);
|
||||
attachable(anchor,spin,orient, size=[each size1, h], size2=size2, shift=shift) {
|
||||
down(h/2) {
|
||||
|
@ -979,8 +1007,8 @@ module rect_tube(
|
|||
);
|
||||
down(0.01) prismoid(
|
||||
isize1, isize2, h=h+0.02, shift=shift,
|
||||
rounding=irounding, rounding1=irounding1, rounding2=irounding2,
|
||||
chamfer=ichamfer, chamfer1=ichamfer1, chamfer2=ichamfer2,
|
||||
rounding1=irounding1, rounding2=irounding2,
|
||||
chamfer1=ichamfer1, chamfer2=ichamfer2,
|
||||
anchor=BOT
|
||||
);
|
||||
}
|
||||
|
@ -993,9 +1021,9 @@ function rect_tube(
|
|||
h, size, isize, center, shift=[0,0],
|
||||
wall, size1, size2, isize1, isize2,
|
||||
rounding=0, rounding1, rounding2,
|
||||
irounding=0, irounding1, irounding2,
|
||||
irounding, irounding1, irounding2,
|
||||
chamfer=0, chamfer1, chamfer2,
|
||||
ichamfer=0, ichamfer1, ichamfer2,
|
||||
ichamfer, ichamfer1, ichamfer2,
|
||||
anchor, spin=0, orient=UP,
|
||||
l, length, height
|
||||
) = no_function("rect_tube");
|
||||
|
|
|
@ -64,9 +64,9 @@ function _format_key(key) = is_string(key) ? str("\"",key,"\""): key;
|
|||
// struct = input structure
|
||||
// key = a single key or list of keys to remove.
|
||||
function struct_remove(struct, key) =
|
||||
!is_list(key) ? struct_remove(struct, [key]) :
|
||||
!is_list(key) ? struct_remove(struct, [key]) :
|
||||
let(ind = search(key, struct))
|
||||
list_remove(struct, ind);
|
||||
list_remove(struct, [for(i=ind) if (i!=[]) i]);
|
||||
|
||||
|
||||
// Function: struct_val()
|
||||
|
|
|
@ -31,6 +31,7 @@ module test_struct_remove() {
|
|||
assert(struct_remove(st, ["Baz","Baz"]) == [["Foo",91],["Bar",28]]);
|
||||
assert(struct_remove(st, ["Baz","Foo"]) == [["Bar",28]]);
|
||||
assert(struct_remove(st, []) == st);
|
||||
assert(struct_remove(st, ["Bar","niggle"]) == [["Foo",91],["Baz",9]]);
|
||||
assert(struct_remove(st, struct_keys(st)) == []);
|
||||
}
|
||||
test_struct_remove();
|
||||
|
|
Loading…
Reference in a new issue