Migrate export_step / export_stl / export_brep off FreeCAD, onto build123d + OCP #23

Closed
opened 2026-06-20 19:12:53 +00:00 by Mark · 5 comments
Owner

Migrate export_step / export_stl / export_brep off FreeCAD, onto build123d + OCP

Architectural stance (decided 2026-06-23)

FreeCAD is dropped from pc2cad exports, no fallback. No _HAS_FREECAD
conditional block, no migration shim, no "use FreeCAD if installed." Every
export path runs on OCP + build123d (+ numpy-stl for binary STL), in a
plain Python venv, with no system FreeCAD, no conda env, no AppImage, no
PYTHONPATH surgery.

export_fcstd stays gated on FreeCAD: .FCStd is a FreeCAD-Document.xml
archive with no OCP equivalent, and the CLI does not expose it. The function
keeps its import FreeCAD so anyone calling it directly still works; nothing
else in pc2cad.py imports FreeCAD or Part.

Blast radius (already mapped)

FreeCAD/Part surface in pc2cad.py:

  • pc2cad.py:3583 _freecad_import — the lazy import shim. Delete it.
  • pc2cad.py:3592 _primitive_to_shape(FreeCAD, Part, primitive) — the
    per-primitive OCP shape constructor. This is the rewrite target, just
    stop taking FreeCAD, Part as parameters.
  • pc2cad.py:4991 export_step — uses _freecad_import, Part.makeCompound,
    Part.export. Rewrite to STEPControl_Writer.
  • pc2cad.py:5067 export_fcstd — keep FreeCAD-gated; document in error
    message; CLI does not expose it.
  • pc2cad.py:5183 _write_stl_binary — already OCP-data-ready; just needs
    the upstream data source changed.
  • pc2cad.py:5212 export_stl — uses _freecad_import, compound.tessellate.
    Rewrite to BRepMesh_IncrementalMesh + per-face BRep_Tool.Triangulation.
  • pc2cad.py:5288 compound.tessellate(tol) call site — replaced.

Boolean ops to migrate: shape.fuse / shape.cut / shape.common
(8 call sites in _cut_by_chamfers, _cut_by_fillet_tools, _cut_by_slot_tools,
_cut_by_hole_tools, derive_profile_features_from_sections) →
BRepAlgoAPI_Fuse / BRepAlgoAPI_Cut / BRepAlgoAPI_Common.

Already-working path that converges on this: pc2cad_profile.py +
pc2cad_cli.py::_export_build123d. The full profile_extrude → build123d
→ STEP pipeline was verified 2026-06-20 against
samples/sample_plane_cyl.ply (1 solid, 19 faces, 102 edges after STEP
round-trip via OCP.STEPControl_Reader). That is the reference
implementation.

Verification commands (run after every phase lands)

cd ~/Projects/pc2cad
python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.step --out-format step
file /tmp/test.step                                                  # ISO-10303 STEP
python -c "from OCP.STEPControl import STEPControl_Reader; r=STEPControl_Reader(); r.ReadFile('/tmp/test.step'); print(bool(r.TransferRoot()))"
python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.brep --out-format brep
python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.stl --out-format stl
python pc2cad_cli.py samples/organic_bunny.ply --out /tmp/bunny.step --mode hybrid --freeform poisson
python -m pytest tests/ -v
git grep -nE "import (FreeCAD|Part)$" pc2cad.py                          # zero hits outside export_fcstd

Acceptance

  1. --out X.step writes a real STEP file (>5 KB, valid AP214 header,
    readable by OCP.STEPControl_Reader) with no FreeCAD import.
  2. Same for --out-format stl and --out-format brep.
  3. git grep -nE "import (FreeCAD|Part)$" pc2cad.py returns no hits
    outside export_fcstd.
  4. tests/test_pipeline.py passes without FreeCAD test markers; the
    test_export_with_freecad test is either rewritten to use OCP or
    wrapped in pytest.importorskip("FreeCAD", reason="FreeCAD-only test").
  5. Bunny / torus-knot / vase samples still produce freeform Poisson
    mesh output via export_residual_mesh (open3d, unchanged).
  6. No _HAS_FREECAD block, no _freecad_import shim, no conditional
    fallback. Decision is final; this is a clean cutover.

Phase plan

P1: Rewrite _primitive_to_shape to use OCP constructors

Goal: Replace pc2cad.py:3592 _primitive_to_shape(FreeCAD, Part, primitive)
with an OCP-only equivalent that does not take FreeCAD/Part as parameters.
This is the per-primitive shape constructor every boolean and export op
funnels through, so it is the choke point.

