Skip to content

Add rounded ring bands (tori) as a feature - #14

Merged
MasoudMiM merged 1 commit into
mainfrom
feature/tori
Oct 31, 2026
Merged

MasoudMiM merged 1 commit into
mainfrom
feature/tori

Conversation

@MasoudMiM

Copy link
Copy Markdown
Owner

Phase 2 item 3 (the last of the three feature-depth items): detect and rebuild full-revolution ring bands as editable PartDesign history.

What

A rounded ring band is a torus: a tube of revolution standing on a face. A band growing out of the face it sits on is a donut blend the fillet rule cannot claim (fillets are partial revolutions; a ring band is a full one) → torus_boss. A band cut into a face is a ring groove → torus_recess. PartDesign has no torus primitive, so the executor revolve-builds the band: a circular-arc profile sketched on a plane through the major axis, spun 360° as a PartDesign::Revolution (boss) or PartDesign::Groove (seat).

The core had no torus primitive at all, so a ring band was either left unassigned or absorbed by a straight-walled terrace pad (the right footprint at the wrong profile). This adds the full pipeline:

  • core/primitives.py: new Torus primitive (complexity 3, 7 dof).
  • core/fitting.py: new fit_torus fitter (least-variance axis — a ring is thin along its major axis, opposite a cylinder; circle in the (rho, h) cross-section; nonlinear refinement), registered in fit_best.
  • core/emission.py: _torus_patch (poloidal v = 0 at tube top, full-u from the toroidal angle).
  • core/features.py: torus_boss / torus_recess rules (rim annulus = two concentric circles where the tube is cut by the face; additive from the rim face's mean normal; axis out of the face for a boss, into the material for a seat).
  • core/history.py: TorusOp plan op + BuildPlan.tori.
  • core/solidify.py + tests/test_adversarial.py: headless torus-band rebuild for round-trip verification.
  • build.py: the revolve/groove executor branch (arcs built through 3 points so >180° profiles close).
  • scripts/freecad_smoke_test.py: ring-boss + ring-groove cases.

Impostor gates (the interesting part)

The flexible 7-dof fit grabs impostors a simpler fitter misses:

  • Conical — a short frustum's (rho, h) cross-section is arc-like, so the point fit alone can't tell a cone from a torus. A cone's surface normals all make the same angle with its axis, so the fit is rejected when the 95th-percentile normal angle stays below 60° (a genuine torus's normals wrap the tube, 0–90°). This is what was crashing the FreeCAD smoke test: a conical pocket's cone + top face merge into one segment (adaptive angle threshold 60°) and the torus fit won, never re-splitting.
  • Partial patch — a torus is a full ring (toroidal angle ~360°). A local curved patch, notably a slot's half-cylinder rounded end (where the cylinder fit fails on the partial circumference), covers only a narrow arc and is rejected when the toroidal-angle coverage is below 300°.

Scope

Rounded ring bosses and ring seats. Standalone donuts (no rim / no planar base) and partial-revolution bands are out of scope.

Verification

  • Headless suite: 580 passed, 1 xfailed (was 551 before the torus tests; includes 29 new test_torus.py tests — detection, planning, round-trip, and negatives incl. the slot-half-cylinder impostor).
  • FreeCAD 1.1.4 smoke test: 119 checks green, 0 failed (ring-boss and ring-groove volume-exact).

…ring band (torus_boss / torus_recess), plan as a TorusOp, and rebuild as a PartDesign::Revolution (additive boss) or PartDesign::Groove (subtractive seat) of a circular-arc profile. The core gained a Torus primitive and a fit_torus fitter (least-variance axis, (rho,h) circle). The fit carries two impostor gates -- conical (a cone's normals make a constant angle with its axis) and partial-patch (a torus wraps the major axis; a slot half-cylinder end does not) -- so truncated cones and slot ends are not mis-fit. 29 new test_torus.py tests (detection/planning/round-trip/negatives) + ring-boss and ring-groove smoke cases; headless suite 580 passed, FreeCAD smoke 119 checks green.
@MasoudMiM
MasoudMiM merged commit 872fc66 into main Oct 31, 2026
4 checks passed
@MasoudMiM
MasoudMiM deleted the feature/tori branch October 31, 2026 01:56
MasoudMiM added a commit that referenced this pull request Oct 31, 2026
ROADMAP: Phase 2 (cones/spheres/tori) marked done (PR #14, shipped in
v0.18.0); drop the stale '(current slice: feature/tori)' marker and the
'after v0.17.7' version anchor.
VERIFY: rewrite the stale 'Non-goals at v0.3' section (it still claimed
output was surface patches, not solids) as current known limitations;
describe the smoke-test output as the reconstructed parts rather than a
single cylinder + caps.
design-notes: add Torus to the primitives list in the Architecture
section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant