OpenSCAD Tutorial/Chapter 9

Doing math calculations in OpenSCAD
So far you have learned that OpenSCAD variables can hold only one value throughout the execution of a script, the last value that has been assigned to them. You have also learned that a common use of OpenSCAD variables is to provide parameterization of your models. In this case every parameterized model would have a few independent variables, whose values you can change to tune that model. These variables are usually directly assigned a value as in the following examples.

Another thing that you have seen a few times already, but which has not been mentioned explicitly is the ability to perform mathematical operations using variables and hard-coded values in your script. One example of this is in implementing the car's wheelbase. Recall that the car's axles and wheels were translated along the X axis and away from the origin by half the value of the wheelbase. Since in this case the wheelbase is a variable that has already been defined in your script, you can calculate the amount of units by dividing the wheelbase variable by two. A similar thing was done with the track variable to place the left and right wheels of the car. Recall that the left and right wheels were translated along the Y axis and away from the origin by half the value of the track.



Addition, subtraction, multiplication and division are represented in OpenSCAD with the signs +, -, * and /. Apart from these fundamental operations, there are also a number of additional mathematical operations that can be useful when building more complex models. Two examples of this are the cosine and sine functions that you used to define a circular pattern of cars. Specifically, you used the cosine and sine functions to transform the polar coordinates of each car into Cartesian coordinates in order to translate it in its proper position. You can find all available math functions briefly listed in the cheat sheet.



In the above case you are not only using available mathematical operations in your script, but you are also defining two additional variables dx and dy to store the result of your calculations in order to increase the readability of your script. This is something that could also be done in your car models. Take for example the following car model.



In the above model, mathematical operations are used to calculate the required amount of translation for each wheel and axle along the X and Y axis.



Creating any 2D object with the polygon primitive
Aside from the circle and square 2D primitives, there is another primitive that lets you design practically any 2D object. This is the polygon primitive, which lets you define 2D objects by providing a list that contains the coordinates of their points. Let’s say you want to design the following 2D part.



One way to go about designing this part without using the polygon primitive would be to start from a square that corresponds to the outer dimensions of this part and then subtract a properly rotated and translated square from its top right corner. Calculating the proper angle of rotation and amount of translation would be a time-consuming task. Additionally, following this strategy for a more complex object wouldn’t be possible. Instead, you can create this object using the polygon primitive in the following way.



There are a few things you should notice regarding the use of the polygon primitive. The polygon primitive uses a list of points as inputs. The points, or vertices, are represented using pairs of X and Y coordinates, and are provided in order. When defining the list, you may start with any vertex you like and you can traverse them in either a clockwise or counterclockwise order. In the example above, the first vertex is at the origin (0,0), while the remaining vertices are listed in a clockwise direction. All vertices (pairs of X and Y coordinates) p0, p1, …, p4 are placed inside a list named points. This list is then passed to the polygon command to create the corresponding object.

Whether a variable has only a single value or it’s a list of values, you can print its content on the console using the echo command.

The output in the console is: 0, 0], [0, 30], [15, 30], [35, 20], [35, 0

Naming each point separately (p0, p1, …) is not required but it’s recommended to better keep track of your design. You could also directly define the list of points to be passed to the polygon command.

Moreover, you don’t even have to define a variable to store the list of points. You can directly define the list of points when calling the polygon command.

The above practices are not recommended. Instead the use of additional variables as in the first example is encouraged in order to make your scripts more readable and extendable.

You could also parameterize the definition of the points’ coordinates according to the given dimensions, which will give you the ability to rapidly modify the dimensions of your object. This can be achieved by introducing one variable for each given dimension and by defining the coordinates of the points using appropriate mathematical expressions.









Challenge
It’s time to use your new skills to create the body of a racing car!









Creating more complex object using the polygon primitive and math
From the above examples it should be quite obvious that the polygon primitive opens up possibilities to create objects that would hardly be possible by just using the fundamental 2D or 3D primitives. In these examples you created custom 2D profiles by defining the coordinates of their points according to a given design. To unlock the true power of the polygon command though, and to create even more complex and impressive designs, you have to programmatically define the points of your profiles using math. This is because defining each point separately is not scalable to the hundreds of points that are required to design smooth non-square profiles. One example of this is the following heart. Can you manually define the required points to create it? There is no way.



Instead of manually defining each point, which would be practically impossible, this model was programmatically defined using the following parametric equations.

x = 16&sdot;sin⁡(t)3 y = 13&sdot;cos⁡(t) − 5&sdot;cos⁡(2&sdot;t) − 2&sdot;cos⁡(3&sdot;t) − cos⁡(4&sdot;t)

When the range of the t variable covers values from 0 to 360 degrees, the above equations give the X and Y coordinates for the outline of the heart, starting from the top middle point and moving in a clockwise direction. Using the above equations, a list that contains each point’s coordinates can be generated in the following way.

There are a few things you should notice about the syntax of list generation. First the name of the variable where the list will be stored is typed out. Then follows the equal sign (as in every variable assignment) and a pair of square brackets. Inside the pair of square brackets, the first thing that is typed out is the keyword for. After the keyword for follows a pair of parentheses inside of which the consecutive values that the corresponding variable is going to take are defined. This variable is similar to the for loop variable encountered in for loops. The number of elements that the generated list is going to have is equal to the number of values that this variable is going to take. For every value that this variable takes, one element of the list is defined. What each element of the list is going to be, is specified after the closing parenthesis. In this case each element of the generated list is itself a list that has two elements, one for each coordinate of the corresponding point. The t variable goes from 0 to 360 which is the required range to produce the whole outline of the heart. Since the polygon shouldn't include duplicate points, 359.999 is used instead of 360. By choosing a smaller or bigger value for the step variable, the amount of points that will be created can be controlled. Specifically, in order to create n points the step variable needs to be defined in the following way.

Putting all these together, the heart can be created with the following script.



You can see that by using 500 points the resolution of the outline is very good.



Using more or less points is up to you. If you want to create an object that closely resembles the underlying mathematical equations, you should increase the number of points. Instead, if you opt for a low poly style you should decrease the number of points.

Solution for exercise i, [1, 2, 3, 4, 5, 6]:

Solution for exercise ii, [10, 8, 6, 4, 2, 0, -2]:

Solution for exercise iii, 3, 30], [4, 40], [5, 50], [6, 60:

Note that when no step is provided, a default of 1 is used.

OpenSCAD also allows you to define your own mathematical functions, which can be useful when a mathematical expression is particularly long, or when you would like to use it multiple times. These functions work similarly to modules, except that instead of defining a design they define a mathematical process. After a function has been defined, you can use it by invoking its name and providing the necessary input parameters. For example, you can define a function that accepts the parameter t, and returns the X and Y coordinates of the corresponding point of the heart's outline.

In this case the script that creates the heart would take the following form.

There are a few things you should notice about the definition of a function. First the word function is typed out. Then follows the name that you want to give to the function. In this case the function is named heart_coordinates. After the name of the function follows a pair of parentheses that contains the input parameters of the function. Like module parameters, the input parameters in a function can have default values. In this case, the only input parameter is the polar angle of the current step t and it’s not given a default value. After the closing parenthesis follows the equal sign and the command that defines the pair of X and Y coordinates of the heart’s outline.

The generation of the list of points can also be turned in a function. This can be done in a similar fashion as follows.

In this case the script that creates the heart would take the following form.

In short you should remember that any command that returns a single value or a list of values can be turned into a function. Like modules, functions should be used to organize your designs and make them reusable.

Another challenge
You are going to put your new skills into practice to create an aerodynamic spoiler for your racing car!