Modules, Variables and designing like a programmer

So far i have introduced you to enough that with patience and practice you could make just about anything, however sometimes you want to work smarter not harder. To do this we will look at how to use OpenSCAD more like a programing language in order to do things a little smarter.

Lets start with variables, we can define variables like we would in programming languages like python (without defining anything about a type). This is particularly useful in two situations: when you are using the same value repeatedly; and when you wish to look at how a model will look as you change a variable. So as an example lets look at creating a grid of cubes using a variable to define both the size of the cubes and the spacing of the grid


spacing = 30;
dimensions = [10,10,10];

cube(dimensions);
translate([spacing,0,0]){
 cube(dimensions);
}
translate([0,spacing,0]){
 cube(dimensions);
}
translate([spacing,spacing,0]){
 cube(dimensions);
}

So here we have two variables defined at the start, one takes the form of a vector [x,y,z] and the other an number. This allows us to then create a grid of cubes, all the same size spaced by the same amount, now if you wanted to quickly look at how this looked with a variety of cube sizes, we only need to change the value of spacing and the effect takes place everywhere. Now here is where I do need to give a word of warning compared to what you might be expecting here. Normally code is run sequentially for example


A = 2;
B = 5;
C = A+B;
A=3;

Normally we would expect C=7 from this string of code, however in OpenSCAD things are little different and reads the entire code first, assigns all the variables then produces objects. In this case C=8. There is a way around this however, making use of scopes. A simple way of explaining a scope is that regions within a pair or { ...} can be considered separately, and any variables defined within these braces do not exist outside, however just placing your code within {...} would just be ignored, but if you are creating a union, or some other modification to an object then you can define the variables within the scope.

The next useful programming feature of OpenSCAD is the ability to define modules, which allows you to in essence create your own custom shapes, not just the basic shapes we have created so far. If you are familiar with functions in other languages, this would be the closest example in OpenSCAD. Lets look at an example of how we do this :



module starburst(radius,width){
 intersection(){
  union(){
   cylinder(r=width,h=radius, center = true);
   rotate([90,0,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([0,90,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([45,0,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([0,45,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([45,45,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([-45,0,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([0,-45,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([-45,-45,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([45,-45,0]){
    cylinder(r=width,h=radius, center = true);
   }
   rotate([-45,45,0]){
    cylinder(r=width,h=radius, center = true);
   }
  }
  sphere(d=radius);
 }
}

$fn=100;
starburst(10,1);

translate([0,20,0]){
 starburst(5,0.5);
}

So first to define a new module we simply write module modulename(variable1,variable2,...){...}, with modulename the name you wish to use to call the module later on. We can also define here any parameters we would like to use for the module, so in the examle abouve we define both the radius of the starburst and the width of the cylinders that make up the starburst. The module can then be called by typing modulename(...); just like you would a basic object.

The above code is also a good example of the use of scopes, as you can see the values we use for radius and width for the first object do not effect those on the second time we call, where as if we were to use


a=10;
b=1;
starburst(a,b);
a=20;
b=0.5;
translate([0,20,0]){
 starburst(a,b);
}


Then we get two identical copies as the values of a and b are over written.

OpenSCAD also alows you to use mathematical functions as part of the code, there are a lot of available math function, for a complete list go to https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Mathematical_Operators , but these can be used to make variables, and dimensions that relate to each other rather than simply having a fixed value.

As a final additional programming tool for you to use, as with most other programming languages there are a few looping and conditional statements that can be used to help make a variety of objects. Lets start with a simple for loop



for (i=[-10:1:10]){
 for (j=[-10:1:10]){
  translate([i,j,0]){
   cube([1,1,sqrt(i*i + j*j)]);
  }
 }
}

The for(iterator){...} command takes a list of objects (in this case i=[-10:1:10]) and passes for each item in the list performs the contents of the {...}. The iterator part in the example is simply a short hand way of defining a list of all the numbers between -10 and 10 in steps of one, [start,step,end]. If the step size is in steps of one, the value of the step size can be omitted and written simply as [start,end]. The above example can also be shortened by combining the two above loops into a single command



for (i=[-10:10],j=[-10:10]){
 translate([i,j,0]){
  cube([1,1,sqrt(i*i + j*j)]);
 }
}

We can also explicitly define the list of number we wish to iterate for example



for (i=[1,1,2,3,5,8,13]){
 translate([i,i,0]){
  cube(1);
 }
}

We can also iterate over a list of vectors rather than defining a range of numbers to iterate over.



for (i=[[-1,-1,-1],[0,0,0],[1,1,1]]){
 translate(i){
  cube(0.5);
 }
}

Note that each vector is within its own set of [...] and separated by commas. OpenSCAD also has another form of for loop, called intersection_for(...){...}, The best way to describe what this does is you create the objects in the for loop, and then take the volume which appears as part of all the objects.

OpenSCAD can also use if(...){...}else{...} statements to decide what action to perform. This is especially useful in loops when want to change the behaviour depending on the value of the iterator.



for (i=[-10:10]){
 translate([i,0,0]){
  if (i < 0){    cube([0.5,0.5,0.75]);   }   else {    cube([0.5,0.5,1.5]);   }  } }

These programming tools should be enough to make designing objects in OpenSCAD easier when you have a large number of related parts to make.

Share This:

Leave a Reply

Your email address will not be published. Required fields are marked *