Named solid parts and reference geometry with explicit placement.
An assembly is a deferred value. Add members with part/4 and
reference/4, then call Smith.evaluate/1. Equal member recipes are
evaluated once per assembly evaluation; each member gets its own placement.
Use subassembly/4 to place another assembly and retain its members.
Equal leaf recipes share one evaluation across the entire tree. There is
no global cache. Named attachment frames and directed connections provide
rigid, revolute, linear, cylindrical, and ball poses; closed linkages are not solved.
iex> foot = Smith.box(10, 10, 4)
iex> recipe =
...> Smith.Assembly.new(:pair)
...> |> Smith.Assembly.part(:left, foot)
...> |> Smith.Assembly.part(:right, foot, position: {20, 0, 0})
iex> {:ok, assembly} = Smith.evaluate(recipe)
iex> {:ok, solids} = OCEx.solids(assembly.shape)
iex> length(solids)
2The evaluated compound contains installed manufactured parts, without
fusing them. References and installed: false extras are available
through fetch/2 but excluded from that compound. All members must
contain at least one solid.
See assemblies for print placement, separate part exports, metadata, and assembly reports.
Summary
Functions
Connects a moving attachment frame to a target frame.
Returns a member in final world coordinates.
Returns a named joint's evaluated world frame and owning member path.
Defines a named attachment frame on an immediate assembly member.
Lists all leaf members in depth-first insertion order.
Creates an empty named assembly recipe.
Adds a named manufactured part to an assembly recipe.
Adds named reference geometry that is excluded from print output.
Adds a named instance of another assembly.
Builds a geometry snapshot of an evaluated assembly for inspection.
Types
Functions
@spec connect(t(), member_path(), keyword()) :: t()
Connects a moving attachment frame to a target frame.
source and required to: are joint names or paths to joints in
nested instances. The source's top-level member moves as a rigid unit,
including all descendants, references, and extras. The target stays attached
to its member. Matching frames align both normals and X directions; there
is no implicit face-to-face reversal. Use opposing local planes when needed.
The connection overrides the source member's initial placement.
Motion options
kind: | Coordinates | Meaning |
|---|---|---|
:rigid (default) | none | Coincident frames |
:revolute | angle: | Rotation around target local Z, degrees |
:linear | offset: | Translation along target local Z, mm |
:cylindrical | angle:, offset: | Both motions |
:ball | angles: {x, y, z} | Rotations about fixed target X, then Y, then Z, degrees |
All coordinates default to zero. Optional limits: supplies inclusive
{min, max} pairs keyed by :angle/:offset, or by
:x/:y/:z for a ball. Unspecified limits are unbounded.
Out-of-range values return :joint_limit; they are not clamped.
Each moving member may have one connection. Dependencies are resolved in target-first order, independent of declaration order. Self-connections, multiple connections for one member, and cycles fail explicitly. Connections inside a subassembly resolve before parent-level connections move that instance. This calculates a pose, not a physical simulation or general constraint solver; collisions, clearances, loads, and closed linkages are not solved.
@spec fetch(Smith.Assembly.Result.t(), member_path()) :: {:ok, Smith.Result.t() | Smith.Assembly.Result.t()} | {:error, :unknown_part}
Returns a member in final world coordinates.
Works for manufactured parts, uninstalled printable extras, and references.
Atom and string names match after underscores become hyphens. Unknown
names return {:error, :unknown_part}. Print and display transforms
do not affect the fetched geometry.
A subassembly returns a Smith.Assembly.Result; a leaf returns a
Smith.Result. Use a list such as [:left, :foot] or a slash path
such as "left/foot" to address descendants. Fetching from a returned
subassembly uses paths relative to it, but its geometry remains in world
coordinates. Empty paths and descent through a leaf return :unknown_part.
iex> recipe =
...> Smith.Assembly.new(:mount)
...> |> Smith.Assembly.part(:left_foot, Smith.box(2, 3, 4),
...> position: {10, 0, 0}
...> )
iex> {:ok, assembly} = Smith.evaluate(recipe)
iex> {:ok, foot} = Smith.Assembly.fetch(assembly, "left-foot")
iex> OCEx.bounds(foot.shape)
{:ok, {{10.0, 0.0, 0.0}, {12.0, 3.0, 4.0}}}
iex> Smith.Assembly.fetch(assembly, :missing)
{:error, :unknown_part}
@spec fetch_joint(Smith.Assembly.Result.t(), member_path()) :: {:ok, Smith.Assembly.Joint.t()} | {:error, :unknown_joint}
Returns a named joint's evaluated world frame and owning member path.
Accepts a name, slash path, or list as in fetch/2. Nested lookup
prefixes the owner path but leaves the world frame unchanged. Unknown joints
return {:error, :unknown_joint}. The returned Smith.Assembly.Joint
is a snapshot; reevaluate the recipe to change its pose.
Defines a named attachment frame on an immediate assembly member.
Required on: names a part, reference, or subassembly at this level.
at: is a Smith.Plane or :xy, :xz, or :yz;
it defaults to :xy. The frame is in that member's original recipe
coordinates, before its placement. Its normal is local Z and its X direction
fixes rotational alignment. Names are unique in the assembly's joint namespace.
Frames follow their members through placement and connections. Refer to a
child assembly's joint with a path such as [:module, :pin]. Joint
definitions and connections are validated when the assembly is evaluated.
@spec members(Smith.Assembly.Result.t()) :: {:ok, [map()]}
Lists all leaf members in depth-first insertion order.
Returns {:ok, members}. Each map contains normalized :path
segments, a slash-separated :key, the original leaf :name,
:kind (:part or :reference), its world-space :result,
:options, and effective :installed. A manufactured leaf is
installed only if it and all its ancestor instances are installed;
references are never installed manufactured geometry.
Options include accumulated world display/exploded offsets and effective installed status. Print options are unchanged. This is the same leaf view used by assembly export. Neither enumeration nor lookup evaluates recipes.
Creates an empty named assembly recipe.
Names are atoms or strings beginning with an ASCII letter or digit,
followed by letters, digits, underscores, or hyphens. Validation occurs
at evaluation. Add at least one installed part before evaluating;
otherwise the result is {:error, :no_installed_parts}.
Adds a named manufactured part to an assembly recipe.
recipe must be a Smith.Model that evaluates to geometry containing
at least one solid. Multiple solids are allowed. Names follow new/1
and must be unique across parts and references, after replacing underscores
with hyphens. Names remain case-sensitive.
Options
:position— translation in the parent frame{x, y, z}in mm, default zero.:rotation—{axis_vector, degrees}about the parent-frame origin, applied before:position. Default: no rotation.:installed— defaulttrue. Setfalsefor a printable extra excluded from the installed compound and assembly preview.:print— keyword list controlling print placement, described below.:display_offset— world offset for the exported preview mesh, default zero. Applied byview/2in display and exploded modes.:exploded_offset— world offset stored in export metadata, default zero. Added to display placement byview/2in exploded mode. Rendering the assembly directly still shows installed geometry.
Print placement starts from the installed shape. Within :print,
:rotation uses {axis_vector, degrees} about world zero, followed by
:offset (a world translation). Alternatively, on_bed: true centers
the rotated bounds in XY and places minimum Z at zero. It cannot be
combined with :offset. Defaults apply no print transform.
Options are checked during evaluation; unknown or duplicate keys fail
with a Smith.Error identifying this part. Print placement is applied
only at export, so geometrically invalid print transforms can fail there.
Adds named reference geometry that is excluded from print output.
Accepts the same names and solid-containing model recipes as part/4,
but only its :position and :rotation options. References are
evaluated and can fail an assembly build. Retrieve one with fetch/2.
References are absent from the installed compound and its Kino preview.
When STEP is requested, export writes them into a separate
references-DO-NOT-PRINT.step. They never enter the print pack.
Adds a named instance of another assembly.
Child positions and rotations are relative to this instance. Each child rotates before translating; the parent transform applies afterwards. The same subassembly can be reused under different names and placements. Names must be unique among siblings, including parts and references.
Options are :position, :rotation, :installed,
:display_offset, and :exploded_offset, with the defaults from
part/4. Setting installed: false excludes the whole branch
from the parent's installed shape; manufactured leaves still get print
files. References remain references at every depth.
Print options belong to leaf parts and operate on their final world shapes.
Display and exploded offsets are world vectors: offsets at ancestor and
leaf levels add without rotation. They affect export metadata, not geometry.
Retrieve an instance or leaf with fetch/2; enumerate leaves with
members/1. A subassembly must contain an installed manufactured part
when evaluated on its own. Invalid recipes return :invalid_subassembly.
@spec view(Smith.Assembly.Result.t(), :installed | :display | :exploded) :: {:ok, Smith.Result.t()} | {:error, term()}
Builds a geometry snapshot of an evaluated assembly for inspection.
Returns {:ok, %Smith.Result{}}, suitable for Smith.Kino.render/2.
The mode selects which manufactured parts and offsets to show:
:installed(default) reuses the installed shape and its revision.:displayincludes all manufactured leaves, including uninstalled extras, and applies their accumulated:display_offset.:explodedadds accumulated:exploded_offsetto the display offset.
Nested placement and joint connections have already been resolved. Offsets
are world vectors; parent and leaf offsets add without rotation. References
are excluded in all modes. Fetch a reference with fetch/2 to inspect it.
This does not reevaluate recipes or apply print transforms. It preserves the assembly and returns an unfused snapshot with a matching BREP revision. Export the original assembly to retain part names, separate files, and print placement; the view is only a combined shape, without assembly metadata.
Revision and native geometry failures return tagged errors. An unsupported
mode returns :invalid_options; an unevaluated input returns
:invalid_argument.