Single-plane profile_extrude produces wrong geometry + fitter regresses to 4 spheres on sample_plane_cyl.ply #24

Closed
opened 2026-06-20 19:22:33 +00:00 by Mark · 1 comment
Owner

Single-plane profile_extrude produces wrong geometry + fitter regresses to 4 spheres on sample_plane_cyl.ply

What happened

A side-by-side visual comparison of samples/sample_plane_cyl.ply against
the reconstructed STEP exposes two problems. Both were caught on
2026-06-20 while testing the new single-plane extrude fallback that was
introduced in commit 16404ff.

The input (7000 points, raw units = mm)

A vertical cylinder along the Z axis, ~30–40 mm diameter, ~100 mm tall,
intersected at mid-height by a horizontal plane slab parallel to the XY
plane, ~100×100 mm wide, ~1–2 mm thick.

Input point cloud

The output (1 solid, 19 faces, 158 triangles)

A thin plate 0.05 × 0.05 × 0.01 in model units. The cylinder is
entirely missing. The plane's full ~100×100 mm footprint is
collapsed to a 50×50 mm convex hull of the fitter's plane inliers.
There is no curved surface, no hole, no trace of the cylinder.

Reconstructed CAD

Side-by-side

Side by side

Two distinct bugs

Bug 1 — fitter regressed: cylinder → 4 spheres

The pre-16404ff report on this sample had primitives
plane + cone + sphere. The post-16404ff report has
plane + 4 spheres + profile_extrude. The cylinder is being broken
into 4 sphere fits instead of being classified as a cylinder.

This is the inverse of pc2cad#3 ("RANSAC primitive fitting unstable on
synthetic data — sphere misclassified as cylinder"). #3 is sphere
masquerading as a cylinder; #24 is the cylinder being broken into
spheres. Same underlying instability in the RANSAC search, opposite
direction. The cylinder's ~1000 axial points are being claimed greedily
by the densest 1000-point subset that happens to fit a sphere, and the
rest fragment into 3 more sphere fits.

Likely fix path (not for me to implement, the user said no local
patches): make the cylinder-vs-sphere RANSAC comparison penalize sphere
fits whose inlier distribution has high axial variance, or add a
post-RANSAC merge step that combines co-axial sphere fragments into a
cylinder. The original cone fit suggests this used to work; the new
profile_extrude emission may have changed segment assignment or
inlier-pool partitioning in a way that exposed the latent bug.

Bug 2 — single-plane extrude depth source is wrong

The new fallback in derive_profile_operations picks extrude depth
from the nearest cone/cylinder's t_max - t_min. When the fit produces
no axial primitive (because of bug 1), the fallback falls through to
"10% of the polygon's largest extent" — which gave the 0.01 m
thickness. That number is meaningless on a plane slab that should
have a depth of 1–2 mm (matching the pointcloud's ~1–2 mm slab
thickness, not 10 mm).

Likely fix path (also not for me): when no axial primitive is found,
the depth should be estimated from the pointcloud's local density /
bbox along the plane's normal direction, not from the polygon's XY
extent. The current 10%-of-extents heuristic is a stopgap that's
silently producing a 10×-too-thick plate on real input.

A second-order observation: even with a correct depth, the plane
should be reconstructed as a true bounded slab (i.e. trimmed to the
actual 100×100 mm pointcloud extent, not the convex hull of the
fitter's 3146 plane inliers, which is only ~50×50 mm because the
fitter capped inlier count). The polygon in the plane primitive is
the inlier hull, not the geometric extent. That's a separate concern
from bugs 1 and 2.

Verification commands

cd ~/Projects/pc2cad
python pc2cad_cli.py samples/sample_plane_cyl.ply \
  --out /tmp/sample_plane_cyl.step --out-format build123d
python /tmp/render_compare.py   # produces the 3 PNGs above
  • pc2cad#3 — sphere misclassified as cylinder (inverse direction of
    bug 1 here)
  • pc2cad#22 — build123d export path, the upstream this test exercises
  • pc2cad#23 — full FreeCAD→OCP port, the architectural fix for the
    rest of the export story
  • Commit 16404ff — the single-plane extrude fallback that exposed
    both bugs
