API Reference
Nodes
All node classes are importable from solid_node.node. A project is a
tree of nodes: leaf nodes generate solids with an underlying modelling
library, internal nodes combine their children.
Common node API
- class solid_node.node.base.AbstractBaseNode(*args, name=None, **kwargs)
A mechanical project in solid-node is represented by a tree, and this is the abstract base class for all nodes. Above this class, there are two other base classes: LeafNode and InternalNode.
- render()
Every node must implement
render(). Leaf nodes return an object of the underlying modelling library; internal nodes return a list of child node instances.
- rotate(angle, axis)
Rotate this node by
angledegrees around the vectoraxis(a list of three numbers, e.g.[0, 0, 1]). Operations accumulate and are applied both in the viewer and to the mesh used by tests. Returns the node itself, so calls can be chained.anglemay be an expression involvingAssemblyNode.time.
- translate(translation)
Translate this node by the vector
translation, a list of three numbers, e.g..translate([100, 0, 0]). Likerotate(), the operation accumulates and the node itself is returned.
- fn
Number of facets used to approximate curved surfaces, applied as OpenSCAD’s
$fnto the generated code. Only meaningful for OpenSCAD-based nodes (Solid2Node,OpenScadNode); CadQuery exports its own high-resolution STL. Default isNone, which keeps OpenSCAD’s coarse default.
- name
The node’s name, used in viewer and test failure messages. Defaults to the class name; can be overridden with the
namekeyword argument of the constructor.
- set_keyframe(time)
Set a fixed time for keyframes and tests. No-op for non-animated nodes; overridden by AssemblyNode.
- assemble(root=None)
Renders this node and returns an optimized version with all operations applied
- property mtime
Maximum mtime in source file of all nodes rendered inside this one
Leaf nodes
- class solid_node.node.leaf.LeafNode(*args, name=None, **kwargs)
This is a base class for all leaf nodes, which are nodes that generate solid structures. Each LeafNode subclass uses a different technology to generate a solid, and outputs the result as STL. LeafNode subclasses are in the solid_node.node.adapters.* namespace.
- property time
Raise an exception, as leaf nodes cannot rely on time. Implementing a FlexibleNode is in the roadmap
- class solid_node.node.Solid2Node(*args, name=None, **kwargs)
Represents a 3D object created using the SolidPython2 tool.
- as_number(n)
Receives a solid2 function result and calculates its number. uses an openscad process internally to do the calculation.
- class solid_node.node.CadQueryNode(*args, name=None, **kwargs)
Represents a 3D object created using the CadQuery tool.
- class solid_node.node.OpenScadNode(*args, name=None, **kwargs)
A pure OpenScad node. You just need to declare the property “scad_source” with the path of your OpenScad source code. It must be placed in the same directory of the python file containing this node.
The scad file must contain a module with the same name of the file, or you may specify the property “module_name” with the module name.
- scad_source
Path of the OpenScad source file, relative to the directory of the python file declaring the node.
- module_name
Name of the module to call inside
scad_source. Defaults to the file name without the.scadextension.
- __init__(*args, name=None, **kwargs)
Receives args, an optional name keyword argument and a list of keyword arguments. The list of arguments and keyword arguments will be passed as parameter to the module.
- Parameters:
*args – will be passed as arguments to the OpenScad module
argument (name keyword) – the name of this node, defaul to name of the class
**kwargs – will be passed as keyword arguments to the openscad module
- class solid_node.node.JScadNode(name=None)
A JScad node. You just need to declare the property “jscad_source” with the path of your JScad source code. It must be placed in the same directory of the python file containing this node.
You need to have jscad cli tool installed in $PATH, and node dependencies installed in the directory you are running solid from.
- jscad_source
Path of the JScad source file, relative to the directory of the python file declaring the node. The file must export a
mainfunction.
Internal nodes
- class solid_node.node.internal.InternalNode(*args, name=None, **kwargs)
Internal nodes combine its children nodes in some way to make a node with several solids.
- class solid_node.node.AssemblyNode(*args, name=None, **kwargs)
Represents a collection of components that can be moved relative to each other. This is an internal node that can contain instances of LeafNode or other internal nodes. The render method of this class returns a list of its child nodes.
- set_keyframe(time)
Set a fixed time for keyframes and tests, propagating it down the tree so nested assemblies render numerically too.
- property time
The $t variable, the animation time from 0 to 1
- class solid_node.node.FusionNode(*args, name=None, **kwargs)
Represents a fusion of components into a single, inseparable unit. This is an internal node that can contain instances of LeafNode or other FusionNode. The render method of this class returns a list of its child nodes.
- property time
You can’t use self.time with a FusionNode, as the resulting object is expected to be rigid.
Testing
The testing API lives in solid_node.test. See
Test-driven CAD for a walkthrough of both ways of
writing tests: mixing TestCaseMixin into a node class, or writing a
TestCase in a separate file.
- class solid_node.test.TestCase(methodName='runTest')
- assertBlockedBeyond(node, angle, against, axis=None, volume_epsilon=0.0, along=None, directions='both')
Torque-fit / linear-stop engagement contract: perturbed by angle degrees about axis (rotation mode, the default, axis=(0, 0, 1) when omitted) or by angle mm along the unit vector along (translation mode – give one selector or the other, never both), node must intersect against – the fit must genuinely lock beyond its play. See the class comment above for the local-frame semantics shared by both modes.
directions (default ‘both’) checks +angle and -angle separately, and BOTH must foul. ‘forward’ checks only +angle – for contracts that are deliberately one-sided (e.g. a sleeve blocked sliding inward by a lip, but free to slide outward). Any other value is a loud error.
volume_epsilon (mm^3, default 0.0 keeps exact is_empty strictness): when > 0, a perturbation only counts as blocked if the fouling volume exceeds volume_epsilon – so a flush contact that produces boolean noise (see assertNoPairwiseIntersections) never masquerades as a genuine lock in either direction.
- assertClose(node1, node2, max_distance)
Make sure the distance of node1 to node2 is lesser than max_distance
- assertFar(node1, node2, min_distance)
Make sure the distance of node1 to node2 is greater than min_distance
- assertFreeWithin(node, angle, against, axis=None, volume_epsilon=0.0, along=None, directions='both')
Anti-gaming twin of assertBlockedBeyond: perturbed by angle degrees about axis (rotation mode, the default) or by angle mm along the unit vector along (translation mode – give one selector or the other, never both), node must NOT intersect against – so a blocking test elsewhere cannot be gamed by an oversized bore/pocket/sleeve that never truly touches. angle accepts a list/tuple in either mode (e.g. a journal/freewheel sweep of angles, or a set of clearance distances), each checked in turn. See the class comment above for the local-frame semantics shared by both modes.
directions (default ‘both’) checks +angle and -angle separately, and NEITHER may foul. ‘forward’ checks only +angle – for contracts that are deliberately one-sided. Any other value is a loud error.
volume_epsilon (mm^3, default 0.0 keeps exact is_empty strictness): when > 0, a perturbation only counts as fouling if its volume exceeds volume_epsilon, so flush contact within the play window (boolean noise, not real engagement) does not wrongly fail this assertion.
- assertInside(node1, node2)
Make sure node2 is completely inside node1
- assertIntersectVolumeAbove(node1, node2, min_volume)
Make sure the volume of the intersection between node1 and node2 is greater than min_volume.
- assertIntersectVolumeBelow(node1, node2, max_volume)
Make sure the volume of the intersection between node1 and node2 is lesser than max_volume.
- assertIntersecting(node1, node2)
Make sure node1 and node1 have some intersection
- assertNoPairwiseIntersections(node, volume_epsilon=0.0)
Walk the assembled tree rooted at node down to its leaves (a node with no children is a leaf; every other node’s children are walked recursively) and assert that every pair of leaves is non-intersecting. The safety net that holds regardless of which specific contracts exist: any two parts someone forgot to test against each other directly are still covered here.
volume_epsilon (mm^3, default 0.0 keeps exact is_empty strictness): two parts that legitimately abut flush (e.g. shaft segments whose end faces meet exactly) can produce a non-empty boolean of pure float noise – a sliver mesh with volume on the order of 1e-13 mm^3, indistinguishable to is_empty from real interference. When volume_epsilon > 0, an intersection only counts as real interference if its volume exceeds volume_epsilon; a genuine overlap comfortably above the epsilon is still reported.
- assertNotIntersecting(node1, node2)
Test that node1 and node 2 do not intersect
- set_node(node)
This sets the “node” property on the test, and also an alias matching the class name, for testing convenience.
- class solid_node.test.TestCaseMixin(methodName='runTest')
For convenience, nodes can inherit TestCaseMixin to implement tests together with rendering logic.
- solid_node.test.testing_steps(steps, start=0, end=1)
Use this decorator to run the test in several steps of the animation. Use start and end to define the range in that will be divided in those steps.
- solid_node.test.testing_instant(instant)
Use this decorator on a test to define a specific instant of the animation that should be used to run the test
Decorators
- solid_node.node.decorators.property_as_number(method)
Use this decorator to convert a OpenScad property to a number