Approach:

  • Sphere → BRepPrimAPI_MakeSphere(center, radius).Shape()
  • Cylinder → BRepPrimAPI_MakeCylinder(axis_point, axis_dir, radius, height).Shape()
  • Cone → BRepPrimAPI_MakeCone(...) (derive base/apex from primitive)
  • Plane (polygon face) → BRepBuilderAPI_MakeFace from the polygon's
    Poly_Triangulation or from the inlier-hull polygon as a TopoDS_Wire
    on a plane.
  • New signature: _primitive_to_shape(primitive: Primitive) -> TopoDS_Shape.
    Drop the FreeCAD, Part params.

Files: pc2cad.py:3592-3690 (rewrite _primitive_to_shape),
pc2cad.py:3583-3591 (delete _freecad_import).

Acceptance:

  • New function exists, old signature gone, no FreeCAD import.
  • git grep "def _primitive_to_shape" pc2cad.py shows the new signature.
  • All 8 boolean call sites (lines 3831, 4040, etc.) updated to the new
    signature; lint passes.
  • All existing tests still pass (no behavioural change yet — just signature).

P2: Migrate boolean ops to OCP (BRepAlgoAPI_*)

Goal: Replace shape.fuse / shape.cut / shape.common with OCP boolean
operations at every call site in pc2cad.py.

Approach: Use BRepAlgoAPI_Fuse / BRepAlgoAPI_Cut /
BRepAlgoAPI_Common. These are not method-chained like FreeCAD's — each
returns a BRepAlgoAPI_* object whose Shape() property gives the result.
Wrap in a small helper _fuse(shapes: List[TopoDS_Shape]) -> TopoDS_Shape
that handles the iterative fold.

Files: pc2cad.py:3809, 3831, 3843, 3851, 3860, 3869, 3925, 3944, 3971, 3978, 4040, 4183 — every .fuse / .cut / .common call site. Also the
boolean ops inside _cut_by_chamfers, _cut_by_fillet_tools,
_cut_by_slot_tools, _cut_by_hole_tools.

Acceptance:

  • git grep -nE "\.fuse\(|\.cut\(|\.common\(" pc2cad.py | grep -v _fuse_helper
    returns no hits.
  • python -m pytest tests/test_pipeline.py -v passes.
  • python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p2.step
    produces a valid STEP (boolean ops no longer raise NotImplementedError).

P3: Rewrite export_step to use STEPControl_Writer

Goal: Replace pc2cad.py:4991 export_step (FreeCAD + Part.export)
with an OCP STEPControl_Writer implementation.

Approach:

  • Build each primitive to TopoDS_Shape via _primitive_to_shape.
  • Fuse the per-primitive shapes into a single TopoDS_Compound via
    TopoDS_Builder.
  • Write via STEPControl_Writer: w = STEPControl_Writer();
    w.Transfer(compound, STEPControl_AsIs); w.Write(path).

Files: pc2cad.py:4991-5066 (rewrite export_step),
pc2cad.py:5063-5064 (replace Part.makeCompound + Part.export).

Acceptance:

  • python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p3.step
    writes a STEP file >5 KB.
  • file /tmp/p3.step reports "ISO-10303 STEP data".
  • OCP.STEPControl_Reader reads it back without error.

P4: Rewrite export_stl to use OCP mesh + binary writer

Goal: Replace pc2cad.py:5212 export_stl (FreeCAD + tessellate) with
an OCP BRepMesh_IncrementalMesh + binary writer pipeline. The
_write_stl_binary helper at pc2cad.py:5183 already accepts the
(vertices, triangles) shape; just feed it OCP data.

Approach:

  • Build the compound via the P3 path.
  • Mesh it: BRepMesh_IncrementalMesh(compound, tol).
  • For each face, read BRep_Tool.Triangulation(face, loc) to get
    Poly_Triangulation (nodes + triangles). Apply loc.Transformation() to
    node coordinates.
  • Flat-pack triangles (handle orientation) into vertices and triangles
    arrays; pass to _write_stl_binary.

Files: pc2cad.py:5212-5290 (rewrite export_stl),
pc2cad.py:5288-5289 (replace tessellate call).

Acceptance:

  • python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p4.stl --out-format stl writes a binary STL.
  • python -c "from stl import mesh; m=mesh.Mesh.from_file('/tmp/p4.stl'); print(len(m.vectors))" reports a positive triangle count.
  • Triangle count is in the same order of magnitude as the pre-rewrite
    FreeCAD-tessellate output for the same sample (±20%).