# Single-plane profile_extrude produces wrong geometry + fitter regresses to 4 spheres on `sample_plane_cyl.ply` ## What happened A side-by-side visual comparison of `samples/sample_plane_cyl.ply` against the reconstructed STEP exposes two problems. Both were caught on 2026-06-20 while testing the new single-plane extrude fallback that was introduced in commit `16404ff`. ## The input (7000 points, raw units = mm) A vertical cylinder along the Z axis, ~30–40 mm diameter, ~100 mm tall, intersected at mid-height by a horizontal plane slab parallel to the XY plane, ~100×100 mm wide, ~1–2 mm thick. ![Input point cloud](https://forgejo.tail018ac4.ts.net/attachments/040d9389-fc1c-4cdb-bbd0-6e7895518aca) ## The output (1 solid, 19 faces, 158 triangles) A thin plate 0.05 × 0.05 × 0.01 in model units. The cylinder is **entirely missing**. The plane's full ~100×100 mm footprint is collapsed to a 50×50 mm convex hull of the fitter's plane inliers. There is no curved surface, no hole, no trace of the cylinder. ![Reconstructed CAD](https://forgejo.tail018ac4.ts.net/attachments/eeaba244-514d-43d5-9246-b0fadd25941a) ## Side-by-side ![Side by side](https://forgejo.tail018ac4.ts.net/attachments/7469d826-7570-4eb2-8948-2a3550f4ba7f) ## Two distinct bugs ### Bug 1 — fitter regressed: cylinder → 4 spheres The pre-`16404ff` report on this sample had primitives `plane + cone + sphere`. The post-`16404ff` report has `plane + 4 spheres + profile_extrude`. The cylinder is being broken into 4 sphere fits instead of being classified as a cylinder. This is the inverse of pc2cad#3 ("RANSAC primitive fitting unstable on synthetic data — sphere misclassified as cylinder"). #3 is sphere masquerading as a cylinder; #24 is the cylinder being broken into spheres. Same underlying instability in the RANSAC search, opposite direction. The cylinder's ~1000 axial points are being claimed greedily by the densest 1000-point subset that happens to fit a sphere, and the rest fragment into 3 more sphere fits. Likely fix path (not for me to implement, the user said no local patches): make the cylinder-vs-sphere RANSAC comparison penalize sphere fits whose inlier distribution has high axial variance, or add a post-RANSAC merge step that combines co-axial sphere fragments into a cylinder. The original cone fit suggests this used to work; the new profile_extrude emission may have changed segment assignment or inlier-pool partitioning in a way that exposed the latent bug. ### Bug 2 — single-plane extrude depth source is wrong The new fallback in `derive_profile_operations` picks extrude depth from the nearest cone/cylinder's `t_max - t_min`. When the fit produces no axial primitive (because of bug 1), the fallback falls through to "10% of the polygon's largest extent" — which gave the 0.01 m thickness. That number is meaningless on a plane slab that should have a depth of 1–2 mm (matching the pointcloud's ~1–2 mm slab thickness, not 10 mm). Likely fix path (also not for me): when no axial primitive is found, the depth should be estimated from the pointcloud's local density / bbox along the plane's normal direction, not from the polygon's XY extent. The current 10%-of-extents heuristic is a stopgap that's silently producing a 10×-too-thick plate on real input. A second-order observation: even with a correct depth, the plane should be reconstructed as a true bounded slab (i.e. trimmed to the actual 100×100 mm pointcloud extent, not the convex hull of the fitter's 3146 plane inliers, which is only ~50×50 mm because the fitter capped inlier count). The `polygon` in the plane primitive is the inlier hull, not the geometric extent. That's a separate concern from bugs 1 and 2. ## Verification commands ```bash cd ~/Projects/pc2cad python pc2cad_cli.py samples/sample_plane_cyl.ply \ --out /tmp/sample_plane_cyl.step --out-format build123d python /tmp/render_compare.py # produces the 3 PNGs above ``` ## Related - pc2cad#3 — sphere misclassified as cylinder (inverse direction of bug 1 here) - pc2cad#22 — build123d export path, the upstream this test exercises - pc2cad#23 — full FreeCAD→OCP port, the architectural fix for the rest of the export story - Commit `16404ff` — the single-plane extrude fallback that exposed both bugs
Mark closed this issue 2026-06-22 02:18:54 +00:00
Author
Owner

Closed — decomposed into three sub-issues on 2026-06-22:

  • #38 — bug 1: RANSAC cylinder→4-sphere regression
  • #39 — bug 2: single-plane extrude depth source is wrong
  • #40 — third concern: plane polygon is the inlier hull, not the geometric extent

Original body, attachments, and verification commands preserved here for reference. The three children carry the implementation work.

Closed — decomposed into three sub-issues on 2026-06-22: - #38 — bug 1: RANSAC cylinder→4-sphere regression - #39 — bug 2: single-plane extrude depth source is wrong - #40 — third concern: plane polygon is the inlier hull, not the geometric extent Original body, attachments, and verification commands preserved here for reference. The three children carry the implementation work.
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#24
No description provided.