Skip to content
Leeroy edited this page Jul 25, 2018 · 21 revisions

relativity.scad uses parent-child relationships to express alignments between objects in space. However, the same sorts of relationship are used by the built-in openscad modules to express CSG operations like difference, intersection, and hull. This presents a problem when you want to perform CSG operations between a parent object and its child.

Enter the CSG operations.

CSG operations in relativity.scad follow the same naming convention that's used throughout the library - take the name of the built in module and use the past tense to find the equivalent in relativity.scad. As an example, the differed() function is a stand in for difference in vanilla OpenSCAD.

All CSG operations work by specifying the class of objects on which they should operate. Object class is assigned through a special variable, $class. Classes should be a familiar concept to anyone who's spent some time in html, css, jquery, etc., but if they aren't, no worries - just read on.

show

show(class)

show() will exclusively render primitives that match the class selector you provide.

Render Code
show("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

hide

hide(class)

hide() will exclusively render primitives that do not match the class selector you provide. Its implementation is complementary to show() - show("not(foo)") is functionally equivalent to hide("foo").

Render Code
hide("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

differed

differed(negative, positive="*", unaffected=undef)

differed() takes two arguments: the first argument gives the class name for objects representing negative space, the second argument gives the class name for objects representing positive space.

Render Code
differed("hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

An additional parameter, unaffected, specifies the class or classes that should be unaffected by the presence of negative space. By default, unaffected is set to any class that is not already covered under the positive or negative parameters.

In essence, differed() can be thought of as follows:

module differed(negative, positive, unaffected){
	difference(){
		show(positive)
			children();
		show(negative)
			children();
	}
	show(unaffected)
		children();
}

hulled

hulled(class="*")

hulled() takes a single argument expressing an object class. hulled() finds all primitives with that class and performs a hull operation over them. Everything not specified by the class selector is left untouched.

Render Code
hulled("hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

In essence, hulled() can be thought of as follows:

module hulled(class){
	hull()
	show(class)
	children();

	hide(class)
	children();
}

intersected

intersected(class1, class2, unaffected=undef)

intersected() takes two arguments expressing object class. intersected() finds all primitives with those classes and performs an intersection between them.

Render Code
intersected("hole", "not(hole)")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

An additional parameter, unaffected, specifies the class or classes that should render as if no intersection was applied. By default, unaffected is set to anything that is not covered by the class1 or class2 parameters.

rotated

rotated(offset, n=[1], class="*")

When only offset is provided, rotated() is equivalent to the built-in rotate() operation.

Render Code
rotated(22*z, class="hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

An additional parameter, n, can be used to form repeating patterns through rotation. Each child will be copied multiple times, and each copy will rotate at an angle that is equal to n[i] * offset, where i is an index within the list, n.

If class is supplied, a child object will only rotate if its class matches the selector provided through the class parameter.

translated

translated(offset, n=[1], class="*")

When only the offset parameter is supplied, translated() works exactly like the built-in translate() operation.

Render Code
translated(10*z, class="hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

An additional parameter, n, can be used to form repeating patterns through translation. Each child will be copied multiple times, and each copy will translate at by an offset that is equal to n[i] * offset, where i is an index within the list, n.

If class is supplied, a child object will only translate if its class matches the selector provided through the class parameter.

scaled

scaled(v=[0,0,0], class="*")

scaled() takes two aruments. The first argument is a vector expressing an amount to scale. The second argument expresses an object class. Child objects of matching class are scaled by the desired amount.

Render Code
scaled(0.95, "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

Using scaled() does not modify the position of objects whose class does not match the selector. Take note of this if you are constructing an object that relies upon the accurate alignment of primitives!

resized

Render Code
resized([47,47,47], "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

mirrored

mirrored(axes=[0,0,0], class="*")

mirrored() can be used to form objects with bilateral symmetry.

Render Code
 mirrored(y) 
rotated(22*z, class="hole")
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

mirrored() takes two arguments. The first argument is a vector indicating a 2D plane. The second argument expresses a class of object. mirrored() copies objects of that class and then flips one of the copies along a desired axis.

colored

colored() can be used to selectively color portions of an object.

Render Code
colored("red", "hole") 
ball(50)
orient([x,y,z])
rod(d=25, h=50, $class="hole");

colored() takes two arguments. The first argument is a string or vector indicating color. The second argument expresses a class of object. colored() selectively colors primitives matching that object class, leaving the others untouched.

attach

attach(to)

New to version 2015.02.14. attach() is just an all-around neat function. attach() enables you to create a module with multiple references to the children() operator. When it comes time to invoke the module, you can pick and choose which of these references will handle the child modules you pass.

This can be clarified with an example. First, we set up a module that invokes the children() operator at multiple locations. Each invocation has its own value for $class:

module motor(){
	box(42, $class="stator")
	align(top)
	{
	    rod(d=22,h=10, $class="rotor")
	    children();
	    
	    translated(31*y, [-1,1]/2) 
	    translated(31*x, [-1,1]/2) 
	    rod(d=3,h=10, $class="screw")
	    children();
	}
}

We then invoke the newly created module, passing it children. For each child, we invoke the attach() module with a selector. This indicates where we wish to place the child.

differed("not(wrapper)")
hulled("wrapper")
motor(){
	attach("rotor")
	rod(d=30,h=10, $class="wrapper");
	
	attach("screw")
	rod(d=10,h=10, $class="wrapper");
}

In this example we've created a mount for our motor module. The Motor Mount tutorial provides an in-depth version of this example.

attach() works by selectively displaying its children, showing child modules only when the parent of attach() matches a given selector. In short, this:

attach("foo")

is equivalent to this:

show("foo *")

An interesting consequence of this behavior means you can also use attach to render the child module exclusively. This is done by calling attach() before invoking the parent class:

attach("rotor,screw")
motor(){
	
	rod(d=30,h=10, $class="wrapper");
	
	attach("screw")
	rod(d=10,h=10, $class="wrapper");
}

Classes

Object class is assigned through a special variable, $class. $class by convention is a string variable expressing the space delimited classes that are associated with an object. In css, compound words are "dash-delimited" by convention, however "underscore_delimited" and "CamelCase" conventions are also possible in relativity.scad. As with other special variable, $class will be inherited from a parent unless explicitly stated otherwise.

On its own, a class doesn't affect the render in any way. It's only through modules like differed() that a class gets its meaning.

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"
Note the lack of whitespace
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.png 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.

A note on selector tags

The similarities between relativity and CSS might lead one to believe they can search for objects in relativity with the help of selector tags such as "." or "#". While this is a really cool idea, it is currently unimplemented to avoid confusing users who are not familiar with CSS. I expect this will change if there turns out to be sufficient demand for this feature.

Clone this wiki locally