Skip to content
Lytigas edited this page Nov 12, 2017 · 76 revisions

The OpenSCAD General Library of Relativity

Table of Contents

Installation
Primitives
Centering
Alignment
Orientation
Sizing
Styling
Demos

Installation

To use the library on your own machine, download "relativity.scad" from the project page on Thingiverse. This will get you the latest stable release. Alternatively, you can download the latest unstable release of relativity.scad from the root folder of the project page on github.

Once you download the file, place it in the OpenSCAD folder on your machine. The location of this folder varies by operating system. Start OpenSCAD and type the following:

include <relativity.scad>

Its important you import relativity using the "include" keyword. relativity.scad needs to declare variables during its initialization. If you import relativity.scad with the "use" keyword, OpenSCAD will not load these variables, and strange behavior will result!

Primitives

This OpenSCAD library adds functionality to size, position, and orient objects relative to other geometric primitives.

To do so, the library introduces a new set of modules to replace the default geometric primitives in OpenSCAD:

Render Module Replaces
box cube
rod cylinder
ball sphere

All the original geometry primitives are still there if you need them, and you can decide how much or how little to use them. The new primitives have most all the behavior of their old counterparts, but with two important distinctions.

Centering

First, in place of center is a new attribute, anchor. This attribute specifies where the axis of rotation is to be placed relative to the object. The anchor attribute is given as a vector whose elements range from -1 (e.g. bottom of axis) to 1 (e.g. top of axis). A value of 0 indicates the anchor is to be centered along an axis.

+1 0 -1
X anchor = [1,0,0] anchor = [1,0,0] anchor = [0,0,0] anchor = [0,0,0] anchor = [-1,0,0] anchor = [-1,0,0]
Y anchor = [0,1,0] anchor = [0,1,0] anchor = [0,0,0] anchor = [0,0,0] anchor = [0,-1,0] anchor = [0,-1,0]
Z anchor = [0,0,1] anchor = [0,0,1] anchor = [0,0,0] anchor = [0,0,0] anchor = [0,0,-1] anchor = [0,0,-1]

Alignment

The second distinction among these new primitives allows for the creation of child objects. By default, a child object is positioned with its origin at the center of its parent:

box(50, anchor=[0,0,-1])
    sphere(d=55);

this however can be changed using of a second operation, align:

box(50, anchor=[0,0,-1])
    align([0,0,1])
    sphere(d=60);

You can align objects along any axis. The value passed to align() is a vector whose elements range from -1 (e.g. bottom of axis) to 1 (e.g. top of axis). A value of 0 indicates an object is to be placed at the center of its parent along that axis.

+1 0 -1
X align([1,0,0]) align([1,0,0]) align([0,0,0]) align([0,0,0]) align([-1,0,0]) align([-1,0,0])
Y align([0,1,0]) align([0,1,0]) align([0,0,0]) align([0,0,0]) align([0,-1,0]) align([0,-1,0])
Z align([0,0,1]) align([0,0,1]) align([0,0,0]) align([0,0,0]) align([0,0,-1]) align([0,0,-1])

You can also pass a list of vectors. When you pass a list of vectors, align() will create duplicates of its children in the locations indicated by your vectors.

box(50, anchor=[0,0,-1])
    align([[0,0,1], [0,1,0]])
    sphere(d=60);

The examples above use sphere() as their child object. However, ball() can also be be used as a child. Using ball() will allow us to combine align() and anchor, making it easy to stack objects end-to-end:

box(50, anchor=[0,0,-1])
align([0,0,1])
ball(50, anchor=[0,0,-1])
align([0,0,1])
rod(50, anchor=[0,0,-1]);

To allow for readable code, relativity.scad comes with a few constants representing commonly used values for the align operator:

top = [0,0,1];
center=[0,0,0];
bottom = [0,0,-1];
x = [1,0,0];
y = [0,1,0];
z = [0,0,1];

It is also possible to combine this constant with + or - operators, since OpenSCAD does (simple) vector calculations.

There are also two special variables that are exposed by the align() module, $inward and $outward. $inward points towards the center of a parent object, while $outward points away from it.

The anchor parameter defaults to $inward. This is meant to facilitate stacking objects. All told, the code above can be rewritten:

box(50)
align(top)
ball(50)
align(top)
rod(50);

Orientation

Child objects by default will maintain the same z-axis orientation as their parent objects

box(50, anchor=[0,0,-1])
align([0,1,0])
rod(d=50, h=50, anchor=[0,-1,0]);