P5: Wire export_brep and update CLI / tests

Goal: Ensure export_brep (already OCP-capable via BRepTools.Write_s
per pc2cad_cli.py:513) is wired into the new pipeline. Update
tests/test_pipeline.py and add a no-FreeCAD regression test.

Approach:

  • Verify pc2cad_cli.py:513 export_brep uses OCP (it already imports it).
    If it relies on pc2cad.py internals, refactor to call into the new
    OCP-only export layer.
  • Add tests/test_pipeline.py::test_export_without_freecad that runs the
    full STEP/BREP/STL export on samples/sample_plane_cyl.ply without
    FreeCAD installed and asserts all three files are non-placeholder.
  • Wrap test_export_with_freecad (if it exists) in
    pytest.importorskip("FreeCAD", reason="FreeCAD-only test").

Files: pc2cad_cli.py:513, 530, 532, tests/test_pipeline.py.

Acceptance:

  • --out-format brep writes a valid BREP file with no FreeCAD import.
  • pytest tests/ -v passes with FreeCAD uninstalled in the test venv.
  • The FreeCAD-only test is properly skipped, not failed, when FreeCAD is
    absent.

P6: Final cleanup — delete _freecad_import, prove no FreeCAD in export paths

Goal: Remove every FreeCAD/Part reference from the export paths.
Verify the acceptance criteria from the original spec are met.

Approach:

  • Delete pc2cad.py:3583 _freecad_import function (no callers remain
    after P1-P5).
  • Confirm git grep -nE "import (FreeCAD|Part)$" pc2cad.py returns hits
    only inside export_fcstd (which is intentionally kept gated).
  • Run the full verification command set from the spec; capture output
    for the closing comment.
  • Update pointcloud-to-cad-guide.md to remove FreeCAD install
    instructions from the export pipeline section.

Files: pc2cad.py:3583-3591 (delete), pointcloud-to-cad-guide.md
(doc update).

Acceptance:

  • git grep -nE "import (FreeCAD|Part)$" pc2cad.py returns hits only in
    export_fcstd.
  • All 6 spec acceptance criteria from the parent issue pass.
  • pointcloud-to-cad-guide.md no longer tells users to install FreeCAD
    for exports.

Out of scope

  • Rewriting _fit_* analytic primitive fitting — only the export is broken.
  • Touching the pc2cad_profile.py build123d path — already working; this
    rewrite converges on it, doesn't replace it.
  • Touching export_residual_mesh — open3d-based, unchanged.
  • FreeCAD GUI support for users who explicitly want it. The CLI does not
    expose export_fcstd; the function still works for direct callers.
  • Closes #2 (root cause of the sandbox / install failure).
  • Closes #6 (profile_extrude / profile_revolve now exported via the
    new path).
  • Depends on #22 having landed (it has — pc2cad_profile.py +
    pc2cad_cli.py::_export_build123d are merged and working).
