Skip to main content

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 definitions
mountingHoleRadius=1.5;
// ... other module definitions
module plateHoles() {
translate([baseWidth/2+pivotRadius,-baseThickness,0]){
rotate([-90,0,0]){
cylinder(r=mountingHoleRadius,h=baseThickness*4);
}
}
}
%hingeHalfFemale();
// hingeHalfMale();
plateHoles();

Live Demo

Basic Loop#

From 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);
}
}
}
}

Live Demo

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", 0
ECHO: "increment is currently", 1
ECHO: "increment is currently", 2
// followed by some internal OpenSCAD messages

Repeating Geometry#

Great, 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);
}
}
}
}

Live Demo

And just like that we have three evenly spaced cylinders!

Calculating distribution#

I'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);
}
}
}
}

Live Demo

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);
}
}
}
}

Live Demo

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);
}
}
}
}

Live Demo

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();

Live Demo

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!