Export 3MF with B-rep face tags (#834)

3MF export carries each triangle's B-rep face tag.
This commit is contained in:
Irakli Kourtis authored and GitHub committed 2026-10-13 16:29:09 -04:00
1 parent ff7a347013
commit 5d661fa2af
10 files changed
+286 -47

No files matched your search

+7
View File
@@ -7,6 +7,7 @@
| STEP (AP203, AP214, AP242) | solids, assemblies, units, names, colours | AP242 with names, colours and the component tree |
| IGES 5.3 | manifold solids, or trimmed surfaces sewn into solids | manifold solids with names and colours |
| 3MF, STL, OBJ | mesh bodies | yes |
| 3MF with face tags | as 3MF | each triangle tagged with its B-rep face, exact coordinates |
| DXF, SVG | into a sketch | sketches and flat patterns as DXF |
| PNG, JPEG | canvases and decals | |
@@ -28,6 +29,12 @@ tapers, stepped parts and organic scans are refused by this first reconstruction
method; it does not silently substitute a faceted solid. Conversion currently
accepts at most 50,000 triangles and a bounded number of boundary segments.
**File → Export 3MF with Face Tags** (`file.export` with `format: "3mf-tagged"`) writes an
ordinary 3MF in which every triangle also names the B-rep face it lies on and every coordinate
is the tessellation's own double-precision value. Meshing and analysis tools can use the tags to
keep a model's faces (for loads, boundary conditions or feature edges); other 3MF readers ignore
them. The format is specified in [`docs/formats/3mf-face-tags.md`](https://github.com/bherbruck/solidcraft/blob/main/docs/formats/3mf-face-tags.md).
Saves are atomic: a crash at any moment leaves either the old file or the new one, and the
replaced version is kept as `<file>.bak`. Unsaved changes are autosaved to a recovery folder,
and the next launch offers to recover them. Older design files are upgraded on open, and files
+79
View File
@@ -0,0 +1,79 @@
# 3MF with B-rep face tags
Version 1 (2026-10). Namespace `https://github.com/bherbruck/solidcraft/formats/3mf-face-tags/2026/10`,
prefix `ft`.
A tessellated body loses its faces: a plain mesh says where the surface is, not which B-rep face
each triangle came from. Downstream tools that mesh or analyse a part need that back. They apply
loads and boundary conditions to faces, keep face boundaries as feature edges, and group
results by face. SolidCraft therefore exports a 3MF in which every triangle carries the index of
the B-rep face it lies on (**File → Export 3MF with Face Tags**, or `file.export` with
`format: "3mf-tagged"`).
## Why 3MF
The file is an ordinary **3MF package** (3MF Consortium, *3D Manufacturing Format Core
Specification* 1.3). The tags are one attribute in a namespace of SolidCraft's. The Core
specification allows that attribute on `<triangle>` and `<object>`, and every consumer ignores it
because the namespace is not listed in `requiredextensions`. Slicers, viewers and SolidCraft's
own mesh import open the file as plain 3MF. A tool that knows the namespace gets the faces too.
A purpose-built binary format would have needed its own specification and readers, and would
open nowhere else. Decimal coordinates lose nothing: written in shortest round-trip form, every
`f64` reads back bit for bit.
## Example
```xml
<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US"
xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02"
xmlns:ft="https://github.com/bherbruck/solidcraft/formats/3mf-face-tags/2026/10">
<metadata name="Application">SolidCraft</metadata>
<resources>
<object id="2" type="model" name="Body1" ft:faces="7">
<mesh>
<vertices>
<vertex x="0" y="0" z="0"/>
...
</vertices>
<triangles>
<triangle v1="0" v2="2" v3="1" ft:face="0"/>
...
</triangles>
</mesh>
</object>
</resources>
<build>
<item objectid="2"/>
</build>
</model>
```
## Attributes
| Attribute | On | Value | Meaning |
|---|---|---|---|
| `ft:faces` | `<object>` | integer ≥ 1 | Number of B-rep faces of the body. Every `ft:face` of the object is below it. Faces without triangles still count. |
| `ft:face` | `<triangle>` | integer ≥ 0 | The B-rep face (0-based, in the body's own face order) the triangle lies on. |
An object's triangles are either all tagged or none. A reader treats an object without tags as a
single face (tag 0).
## What SolidCraft writes
- `unit="millimeter"`, Z up. There is one `<object type="model">` with a `<mesh>` per body,
named after the body, and one `<item>` per object, with no transform and no components.
- The tessellation is the export mesh (chord tolerance 2·10⁻⁴ of the body size). It is welded
watertight: vertices within 10⁻⁶ of the body size are merged and T-junctions between faces are
split. Each piece of a split triangle keeps its face. Triangles are counter-clockwise seen from
outside, and degenerate triangles are dropped.
- Coordinates are the tessellation's own `f64` values in shortest round-trip form, and vertices
are shared by exact value.
- Colours use 3MF's own `basematerials` (`pid`/`p1`), as in the plain 3MF export, independent of
the tags.
- The bytes are deterministic: fixed part order, fixed zip timestamps, no hash-ordered output.
## Versions
A later version gets a new namespace (`…/3mf-face-tags/<year>/<month>`). A reader accepts the
versions it knows and treats an unknown face-tag namespace as untagged.
+1 -1
View File
@@ -65,7 +65,7 @@ They cover the workflow, the command shapes, how to verify with `measure`, and t
| `body_topology` | `body` | Edges (index, midpoint, length, ends) and faces (index, area, centroid, normal). An edge midpoint is the `[x,y,z]` that picks that edge for fillet and chamfer. |
| `set_parameter` | `name`, `value` (number or expression), `unit?`, `comment?` | Create or change a user parameter and recompute; reports `recomputed` (features rebuilt), `restored` (features whose earlier result for the same inputs was reused, e.g. a value set back) and features that now fail. |
| `screenshot` | `view?` (iso, top, front, back, bottom, left, right, home, fit, or a named view saved with `view.save`), `camera?` (`{target, yaw, pitch, distance, fov?}`, as `view.apply`), `path?`, `width?`, `height?`, `source?` (window, model) | A PNG image content block. Headless: CPU render fitted to the model, or from the named view or camera. Bridged: the app window (default) or a model render with the app's camera; a named view or camera moves the app's viewport there first (`execute` `view.apply` does the same without a screenshot). |
| `export` | `path`, `format?` (step, 3mf, stl, stla, obj), `bodies?` | STEP, 3MF or mesh export. |
| `export` | `path`, `format?` (step, 3mf, 3mf-tagged, stl, stla, obj), `bodies?` | STEP, 3MF or mesh export. |
| `undo`, `redo` | — | Undo / redo one change. |
| `crash_reports` | `id?`, `limit?` | The crash reports on this computer, newest first; with `id`, the whole report (backtrace, command, recent commands, `design_path`/`replay_path`). See [crash-reports.md](crash-reports.md). |
| `new_design` | `name?` | Start an empty design. |