# Migrate `export_step` / `export_stl` / `export_brep` off FreeCAD, onto build123d + OCP ## Architectural stance (decided 2026-06-23) **FreeCAD is dropped from `pc2cad` exports, no fallback.** No `_HAS_FREECAD` conditional block, no migration shim, no "use FreeCAD if installed." Every export path runs on `OCP` + `build123d` (+ `numpy-stl` for binary STL), in a plain Python venv, with no system FreeCAD, no conda env, no AppImage, no PYTHONPATH surgery. `export_fcstd` stays gated on FreeCAD: `.FCStd` is a FreeCAD-Document.xml archive with no OCP equivalent, and the CLI does not expose it. The function keeps its `import FreeCAD` so anyone calling it directly still works; nothing else in `pc2cad.py` imports FreeCAD or Part. ## Blast radius (already mapped) FreeCAD/Part surface in `pc2cad.py`: - `pc2cad.py:3583` `_freecad_import` — the lazy import shim. Delete it. - `pc2cad.py:3592` `_primitive_to_shape(FreeCAD, Part, primitive)` — the per-primitive OCP shape constructor. **This is the rewrite target**, just stop taking `FreeCAD, Part` as parameters. - `pc2cad.py:4991` `export_step` — uses `_freecad_import`, `Part.makeCompound`, `Part.export`. Rewrite to `STEPControl_Writer`. - `pc2cad.py:5067` `export_fcstd` — keep FreeCAD-gated; document in error message; CLI does not expose it. - `pc2cad.py:5183` `_write_stl_binary` — already OCP-data-ready; just needs the upstream data source changed. - `pc2cad.py:5212` `export_stl` — uses `_freecad_import`, `compound.tessellate`. Rewrite to `BRepMesh_IncrementalMesh` + per-face `BRep_Tool.Triangulation`. - `pc2cad.py:5288` `compound.tessellate(tol)` call site — replaced. Boolean ops to migrate: `shape.fuse` / `shape.cut` / `shape.common` (8 call sites in `_cut_by_chamfers`, `_cut_by_fillet_tools`, `_cut_by_slot_tools`, `_cut_by_hole_tools`, `derive_profile_features_from_sections`) → `BRepAlgoAPI_Fuse` / `BRepAlgoAPI_Cut` / `BRepAlgoAPI_Common`. Already-working path that converges on this: `pc2cad_profile.py` + `pc2cad_cli.py::_export_build123d`. The full `profile_extrude` → build123d → STEP pipeline was verified 2026-06-20 against `samples/sample_plane_cyl.ply` (1 solid, 19 faces, 102 edges after STEP round-trip via `OCP.STEPControl_Reader`). That is the reference implementation. ## Verification commands (run after every phase lands) ```bash cd ~/Projects/pc2cad python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.step --out-format step file /tmp/test.step # ISO-10303 STEP python -c "from OCP.STEPControl import STEPControl_Reader; r=STEPControl_Reader(); r.ReadFile('/tmp/test.step'); print(bool(r.TransferRoot()))" python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.brep --out-format brep python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/test.stl --out-format stl python pc2cad_cli.py samples/organic_bunny.ply --out /tmp/bunny.step --mode hybrid --freeform poisson python -m pytest tests/ -v git grep -nE "import (FreeCAD|Part)$" pc2cad.py # zero hits outside export_fcstd ``` ## Acceptance 1. `--out X.step` writes a real STEP file (>5 KB, valid AP214 header, readable by `OCP.STEPControl_Reader`) with no FreeCAD import. 2. Same for `--out-format stl` and `--out-format brep`. 3. `git grep -nE "import (FreeCAD|Part)$" pc2cad.py` returns no hits outside `export_fcstd`. 4. `tests/test_pipeline.py` passes without FreeCAD test markers; the `test_export_with_freecad` test is either rewritten to use OCP or wrapped in `pytest.importorskip("FreeCAD", reason="FreeCAD-only test")`. 5. Bunny / torus-knot / vase samples still produce freeform Poisson mesh output via `export_residual_mesh` (open3d, unchanged). 6. No `_HAS_FREECAD` block, no `_freecad_import` shim, no conditional fallback. Decision is final; this is a clean cutover. --- ## Phase plan ### P1: Rewrite `_primitive_to_shape` to use OCP constructors **Goal:** Replace `pc2cad.py:3592 _primitive_to_shape(FreeCAD, Part, primitive)` with an OCP-only equivalent that does not take FreeCAD/Part as parameters. This is the per-primitive shape constructor every boolean and export op funnels through, so it is the choke point. **Approach:** - Sphere → `BRepPrimAPI_MakeSphere(center, radius).Shape()` - Cylinder → `BRepPrimAPI_MakeCylinder(axis_point, axis_dir, radius, height).Shape()` - Cone → `BRepPrimAPI_MakeCone(...)` (derive base/apex from primitive) - Plane (polygon face) → `BRepBuilderAPI_MakeFace` from the polygon's `Poly_Triangulation` or from the inlier-hull polygon as a `TopoDS_Wire` on a plane. - New signature: `_primitive_to_shape(primitive: Primitive) -> TopoDS_Shape`. Drop the FreeCAD, Part params. **Files:** `pc2cad.py:3592-3690` (rewrite `_primitive_to_shape`), `pc2cad.py:3583-3591` (delete `_freecad_import`). **Acceptance:** - New function exists, old signature gone, no FreeCAD import. - `git grep "def _primitive_to_shape" pc2cad.py` shows the new signature. - All 8 boolean call sites (lines 3831, 4040, etc.) updated to the new signature; lint passes. - All existing tests still pass (no behavioural change yet — just signature). --- ### P2: Migrate boolean ops to OCP (`BRepAlgoAPI_*`) **Goal:** Replace `shape.fuse / shape.cut / shape.common` with OCP boolean operations at every call site in `pc2cad.py`. **Approach:** Use `BRepAlgoAPI_Fuse` / `BRepAlgoAPI_Cut` / `BRepAlgoAPI_Common`. These are not method-chained like FreeCAD's — each returns a `BRepAlgoAPI_*` object whose `Shape()` property gives the result. Wrap in a small helper `_fuse(shapes: List[TopoDS_Shape]) -> TopoDS_Shape` that handles the iterative fold. **Files:** `pc2cad.py:3809, 3831, 3843, 3851, 3860, 3869, 3925, 3944, 3971, 3978, 4040, 4183` — every `.fuse / .cut / .common` call site. Also the boolean ops inside `_cut_by_chamfers`, `_cut_by_fillet_tools`, `_cut_by_slot_tools`, `_cut_by_hole_tools`. **Acceptance:** - `git grep -nE "\.fuse\(|\.cut\(|\.common\(" pc2cad.py | grep -v _fuse_helper` returns no hits. - `python -m pytest tests/test_pipeline.py -v` passes. - `python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p2.step` produces a valid STEP (boolean ops no longer raise NotImplementedError). --- ### P3: Rewrite `export_step` to use `STEPControl_Writer` **Goal:** Replace `pc2cad.py:4991 export_step` (FreeCAD + `Part.export`) with an OCP `STEPControl_Writer` implementation. **Approach:** - Build each primitive to `TopoDS_Shape` via `_primitive_to_shape`. - Fuse the per-primitive shapes into a single `TopoDS_Compound` via `TopoDS_Builder`. - Write via `STEPControl_Writer`: `w = STEPControl_Writer()`; `w.Transfer(compound, STEPControl_AsIs)`; `w.Write(path)`. **Files:** `pc2cad.py:4991-5066` (rewrite `export_step`), `pc2cad.py:5063-5064` (replace `Part.makeCompound` + `Part.export`). **Acceptance:** - `python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p3.step` writes a STEP file >5 KB. - `file /tmp/p3.step` reports "ISO-10303 STEP data". - `OCP.STEPControl_Reader` reads it back without error. --- ### P4: Rewrite `export_stl` to use OCP mesh + binary writer **Goal:** Replace `pc2cad.py:5212 export_stl` (FreeCAD + `tessellate`) with an OCP `BRepMesh_IncrementalMesh` + binary writer pipeline. The `_write_stl_binary` helper at `pc2cad.py:5183` already accepts the `(vertices, triangles)` shape; just feed it OCP data. **Approach:** - Build the compound via the P3 path. - Mesh it: `BRepMesh_IncrementalMesh(compound, tol)`. - For each face, read `BRep_Tool.Triangulation(face, loc)` to get `Poly_Triangulation` (nodes + triangles). Apply `loc.Transformation()` to node coordinates. - Flat-pack triangles (handle orientation) into `vertices` and `triangles` arrays; pass to `_write_stl_binary`. **Files:** `pc2cad.py:5212-5290` (rewrite `export_stl`), `pc2cad.py:5288-5289` (replace tessellate call). **Acceptance:** - `python pc2cad_cli.py samples/sample_plane_cyl.ply --out /tmp/p4.stl --out-format stl` writes a binary STL. - `python -c "from stl import mesh; m=mesh.Mesh.from_file('/tmp/p4.stl'); print(len(m.vectors))"` reports a positive triangle count. - Triangle count is in the same order of magnitude as the pre-rewrite FreeCAD-tessellate output for the same sample (±20%). --- ### P5: Wire `export_brep` and update CLI / tests **Goal:** Ensure `export_brep` (already OCP-capable via `BRepTools.Write_s` per `pc2cad_cli.py:513`) is wired into the new pipeline. Update `tests/test_pipeline.py` and add a no-FreeCAD regression test. **Approach:** - Verify `pc2cad_cli.py:513 export_brep` uses OCP (it already imports it). If it relies on `pc2cad.py` internals, refactor to call into the new OCP-only export layer. - Add `tests/test_pipeline.py::test_export_without_freecad` that runs the full STEP/BREP/STL export on `samples/sample_plane_cyl.ply` without FreeCAD installed and asserts all three files are non-placeholder. - Wrap `test_export_with_freecad` (if it exists) in `pytest.importorskip("FreeCAD", reason="FreeCAD-only test")`. **Files:** `pc2cad_cli.py:513, 530, 532`, `tests/test_pipeline.py`. **Acceptance:** - `--out-format brep` writes a valid BREP file with no FreeCAD import. - `pytest tests/ -v` passes with FreeCAD uninstalled in the test venv. - The FreeCAD-only test is properly skipped, not failed, when FreeCAD is absent. --- ### P6: Final cleanup — delete `_freecad_import`, prove no FreeCAD in export paths **Goal:** Remove every FreeCAD/Part reference from the export paths. Verify the acceptance criteria from the original spec are met. **Approach:** - Delete `pc2cad.py:3583 _freecad_import` function (no callers remain after P1-P5). - Confirm `git grep -nE "import (FreeCAD|Part)$" pc2cad.py` returns hits only inside `export_fcstd` (which is intentionally kept gated). - Run the full verification command set from the spec; capture output for the closing comment. - Update `pointcloud-to-cad-guide.md` to remove FreeCAD install instructions from the export pipeline section. **Files:** `pc2cad.py:3583-3591` (delete), `pointcloud-to-cad-guide.md` (doc update). **Acceptance:** - `git grep -nE "import (FreeCAD|Part)$" pc2cad.py` returns hits only in `export_fcstd`. - All 6 spec acceptance criteria from the parent issue pass. - `pointcloud-to-cad-guide.md` no longer tells users to install FreeCAD for exports. --- ## Out of scope - Rewriting `_fit_*` analytic primitive fitting — only the export is broken. - Touching the `pc2cad_profile.py` build123d path — already working; this rewrite converges on it, doesn't replace it. - Touching `export_residual_mesh` — open3d-based, unchanged. - FreeCAD GUI support for users who explicitly want it. The CLI does not expose `export_fcstd`; the function still works for direct callers. ## Related - Closes #2 (root cause of the sandbox / install failure). - Closes #6 (`profile_extrude` / `profile_revolve` now exported via the new path). - Depends on #22 having landed (it has — `pc2cad_profile.py` + `pc2cad_cli.py::_export_build123d` are merged and working).
Author
Owner