This, however, can be changed with the use of another module, orient. The orient module will redirect the top of a child object to face a given direction. Sometimes rotation using orient can be more intuitive than using rotate

box(50, anchor=[0,0,-1])
align([0,1,0])
orient([0,1,1])
rod(d=50, h=50, anchor=[0,0,-1]);

You can also pass a list of vectors to orient. In this case, orient will create duplicates of its children with their tops facing the directions you specify in the list.

//OpenSCAD logo:  
differed("hole", "not(hole)")  
ball(50)  
orient([x,y,z])  
rod(d=25, h=50, $class="hole");  

Sizing

relativity.scad exposes a dynamic variable, $parent_size, in case there are any unforeseen circumstances where something needs to be done relative to a parent object. This can also be used when setting the size of a child, say, when creating a fractal:

box([50,50,50])
align(top)
box(0.8*$parent_size)
align(top)
box(0.8*$parent_size);

The tree demo provides a good example for the parent() and $parent_size functionality.

To ease the use of $parent_size, geometric primitives for rod and ball accept size as their first parameter argument, much like cube and box.

rod([50,50,50])
align(top)
rod(0.8*$parent_size)
align(top)
rod(0.8*$parent_size);

An interesting consequence to this means you can pass rod and ball different values for x,y, and z:

rod([50,50,50])
align(top)
rod([$parent_size.x*.5, $parent_size.y*.7, $parent_size.z*.9])
align(top)
rod([$parent_size.x*.5, $parent_size.y*.7, $parent_size.z*.9]);

Another, more unfortunate side effect means rod does not currently support multiple diameters/radii through the d1 and d2 parameters. This may change as need arises. You can still use the original cylinder primitive when circumstances call for it, but a better idea might be to perform the hull between two rods, one of infinitesimal height.

hulled() rod(d=30, h=infinitesimal) rod(d=10, h=20);

Styling (AKA "CSG")

Relativity.scad transforms the way you work with objects in OpenSCAD. You'll find yourself working a lot more with "tree-like" structures, where geometric primitives nest inside one another. This is similar to the way you write using nested tags in html. Just like html, there is a system for performing operations on the tree-like structure. In html, there's css. In relativity, there's the CSG operations:

Module Demo Code
differed
differed("hole","not(hole)") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
hulled
hulled("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
intersected
intersected("hole", "not(hole)")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
show
show("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
hide
hide("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
colored
colored("red", "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
scaled
scaled(0.95, "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
resized
resized([47,47,47], "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
mirrored
 mirrored(y) 
rotated(22*z, class="hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
rotated
rotated(22*z, class="hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");
translated
translated(10*z, class="hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

Selectors

Selectors are the means through which CSG operations specify class. Selectors are strings whose format is meant to resemble a subset of CSS selector syntax.

Illustrations below uses the following code:

colored("blue", ...)
ball(50, $class="parent")
{
    align(x)
    ball(40, $class="child A")
    align(x)
    ball(30, $class="grandchild");
    
    align(z)
    ball(40, $class="child B")
    align(z)
    ball(30, $class="grandchild");
    
    align(-x)
    ball(40, $class="child C")
    align(-x)
    ball(30, $class="grandchild");
}

As of version 2015.02.14, selectors support the following syntax:

Selector Description Comments
* selects all primitives
A,B Selects all primitives of class "A" or "B"
not(A) Selects all primitives where $class does not contain "A"
child.A Selects all primitives both of class "child" and "A". NOTE: this differs from CSS, where "." indicates a selection based on class
parent grandchild Selects all primitives of class "grandchild" with any ancestor of class "parent"
parent>grandchild Selects all primitives of class "grandchild" whose parent is of class "parent". All "grandchild" objects have "child" objects as their parent, so no object is selected.
parent child,B grandchild Note how operators are applied - operators are applied left to right. There is no order of operation.
(parent child),B grandchild Selects two types of primitives. The first type is of class "grandchild" with ancestor of class "A". The second type is of class "grandchild" with ancestor of class "B". NOTE: Normal operator precedence is overridden by parentheses, unlike CSS.

Note that syntax shown above may be subject to change. This is particularly the case where incongruities exist with the CSS selector syntax.

Demos

Link Render Description
Tree A fractal tree rendered using parent() and mirrored()
Stepper Motor A high fidelity NEMA-17 stepper motor written in 50 lines of code
Motor Mount A stepper motor mount made easy with attach()
Human Body A human body designed using techniques in classical figure drawing. Work in progress. Not for the faint-hearted.
Flower
Centipede