Sync cad-mainline with upstream main and carry the value-field + rename work on top

This commit is contained in:
Tommaso Bianchi
2026-09-10 11:01:24 +02:00
47 changed files with 1395 additions and 645 deletions
+9 -9
View File
@@ -1,4 +1,4 @@
# SnapOrca-CAD vs Onshape — capability gap analysis
# Orca-CAD vs Onshape — capability gap analysis
Generated 2026-07-22 by enumerating the source, not from recollection:
`CadFeatureType` and `add_*` in `src/libslic3r/CAD/CadDocument.hpp`, `Tool` in
@@ -6,19 +6,19 @@ Generated 2026-07-22 by enumerating the source, not from recollection:
`SketchConstraintType` + `SketchEntity::Type` in `src/libslic3r/CAD/SketchEngine.hpp`,
and the JSON-RPC dispatch in `src/slic3r/GUI/CAD/McpControl.cpp`.
**Scope note.** Onshape is a cloud PLM platform; SnapOrca is a Design tab inside a
**Scope note.** Onshape is a cloud PLM platform; Orca is a Design tab inside a
slicer. A large share of Onshape's surface (release management, branching, real-time
collaboration, FEA, rendering, PDM) is out of scope by construction and is listed
separately at the bottom rather than counted as a "missing tool".
---
## 1. What SnapOrca already has
## 1. What Orca already has
### 2D sketcher — near parity with Onshape
This is the strongest area. Very little is missing.
| Category | SnapOrca |
| Category | Orca |
|---|---|
| Entities | Line, Polyline, Arc (3-point / tangent / center), Circle (center / 2-point / 3-point), Point, Ellipse, Elliptical arc, B-spline |
| Shapes | Rectangle (corner / center / oblique / rounded), Slot, Arc-slot, Polygon |
@@ -88,7 +88,7 @@ Studio + configurations are a core differentiator, and this is the cheapest Tier
item to close for the size of the payoff.
**4. Surface modelling.** Absent. No surface extrude/revolve/loft/sweep, no fill,
knit, trim/extend surface, offset surface, or thicken. SnapOrca is solid-only.
knit, trim/extend surface, offset surface, or thicken. Orca is solid-only.
*Impact:* organic/complex shapes and repair of imported junk geometry are impossible.
OCCT already provides all of it (`TKOffset`, `TKBRep`), so the kernel is not the
blocker — only UI and feature plumbing.
@@ -106,7 +106,7 @@ blocker — only UI and feature plumbing.
| **Split body** | Cut removes material; splitting one body into two independently-usable bodies is absent. Very relevant for print-in-parts. | Medium |
| **Thicken** | Solid from a surface/face offset. | Needs surfaces |
| **Rib** | Standard structural feature. | Medium |
| **Delete face / move face / replace face** | Direct/dumb-solid editing — the main tool for fixing imported STEP. Given SnapOrca imports STEP *and* meshes, its absence is felt. | Medium |
| **Delete face / move face / replace face** | Direct/dumb-solid editing — the main tool for fixing imported STEP. Given Orca imports STEP *and* meshes, its absence is felt. | Medium |
| **Datum axis, coordinate system** | Only datum *planes* exist. Axes are needed for revolve/pattern references. | Yes |
| **Mass properties** | `GeometryEngine` computes a volume internally, but there is no volume/mass/COM/inertia readout. For print cost/time estimation this is nearly free to expose. | Yes — trivial |
| **Measure tool in the GUI** | `measure` exists over MCP but there is no interactive measure in the UI. | Yes |
@@ -123,7 +123,7 @@ blocker — only UI and feature plumbing.
Version control with branching/merging, release management, real-time multi-user
collaboration, cloud PDM, FeatureScript custom-feature authoring, simulation/FEA,
photorealistic rendering, app store/integrations. These are Onshape-the-platform,
not Onshape-the-modeller. Not defects in SnapOrca.
not Onshape-the-modeller. Not defects in Orca.
---
@@ -140,7 +140,7 @@ the most capability per unit of work:
5. **Split body** — high value for print-in-parts workflows.
6. **Project edges into sketch** — the sketcher's most conspicuous hole.
7. **Surface modelling** — large, but OCCT already ships the algorithms.
8. **Assemblies** — largest effort; only worth it if SnapOrca targets multi-part products.
8. **Assemblies** — largest effort; only worth it if Orca targets multi-part products.
Deliberately last: drawings and sheet metal — high cost, low relevance to an
FDM-oriented tool.
@@ -149,7 +149,7 @@ FDM-oriented tool.
## 4. Honest summary
SnapOrca's **sketcher is at or near Onshape parity**, and its **solid feature set
Orca's **sketcher is at or near Onshape parity**, and its **solid feature set
covers the mainstream modelling path** (sketch → extrude/revolve/sweep/loft →
dress-up → boolean/pattern). What is absent is *breadth*: assemblies, surfaces,
sheet metal, drawings, and — most importantly for a tool calling itself parametric —
+2 -2
View File
@@ -4,7 +4,7 @@ What the Design tab actually costs a maintainer who merges it. Written to be che
every number below is reproducible with the command that produced it, and the places where
a number is still missing say so instead of guessing.
Measured on Linux x86_64, OCCT V7_6_0, in the `snaporca-deps` build image.
Measured on Linux x86_64, OCCT V7_6_0, in the `snapmaker-deps` build image.
## Summary
@@ -75,7 +75,7 @@ producing them honestly needs a build this machine cannot do:
1. **Windows DLL delta.** OCCT builds shared on Windows, so the shipped cost there is real
DLL bytes rather than linker-selected objects. That needs a Windows build to size —
tracked as the cross-platform build proof (`snaporca-gix`).
tracked as the cross-platform build proof (`gix`).
2. **Clean-build time delta.** Measuring it means building the deps prefix twice, with the
flag ON and OFF, on the same machine. The incremental figures from day-to-day work do not
answer the question and are not offered as if they did.
@@ -1,6 +1,6 @@
# Mate connectors: aligning with the mainstream CAD systems
Research date: 2026-08-05. Written against `orca_cad` / `snaporca` at the M8 state
Research date: 2026-08-05. Written against `orca_cad` / `Snapmaker` at the M8 state
(`CadDocument.{hpp,cpp}`, `apply_mate`, `datum_frame`, the `Mate` card in `DesignPanel.cpp`).
**Brief:** align with the mate-connector concept as the main CAD programs actually implement it,
@@ -300,7 +300,7 @@ times.
**C2 — The roll is unspecified.** Aligning Z leaves one rotation about Z undetermined. Something must
pin it, and if that something is world-derived, the frame does not rotate with its part. **This
codebase shipped exactly this bug** (`snaporca-en4`): a face-only connector took Z from the face
codebase shipped exactly this bug** (`en4`): a face-only connector took Z from the face
normal but X from `coordsys_x_hint`, a world constant, so Fastened and Slider claimed to lock an
orientation the frame could not see. Fixed 2026-07-26 by deriving X from the face's own first usable
edge — but note the fix's own caveat: *"replaying an older document whose face-only connector fed a
@@ -512,7 +512,7 @@ Source of record: `CadDocument.hpp:26,247-252,298-310`; `CadDocument.cpp:1669` (
**Already aligned — do not "fix" these:** the five types and their DOF; the frame definition (A1);
Z as the joint axis (A2); superimpose-then-relax (A3); the fixed/moving asymmetry in the data model
(A5); DOF wording in the type list (A7); free-DOF preservation (A8); right-handed frames under mirror
(R14); and `snaporca-en4`'s fix, which put roll derivation on the body where it belongs (C2).
(R14); and `en4`'s fix, which put roll derivation on the body where it belongs (C2).
**The pattern worth naming: the kernel is in good shape and the concept is under-explained.** Half the
requirements here are wording and drawing, not geometry. The two real engineering items are R9 (origin
@@ -668,7 +668,7 @@ is a symbol, not a part — it must not shrink with the model. Nothing about tha
The glyph was therefore implemented and driven on the rig. Screenshots: `g-0*.png`, left in the workspace `artifacts/shots/` and not moved into the repo.
Five findings, none of which a mock could have produced:
**F1 — Three axis arms lose to one.** Rendered side by side (`SNAPORCA_GLYPH=A` vs default), the
**F1 — Three axis arms lose to one.** Rendered side by side (`ORCA_CAD_GLYPH=A` vs default), the
Onshape-style RGB trio crowds a 22 px disc: the arrowheads are as large as the disc, they bury the
gold quadrant, and at an oblique angle the three heads pile into a coloured smudge. Worse, **it is
indistinguishable from the move gizmo and the bed triad**, which are already RGB arrow trios in this
@@ -827,7 +827,7 @@ conversation it arrived in points at "glyph".
It changes the meaning of every stored document containing a mate. Options: (a) invert and migrate,
writing `direction=Aligned` where `mate_flip` was false; (b) invert only for new mates and store
`direction` explicitly from now on. (b) is safer and costs one field. Note this project has taken one
such semantic hit knowingly before — the `snaporca-en4` fix — and the golden fixture survived, so the
such semantic hit knowingly before — the `en4` fix — and the golden fixture survived, so the
migration path is a known quantity. **If G3 (live preview) lands first, this matters much less.**
**D2 — How far to take origin candidates?** [R9]
@@ -911,7 +911,7 @@ R18's loud refusals carrying the honesty.
[Joint kinematics — the six lower pairs and their DOF](https://erc-bpgc.github.io/handbook/mechanical/Joint%20Kinematics/) ·
[ISO 10303-105 — Kinematics (STEP integrated resource)](https://www.iso.org/standard/78589.html)
**Internal**`snaporca-en4` (closed 2026-07-26, fixes C2 here) · `CadDocument.cpp:1669`
**Internal**`en4` (closed 2026-07-26, fixes C2 here) · `CadDocument.cpp:1669`
`datum_frame` · `CadDocument.cpp:2961` `apply_mate` · `CadDocument.cpp:1302` `add_mate`
**Second opinion** — an independent review by Kimi Code (2026-08-05) contributed the
@@ -9,7 +9,7 @@ static const Vec2d kBearOutline[] = { // 12 verts, RDP eps 0.030, CCW
static const Vec2d kBearChin[] = { // the CHIN BAR, flat. The muzzle is relief — see kBearCrest.
{-0.2682, -0.3578}, {+0.2628, -0.3578}, {+0.2237, -0.1786},
};
// {cx, cy, r}: two eyes, then the cheek dot that carries handedness (snaporca-wi3z).
// {cx, cy, r}: two eyes, then the cheek dot that carries handedness (wi3z).
static const Vec3d kBearMarks[] = {
{-0.1997, +0.1760, +0.0590},
{+0.1947, +0.1760, +0.0590},
@@ -96,7 +96,7 @@
<div class="wrap">
<header>
<div class="eyebrow">SnapOrca Design · assembly</div>
<div class="eyebrow">Orca Design · assembly</div>
<h1>Mate connector glyph — polarity and verse</h1>
<p class="sub">
Onshape's core (disc + roll quadrant + Z arrow) is adopted unchanged because it is proven and
@@ -1,4 +1,4 @@
"""Emit the simplified bear as a C++ table for the viewport glyph — snaporca-wi3z.
"""Emit the simplified bear as a C++ table for the viewport glyph — wi3z.
Everything is normalised to the part's own bounding span and centred, so the renderer scales by
one radius R in screen pixels and nothing here carries millimetres. Emitting rather than
@@ -79,7 +79,7 @@ L.append("};")
L.append(f"static const Vec2d kBearChin[] = {{ // the CHIN BAR, flat. The muzzle is relief — see kBearCrest.")
L.append(" "+", ".join(f"{{{fmt(x)}, {fmt(y)}}}" for x,y in TRI)+",")
L.append("};")
L.append("// {cx, cy, r}: two eyes, then the cheek dot that carries handedness (snaporca-wi3z).")
L.append("// {cx, cy, r}: two eyes, then the cheek dot that carries handedness (wi3z).")
L.append("static const Vec3d kBearMarks[] = {")
for cx,cy,r in E: L.append(f" {{{fmt(cx)}, {fmt(cy)}, {fmt(r)}}},")
L.append(f" {{{fmt(DOT[0])}, {fmt(DOT[1])}, {fmt(DOT[2])}}},")
@@ -1,4 +1,4 @@
"""Render the SIMPLIFIED glyph exactly as render_mate_face() draws it — snaporca-x0kd.
"""Render the SIMPLIFIED glyph exactly as render_mate_face() draws it — x0kd.
This is the panel the study was missing. simplify_study.py measured a FLAT outline and
relief_sheet.py measured the FULL 1508-facet part; neither showed the simplified glyph WITH its
@@ -1,4 +1,4 @@
"""Give the bear a handedness mark that survives rasterisation — snaporca-wi3z, Tommaso's call 2.
"""Give the bear a handedness mark that survives rasterisation — wi3z, Tommaso's call 2.
The study showed the left/right cue lives in sub-millimetre corner radii and is therefore invisible
at glyph size: one pixel is 2.6 mm at 32 px. Roll and verse are safe; handedness is not.
@@ -1,4 +1,4 @@
"""The muzzle has to READ, not just be present — snaporca-wi3z.
"""The muzzle has to READ, not just be present — wi3z.
Faithfully scaled, the part's ridge is 11.3 mm on an 83 mm face: 13.6 % of the width. At glyph
size that is a scratch. A glyph is a symbol, not a scale model, so the question is how much
@@ -1,4 +1,4 @@
"""Flat glyph vs 3D relief, at the elevations that killed the disc — snaporca-wi3z.
"""Flat glyph vs 3D relief, at the elevations that killed the disc — wi3z.
The flat study collapsed at 16 deg because anything drawn IN the connector's plane foreshortens by
sin(elevation). This renders the SAME bear as its real relief (1508 facets off the supplied male)
@@ -1,4 +1,4 @@
"""Reduce the bear face to the fewest marks that still read at glyph size — snaporca-wi3z.
"""Reduce the bear face to the fewest marks that still read at glyph size — wi3z.
Geometry comes from bear_outline.json, which extract_outline.py pulled off the supplied male
B-rep's back plate: the outer wire IS the silhouette, the inner wires are the two eyes and the
+10 -10
View File
@@ -1,13 +1,13 @@
# Rig build traps
The build rig is two long-lived containers, `snaporca-gui` and `orcacad-gui`, one per fork. Each
mounts only its fork's build volume (`snaporca_buildcache` / `orcacad_buildcache`) at
The build rig is two long-lived containers, `snapmaker-gui` and `orcacad-gui`, one per fork. Each
mounts only its fork's build volume (`snapmaker_buildcache` / `orcacad_buildcache`) at
`/OrcaSlicer/build`, its fork's `resources/`, and a shots directory — nothing else. They run the
binary; they do not build it. Rebuild with `scripts/CAD/build-gui.sh`.
| fork repo | project() | deps image | build volume | GUI container | binary |
|---|---|---|---|---|---|
| `snaporca` | `Snapmaker_Orca` | `snaporca-deps` | `snaporca_buildcache` | `snaporca-gui` | `snapmaker-orca` |
| `Snapmaker` | `Snapmaker_Orca` | `snapmaker-deps` | `snapmaker_buildcache` | `snapmaker-gui` | `snapmaker-orca` |
| `orca_cad` | `OrcaSlicer` | `orcacad-deps` | `orcacad_buildcache` | `orcacad-gui` | `orca-slicer` |
`scripts/CAD/build-gui.sh` exists alongside `scripts/CAD/build-gui-incremental.sh` for one reason: it does a
@@ -29,7 +29,7 @@ reports an unknown target, and `orca-slicer` / `OrcaSlicer` have been replaced b
**Cause.** The GUI image's baked `/OrcaSlicer` tree is the Jun-13 Snapmaker-derived source
(`project(Snapmaker_Orca)`, executable `snapmaker-orca`). `orcacad-deps` is layered on
`snaporca-deps`, so even on the mainline fork the baked tree is the other fork's. A `cmake .`
`snapmaker-deps`, so even on the mainline fork the baked tree is the other fork's. A `cmake .`
there reconfigures the shared build dir under the wrong project name.
**Fix.** Build only via `scripts/CAD/build-gui.sh`, which starts a throwaway container from the deps
@@ -64,10 +64,10 @@ Did you initialize submodules?` (the `FATAL_ERROR` guarding `PYBIND11_SOURCE_DIR
fork's root `CMakeLists.txt`, near line 948).
**Cause.** The deps image predates that requirement. Only the mainline (`orca_cad`) fork has
`deps_src/pybind11` and the requirement; snaporca has neither.
`deps_src/pybind11` and the requirement; Snapmaker has neither.
**Fix.** Mount `deps_src` over the baked tree — `scripts/CAD/build-gui.sh` does. Corollary: mounting a
snaporca tree into an `orcacad-deps` build reproduces this error exactly.
Snapmaker tree into an `orcacad-deps` build reproduces this error exactly.
---
@@ -96,7 +96,7 @@ you ever configure by hand, run it twice.
**Cause.** The cache carries `SLIC3R_CAD=ON`, but the root `CMakeLists.txt` actually configured is
a stale baked copy that predates the gate and never runs `add_definitions(-DSLIC3R_CAD)` (the
gate is `if (SLIC3R_CAD)` / `add_definitions(-DSLIC3R_CAD)` in the root list — line 179/180 in
snaporca, 319/320 in orca_cad). Every `#ifdef SLIC3R_CAD` block therefore compiles out while the
Snapmaker, 319/320 in orca_cad). Every `#ifdef SLIC3R_CAD` block therefore compiles out while the
option still reads ON.
**Fix.** Always mount the live `CMakeLists.txt` and `cmake/` — never inherit them from the image.
@@ -109,12 +109,12 @@ all mount both.
`ninja <target>` writes `/OrcaSlicer/build/src/Release/<binary>`; only `build_linux.sh`
additionally packages to `/OrcaSlicer/build/package/bin/<binary>`. `orca_cad`'s
`scripts/CAD/start-headless-gui.sh` defaults `BIN` to `src/Release/orca-slicer`, but snaporca's defaults to
`package/bin/snapmaker-orca`. So after a target-only rebuild on snaporca, launching
`scripts/CAD/start-headless-gui.sh` defaults `BIN` to `src/Release/orca-slicer`, but Snapmaker's defaults to
`package/bin/snapmaker-orca`. So after a target-only rebuild on Snapmaker, launching
`start-headless-gui.sh` with its default runs the **stale packaged** binary — the change under test is
invisible and the session hunts a phantom. Pass `BIN` explicitly:
docker exec -e BIN=/OrcaSlicer/build/src/Release/snapmaker-orca snaporca-gui /OrcaSlicer/scripts/CAD/start-headless-gui.sh
docker exec -e BIN=/OrcaSlicer/build/src/Release/snapmaker-orca snapmaker-gui /OrcaSlicer/scripts/CAD/start-headless-gui.sh
`scripts/CAD/build-gui.sh` prints the correct line for the current fork when it finishes.
+1 -1
View File
@@ -121,7 +121,7 @@ def main():
# A verb may carry a NOTE: the reason it exists, emitted as a C++ comment above its row.
# Without somewhere to put it, a rationale written into the generated header is deleted by
# the next regeneration — which is how the model-mode "Constrain sketch" row came to exist
# in the header and not in the atlas at all (snaporca-ziam). The map exists once; so does
# in the header and not in the atlas at all (ziam). The map exists once; so does
# the explanation.
for ln in ([v["note"]] if isinstance(v.get("note"), str) else v.get("note") or []):
lines.append(f" // {ln}")