If, like me, you are better at manipulating code than manipulating a graphical editor this is going to be a very useful tool when you are creating 3D objects for printing. The OpenSCAD 3D Modeller allows you to describe an object using a language very similar to C or Javascript.

As well as providing statements to create basic primitives (sphere, cube, cylinder, etc) and to perform common transforms (scale, rotate and translate) the application has full support for constructive solid geometry (**CSG**). This feature allows you to build up complex shapes by combining primitives using set operations such as union, intersection or difference. Code can be edited interactively with the final 3D view being shown in an adjacent window allowing for a very quick workflow with rapid feedback for any modifications of the model.

The OpenSCAD language supports functions (which allow the calculation of a value from a set of parameters) and modules (effectively procedures that allow re-using a sequence of common operations with parameters to control the output). The code example that follows uses a module to generate a triangular wedge with parameters controlling the dimensions of the wedge:

```
/** Create a triangle * * The middle of the base is at origin (0, 0, 0) and the tip of the triangle * points along the Y axis. */ module triangle(width, height, depth) { angle = atan(height / (width / 2)); difference() { translate(v = [ 0, height / 2, 0 ]) { cube(size = [ width, height, depth ], center = true); } translate(v = [ width / 2, 0, 0 ]) { rotate(a = [ 0, 0, 90 - angle ]) { translate(v = [ width / 2, height, 0 ]) { cube(size = [ width, height * 2, depth ], center = true); } } } translate(v = [ -width / 2, 0, 0 ]) { rotate(a = [ 0, 0, 270 + angle ]) { translate(v = [ -width / 2, height, 0 ]) { cube(size = [ width, height * 2, depth ], center = true); } } } } }
// Example triangle(5, 10, 2);
```

As you would expect you can call modules from within modules which allows you to build more and more complex objects using an increasing set of building blocks. The code example below generates a *gear* using the *triangle* module show above to generate the teeth:

```
/** Generate a 'gear' with teeth made of isosceles triangles. * * Each tooth of the gear is a triangle where the width and height is * 'tooth_size'. */ module gear(teeth, tooth_size, depth = 2) { circumference = tooth_size * teeth; diameter = circumference / (22 / 7); angle = 2 * asin((tooth_size / 2) / (diameter / 2)); union() { for(step = [ 0 : teeth - 1 ]) { rotate(a = [ 0, 0, step * angle ]) { translate(v = [ 0, (diameter / 2) - tooth_size ]) { triangle(tooth_size, tooth_size, depth); } } } cylinder(h = depth, r = (diameter / 2) - (tooth_size * 0.9), center = true); } }
```

As you can see it helps to have a good understanding of basic trigonometric functions when building code for OpenSCAD.

As well as allowing you to define modules to perform common operations OpenSCAD lets you define your modules in external files and *#include* them in your main file much like a C style *#include* or a Python *import* statement. I have a collection of common operations that I maintain in a file called

