Loops
Let's remove the male hinge for now and add a new module
called plateHoles
.
We'll start by adding adding a cylinder that's definitely longer than the plate is thick, we'll than rotate it by 90 degrees and move it a little:
// ... other variable definitionsmountingHoleRadius=1.5;
// ... other module definitionsmodule plateHoles() { translate([baseWidth/2+pivotRadius,-baseThickness,0]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } }}
%hingeHalfFemale();// hingeHalfMale();plateHoles();
#
Basic LoopFrom here we can see how we can use this new cylinder
along with difference
to make a hole in the hinge base, but it's not quiet in the right place (it's half hanging off the edge), lets add a variable for how close we want the hole to sit from the edge mountingHoleEdgeOffset=4;
.
But bear in mind we also want to want multiple of these hole and it would be good if we could avoid "hard-coding" each one. Luckly we're able to layout a number of holes efficiently with a for
loop.
Lets add another variable mountingHoleCount=3;
. There's a few ways to use a for
loop in OpenSCAD, but we're going to use the simplest case, it's defined as
for(increment=[startNumber:endNmuber]){ /* your code ... */ }
increment
is another variable, we can name it anything we want (i
is very common) but increment is a good name.
The code that runs within the curly braces {}
is run multiple times for each number in the range between startNumber
and endNumber
, and the value of increment
will update each time it's run. To make this concrete, we want 3 holes so lets add the following to plateHoles
:
module plateHoles() { for(increment=[0:2]){ echo("increment is currently", increment); translate([baseWidth/2+pivotRadius,-baseThickness,0]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } } }}
The reason we're using [0:2]
and not [0:3]
is because 0
counts so the code still runs 3 times.
I've also introduced another function echo
, this function can be used to display text to the console, we've added it as a temporary measure to help demonstrate that the code in the for
loop is run multiple times.
You should see the the following in the console:
ECHO: "increment is currently", 0ECHO: "increment is currently", 1ECHO: "increment is currently", 2// followed by some internal OpenSCAD messages
#
Repeating GeometryGreat, echo
runs three times. Since we know the value of increment
changes, lets use that to our advantage and change the Z-axis value of translate
like so:
module plateHoles() { for(increment=[0:2]){ translate([baseWidth/2+pivotRadius,-baseThickness,increment*10]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } } }}
And just like that we have three evenly spaced cylinders
!
#
Calculating distributionI'm sure you can see where this is going, we need to make a few tweaks to get this all polished though.
First lets use our variables, both the new mountingHoleCount
and we can use that calculate a new variable mountingHoleMoveIncrement=hingeLength/(mountingHoleCount-1);
This will be the gap between each of the holes, the reason we're using (mountingHoleCount-1)
is because counting the gaps between holes, there's one less than the amount of holes. let's now add increment*mountingHoleMoveIncrement
:
mountingHoleMoveIncrement=hingeLength/(mountingHoleCount-1);
module plateHoles() { for(i=[0:mountingHoleCount-1]){ translate([baseWidth/2+pivotRadius,-baseThickness,i*mountingHoleMoveIncrement]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } } }}
Awesome, it obvious that the hole spacing is related to the length of the hinge now, we can even increase the amount of holes with mountingHoleCount=4; and it looks correct:
Though we still have the problem if the holes sitting right on the edge.
We defined mountingHoleEdgeOffset
earlier lets now use it in the mountingHoleMoveIncrement
calculation.
mountingHoleEdgeOffset=4;mountingHoleMoveIncrement=(hingeLength-2*mountingHoleEdgeOffset)/ (mountingHoleCount-1);
module plateHoles() { for(i=[0:mountingHoleCount-1]){ translate([baseWidth/2+pivotRadius,-baseThickness,i*mountingHoleMoveIncrement]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } } }}
We subtract 2*mountingHoleEdgeOffset
from the hingeLength
because we are limiting the amount of space the holes can spread out in, it 2*
the offset because we want that space of both sides, but clearly we don't have a gap on each side yet, but this is just a matter of where the first hole starts, so the last step for our for
loop is to shift it over a little:
module plateHoles() { for(i=[0:mountingHoleCount-1]){ translate([ baseWidth/2+pivotRadius, -baseThickness, i*mountingHoleMoveIncrement+mountingHoleEdgeOffset // <-- add offset ]){ rotate([-90,0,0]){ cylinder(r=mountingHoleRadius,h=baseThickness*4); } } }}
Fantastic! now that we have our holes placed, we need to use difference
to actually cut the holes into the part, but where to do it?? We could use difference
in both the male and female parts but that would require doing the same thing twice. The best place to do it is in hingeBodyHalf
since this module is common to both sides of the hinge:
module hingeBodyHalf() { difference() { union() { linear_extrude(hingeHalfExtrudeLength){ offset(1)offset(-2)offset(1){ translate([0,pivotRadius,0]){ circle(pivotRadius); } square([pivotRadius,pivotRadius]); hingeBaseProfile(); } } linear_extrude(hingeLength){ offset(1)offset(-1)hingeBaseProfile(); } } plateHoles(); }}
// .. more code
hingeHalfFemale();hingeHalfMale();
We're using difference
here as planned, but we've also introduced a new operation union
.
union
allows us to combine shapes into one, which is important here since difference
works by subtracting the second child from the first and because both of the linear_extrudes
are children union
lets us combine them into a single child so that we can subtract plateHoles
.
Here's the result!