Auto-decomposition created

This issue has been automatically decomposed into workable sub-issues.

➡️ Track decomposition at pc2cad#25

## Auto-decomposition created This issue has been automatically decomposed into workable sub-issues. ➡️ Track decomposition at pc2cad#25
Author
Owner

Triage: decompose failed

Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this blocked:needs-decision to prevent re-evaluation. Remove the label to retry.

## Triage: decompose failed Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this `blocked:needs-decision` to prevent re-evaluation. Remove the label to retry.
Author
Owner

Triage: decompose failed

Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this blocked:needs-decision to prevent re-evaluation. Remove the label to retry.

## Triage: decompose failed Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this `blocked:needs-decision` to prevent re-evaluation. Remove the label to retry.
Author
Owner

Triage: decompose failed

Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this blocked:needs-decision to prevent re-evaluation. Remove the label to retry.

## Triage: decompose failed Triage pipeline could not create a sub-issue for auto-decomposition (API error or repo permissions). Marking this `blocked:needs-decision` to prevent re-evaluation. Remove the label to retry.
Author
Owner

This issue has been decomposed into the following sub-issues:

# Title Phase Scope
#41 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Replace pc2cad.py:3592 _primitive_to_shape(FreeCAD, Part, primitive)
#42 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Replace shape.fuse / shape.cut / shape.common with OCP boolean opera
#43 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Replace pc2cad.py:4991 export_step (FreeCAD + Part.export) with an
#44 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Replace pc2cad.py:5212 export_stl (FreeCAD + tessellate) with an O
#45 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Ensure export_brep (already OCP-capable via BRepTools.Write_s per
#46 Migrate export_step / export_stl / export_brep off FreeCAD, Goal: Remove every FreeCAD/Part reference from the export paths. Verify the

Each sub-issue has been labeled with triage-approved and is ready for queue routing.

This issue has been decomposed into the following sub-issues: | # | Title | Phase Scope | |---|-------|-------------| | #41 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Replace `pc2cad.py:3592 _primitive_to_shape(FreeCAD, Part, primitive)` | | #42 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Replace `shape.fuse / shape.cut / shape.common` with OCP boolean opera | | #43 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Replace `pc2cad.py:4991 export_step` (FreeCAD + `Part.export`) with an | | #44 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Replace `pc2cad.py:5212 export_stl` (FreeCAD + `tessellate`) with an O | | #45 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Ensure `export_brep` (already OCP-capable via `BRepTools.Write_s` per | | #46 | Migrate export_step / export_stl / export_brep off FreeCAD, | **Goal:** Remove every FreeCAD/Part reference from the export paths. Verify the | Each sub-issue has been labeled with `triage-approved` and is ready for queue routing.
Mark closed this issue 2026-06-24 03:24:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/pc2cad#23
No description provided.