``` /*----------------------------------------------------------------------------* * Defines common constants used throughout the AutoSCAD libraries. *-----------------------------------------------------------------------------* *----------------------------------------------------------------------------*/

//--- Constants

/** The value of Pi */ PI = 3.1415926535897932;

/** Printer resolution (in mm) */ RESOLUTION = 0.3;

/** Base size for objects (in mm) * * The library is designed to generate things in 'units' - this defines the * size of a unit (in mm). */ BASE_SIZE = 2;

//--- Modules

/** Create an isosceles triangle * * The middle of the base is at origin (0, 0, 0) and the tip of the triangle * points along the Y axis. Depth is in the Z axis and is centered on the * origin. If depth is not specified it defaults to 2 units. */ module triangle(width, height, depth = 2) { angle = atan(height / (width / 2)); difference() { translate(v = [ 0, height / 2, 0 ]) { cube(size = [ width, height, depth ], center = true); } translate(v = [ width / 2, 0, 0 ]) { rotate(a = [ 0, 0, 90 - angle ]) { translate(v = [ width / 2, height, 0 ]) { cube(size = [ width, height * 2, depth * 2 ], center = true); } } } translate(v = [ -width / 2, 0, 0 ]) { rotate(a = [ 0, 0, 270 + angle ]) { translate(v = [ -width / 2, height, 0 ]) { cube(size = [ width, height * 2, depth * 2 ], center = true); } } } } }

/** Create an arc * * Creates a slice of a cylinder that is 'width' along the X axis, 'height' * along the Y axis and 'depth' along the Z axis. The base (the flat part) * is centered on the origin. If 'depth' is not specified it defaults to * 2 units. */ module arc(width, height, depth = 2) { radius = ((width * width) + (4 * height * height)) / (8 * height); difference() { translate(v = [ 0, -(radius - height), 0 ]) { cylinder(h = depth, r = radius, center = true, $fs = RESOLUTION); } translate(v = [ 0, -radius, 0 ]) { cube(size = [ radius * 2, radius * 2, depth * 2 ], center = true); } } }

/** Calculates the height of a teardrop with a given radius */ function teardrop*length(td*radius) = td*radius + sqrt(2 * (td*radius * td_radius));

/** Generate a teardrop shape * * These shapes are useful for minimising print volume while maintaining * structural strength. */ module teardrop(td*radius, td*height = 1) { translate(v = [ 0, -(teardrop*length(td*radius) - td*radius), 0 ]) { rotate(a = [ 0, 0, 45 ]) { linear*extrude(height = td*height) { union() { circle(r = td*radius, $fs = RESOLUTION); square(size = [ td*radius, td*radius ]); } } } } }

/** Variation of the teardrop with a specified length * * This module allows you to specify the length of the teardrop shape as well * as the radius. */ module teardrop*scaled(td*radius, td*length, td*height = 1) { scale*factor = td*length / teardrop*length(td*radius); scale(v = [ 1, scale*factor, 1 ]) { teardrop(td*radius, td_height); } }

/** Create a hexagon. * * The 'size' parameter specifies the distance from the center of the * hexagon to the center of one of the six straight edges. The 'depth' * parameter specifies the size in the Z axis. The resulting object * is centered on the origin. */ module hexagon(length, depth = 2) { width = 2 * length * tan(30); union() { cube(size = [ length * 2, width, depth ], center = true); rotate(a = [ 0, 0, 60 ]) { cube(size = [ length * 2, width, depth ], center = true); } rotate(a = [ 0, 0, -60 ]) { cube(size = [ length * 2, width, depth ], center = true); } } }

/** Create a hexagon * * The 'radius' parameter specifies the radius of the smallest circle * that contains the hexagon. The 'depth' parameter specifies the size * in the Z axis. The resulting object is centered on the origin. */ module hexagonR(radius, depth = 2) { hexagon(radius * cos(30), depth); }

/** Create a hexagon * * This version of the hexagon module creates a hexagon where each * edge is of 'part' length. The 'depth' parameter specifies the * size in the Z axis. The resulting object is centered on the * origin. */ module hexagonL(part, depth = 2) { hexagon((part / 2) / tan(30), depth); }

/** Create a rounded rectangle */ module roundrect(width, height, depth, radius) { union() { // Make the four corner pieces translate(v = [ width / 2 - radius, height / 2 - radius, 0 ]) { cylinder(r = radius, h = depth, center = true); } translate(v = [ width / 2 - radius, -(height / 2 - radius), 0 ]) { cylinder(r = radius, h = depth, center = true); } translate(v = [ -(width / 2 - radius), height / 2 - radius, 0 ]) { cylinder(r = radius, h = depth, center = true); } translate(v = [ -(width / 2 - radius), -(height / 2 - radius), 0 ]) { cylinder(r = radius, h = depth, center = true); } // Add the center rectangles cube(size = [ width - (2 * radius), height, depth ], center = true); cube(size = [ width, height - (2 * radius), depth ], center = true); } } ``` . You are more than welcome to download and use this file for your own projects.

One issue I had with OpenSCAD was defining objects consisting of custom polygons (which are expressed in OpenSCAD using a list of vertex co-ordinates), the program is very touchy about the order of the vertices. There is an online tool called the OpenSCAD Polygon Builder which can help you work around this problem. You can also import files in other 3D formats as an object that can then be manipulated using all the normal OpenSCAD operations - this might be a better alternative depending on the complexity of your object.

OpenSCAD will export in a number of common 3D formats including STL and DXF. The STL format is the preferred input format for most 3D printers and there are a wide range of utilities you can use for post processing operations - reducing the polygon count or slicing an object into printable parts for example. Given that objects built up from geometric shapes tend to look very artificial one interesting free tool that will import STL is Sculptris which allows you to manipulate your model as if you were working with clay and add a more *organic* feel to it.

The Thingiverse online database of 3D things will often have OpenSCAD source files available for 3D printable objects (there are also a number of useful OpenSCAD libraries you can download and modify to develop your own objects). I have my own account on the site which will have almost all of the 3D printable objects designed here available for download.

Be sure to check out the OpenSCAD User Manual, keep a link to it as a desktop reference to design your own objects or to understand how other scripts work.