Part bundles containing geometry files, a preview mesh, and check results.
Use Smith.export/3 or write/3 with an evaluated part. Each call writes
a new directory identified by the geometry revision and a random export
ID. current.json points to the latest records by name; previous export
directories remain available.
Print placement affects STL and 3MF. STEP and BREP retain the evaluated geometry's placement. Print meshes are checked after STL serialization, and requested STEP files are reimported and measured. These checks catch common export failures; they do not establish dimensional fit, strength, printer settings, or freedom from every mesh self-intersection.
See write/3 for all options and returned fields, mesh/3 for the
precise checks, and the exporting guide for examples.
Assembly exports go through Smith.export/3; this module's writers
accept individual Smith.Result values.
Summary
Functions
Builds a printable mesh and checks its binary STL representation.
Updates current.json with existing export records.
Writes a checked export bundle for one evaluated Smith.Result.
Writes several part bundles and publishes their records together.
Functions
@spec mesh(OCEx.Shape.t(), number(), number()) :: {:ok, map()} | {:error, term()}
Builds a printable mesh and checks its binary STL representation.
Accepts an OCEx.Shape, linear deflection in mm (default 0.03), and
angular deflection in radians (default 0.5). The shape must contain solids
and have positive total volume. Native mesh vertices are welded with
Smith.Mesh.weld/2, then serialized as binary STL and parsed back.
The parsed mesh must have:
- Exactly two triangles sharing every edge, with opposite edge directions.
- As many edge-connected triangle components as native solids.
- Signed volume within 0.5% of native volume (strictly less than 0.005 relative error).
Returns {:ok, %{mesh: mesh, stl: binary, checks: report}}. The mesh is
the welded pre-STL mesh; checks describe the parsed STL. The report has
the fields from Smith.Mesh.inspect/1, plus :relative_volume_error,
:linear_deflection, and :angular_deflection.
Failures include :no_solids, :non_positive_volume,
:invalid_print_mesh, and :mesh_volume_mismatch. A coarse curved mesh
can fail the volume check; decrease deflections and retry. Component
matching also rejects otherwise valid designs with multiple disconnected
boundary shells per solid, such as a fully enclosed cavity. It is not
a general self-intersection or manufacturability test.
iex> {:ok, box} = OCEx.box(2, 3, 4)
iex> {:ok, print} = Smith.Export.mesh(box)
iex> {print.checks.watertight, print.checks.components, byte_size(print.stl)}
{true, 1, 684}
Updates current.json with existing export records.
Accepts one record map or a nonempty list of records with distinct string
:name values and string :revision values. Returns {:ok, :ok}.
Records with matching names are replaced; unrelated models and assemblies
remain. Standalone records cannot overwrite assembly-owned part names.
This function only updates the manifest. It does not write or verify
geometry files, hashes, or paths. Use write/3 or write_many/2 for
the complete checked export flow.
Malformed records return :invalid_argument, malformed existing
manifests return :invalid_manifest, and ownership conflicts return
:assembly_part_conflict. File-system errors are returned unchanged.
The manifest is replaced through a temporary file; writers to one root
must run sequentially.
@spec write(Smith.Result.t(), String.t(), keyword()) :: {:ok, map()} | {:error, term()}
Writes a checked export bundle for one evaluated Smith.Result.
root is an output directory, created as needed. Returns
{:ok, record} after writing files and updating current.json.
Smith.export/3 delegates here for individual results.
Options
| Option | Default | Meaning |
|---|---|---|
:name | Required | String starting with an ASCII letter/digit; remaining characters may also include _ or - |
:formats | [:step, :stl, :three_mf] | Nonempty unique subset of these formats |
:tolerance | 0.03 | Print mesh linear deflection in mm |
:angular_tolerance | 0.5 | Print mesh angular deflection in radians |
:step_tolerance | 1.0e-6 | Relative STEP volume error threshold; greater than zero and at most 1.0e-5 |
:print_rotation | nil | {axis, degrees} about world zero |
:print_offset | {0, 0, 0} | World translation after print rotation |
:on_bed | false | Centers rotated bounds in XY and puts minimum Z at zero |
:display_orientation | :print | :print or :installed orientation for the preview mesh |
:display_offset | {0, 0, 0} | World translation of the preview mesh only |
:metadata | %{} | JSON-encodable map added to the verification report |
:on_bed cannot be combined with :print_offset. Linear and angular
deflections must exceed 1.0e-7. Metadata tuples become JSON arrays;
generated verification fields take precedence over colliding metadata keys.
Files and returned record
Files are placed under root/name/revision/export_id/. Requested formats
produce model.step, model.stl, and model.3mf. model.brep,
model.json, and verification.json are always written. STEP and BREP
retain evaluated placement; STL and 3MF use print placement. 3MF contains
millimeter geometry without printer or slicer settings.
The record contains :name, :revision, :export_id, :step,
:stl, :three_mf, native :volume, display :mesh, and
:verification. Unrequested format paths are nil. Paths retain
the form of root: use an absolute root if consuming them elsewhere.
The display mesh uses fixed 0.03 mm / 0.5 rad settings, independently
of print mesh settings.
Checks and failures
The result's BREP must match its revision. All bundles run mesh/3
checks, even STEP-only bundles. Each requested STEP is read back and
checked for native validity, solid count, and relative volume error
strictly below :step_tolerance. This is not a boundary-distance or
dimensional comparison. 3MF is serialized from the checked mesh; it is
not read back independently by this exporter.
Failures return {:error, reason}, including :revision_mismatch,
:invalid_options, :invalid_metadata, mesh/STEP check errors, and
file-system errors. Failed exports may leave new files, but preserve the
previous manifest and earlier export directories. Run writers to one
root sequentially.
@spec write_many([{Smith.Result.t(), keyword()}], String.t()) :: {:ok, [map()]} | {:error, term()}
Writes several part bundles and publishes their records together.
entries is a nonempty list of {result, options} pairs. Each result
is a Smith.Result; options follow write/3. Names must be distinct.
Returns {:ok, records} in input order.
Invalid batch options return :invalid_options. A part write failure
returns {:error, {:export_failed, name, reason}}. Nothing is published
until every bundle passes, although completed unpublished files may
remain. This groups exports without creating a named assembly or ZIP.