Skip to content

Commit 094a67d

Browse files
committed
cavalier contours 2d backend
1 parent 738f578 commit 094a67d

17 files changed

Lines changed: 1421 additions & 181 deletions

File tree

Cargo.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ features = [
3434
"metaballs",
3535
"sdf",
3636
"offset",
37+
"cavalier",
3738
"delaunay",
3839
"truetype-text",
3940
"hershey-text",
@@ -69,6 +70,7 @@ spade = { version = "2.15.0", optional = true }
6970
earcutr = { version = "0.5.0", optional = true }
7071
delaunay-triangulator = { package = "delaunay", version = "0.7.6", optional = true }
7172
boolmesh = { version = "0.1.5", optional = true }
73+
cavalier_contours = { version = "0.7.0", path = "../cavalier_contours/cavalier_contours", optional = true }
7274

7375
rapier3d-f64 = { version = "0.31.0", optional = true }
7476
rapier3d = { version = "0.31.0", optional = true }
@@ -119,7 +121,7 @@ serde = { version = "1.0.228", optional = true }
119121
uuid = { version = "1.18", features = ["js"] }
120122

121123
[features]
122-
default = ["f64", "bmesh", "mesh", "sketch", "stl-io", "dxf-io", "obj-io", "ply-io", "amf-io", "gltf-io", "gerber-io", "chull-io", "image-io", "metaballs", "sdf", "offset", "delaunay", "truetype-text", "hershey-text"]
124+
default = ["f64", "bmesh", "mesh", "sketch", "cavalier", "stl-io", "dxf-io", "obj-io", "ply-io", "amf-io", "gltf-io", "gerber-io", "chull-io", "image-io", "metaballs", "sdf", "offset", "delaunay", "truetype-text", "hershey-text"]
123125
parallel = [
124126
"rayon",
125127
"geo/multithreading",
@@ -149,6 +151,9 @@ sketch = [
149151
bmesh = [
150152
"boolmesh",
151153
]
154+
cavalier = [
155+
"dep:cavalier_contours",
156+
]
152157
# convex hull and minkowski sum
153158
chull-io = [
154159
"chull",

PORTING_PLAN.md

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,32 @@ This plan describes how `csgrs` should be ported onto the `hyperlimit`,
55
The goal is to make `csgrs` more robust while keeping it focused on CSG and CAD
66
modeling rather than turning it into a numeric kernel.
77

8-
The immediate transition should not jump straight from `csgrs`'s current
9-
f64/epsilon behavior to full `hyperreal` semantics. First, audit the existing
10-
f64 predicates and epsilon guards, teach `hyperlimit` to match or exceed those
11-
needs through an approximate backend, and then remove the duplicated
12-
`csgrs`-local epsilon system. Once `csgrs` depends on `hyperlimit` for
13-
approximate predicate behavior, porting the same predicate surface to
14-
`hyperreal` becomes a backend upgrade instead of a simultaneous semantic and API
15-
rewrite.
16-
17-
The approximate f64 phase should evaluate
18-
[`decorum`](https://github.com/olson-sean-k/decorum) as a bridge for making
19-
floating-point behavior explicit before the full `hyperreal` port. `decorum`
20-
provides constrained IEEE-754 proxy types with total ordering, equivalence,
21-
hashing, configurable handling of non-real values, and `approx` integration.
22-
Those properties map directly to several current `csgrs` pain points: finite
23-
coordinate enforcement, deterministic map/set keys, explicit NaN/infinity
24-
policy, and centralized approximate comparisons.
8+
The immediate transition should make `hyperreal` the primary numerical
9+
backbone. Auditing the current f64/epsilon behavior is still necessary, but only
10+
to capture compatibility fixtures, document old failure modes, and identify
11+
edge adapters. The replacement implementation should route scalar semantics
12+
through `hyperreal`, geometry storage and transforms through `hyperlattice`,
13+
and geometric decisions through `hyperlimit` predicates.
14+
15+
f64 support is allowed only at explicit interaction boundaries: existing public
16+
compatibility constructors, WASM/FFI bindings, file import/export, and
17+
third-party libraries that have not yet been harvested into the hyperreal stack.
18+
Adapters may use tools such as
19+
[`decorum`](https://github.com/olson-sean-k/decorum) to make finite IEEE-754
20+
policy explicit, but those adapters are not a core numerical backend and must
21+
not make silent topology decisions.
22+
23+
## Numerical backbone policy
24+
25+
- Hyperreal-backed values are the canonical internal numeric representation.
26+
- f64 is an edge format for compatibility, external libraries, and language
27+
bindings.
28+
- Every f64 boundary must be named, centralized, tested, and documented as
29+
exact lifting, lossy approximation, rejected input, or lossy export.
30+
- No f64-only algorithm should become a permanent core dependency for boolean,
31+
predicate, triangulation, contour, offset, or construction decisions.
32+
- Approximate witnesses may propose candidates, but hyperlimit/hyperreal
33+
predicates must certify topology or return explicit uncertainty.
2534

2635
## Branch and commit discipline during the port
2736

@@ -333,15 +342,16 @@ The goal is not to freeze every old epsilon decision forever. The goal is to
333342
make the intended compatibility surface explicit, then let `hyperlimit` exceed
334343
it with better uncertainty handling and clearer classifications.
335344

336-
### Phase 3: Add the `hyperlimit` approximate backend needed by `csgrs`
345+
### Phase 3: Add `hyperlimit` f64-boundary compatibility needed by `csgrs`
337346

338-
Implement the `hyperlimit` approximate backend as the first replacement target
339-
for `csgrs`'s current f64 system.
347+
Implement only the f64-boundary compatibility needed to replace `csgrs`'s
348+
current scattered f64 system while keeping hyperreal as the target internal
349+
numeric model.
340350

341-
This backend should:
351+
This boundary layer should:
342352

343353
- accept current `csgrs` f64-like coordinate data through adapters
344-
- evaluate `decorum` constrained f64 proxy types for the approximate backend's
354+
- evaluate `decorum` constrained f64 proxy types for adapter-local
345355
scalar carrier, especially where finite-real invariants, total ordering,
346356
equality, hashing, or `approx` traits are required
347357
- use `decorum` at adapter and predicate boundaries first, not as a broad public
@@ -352,18 +362,20 @@ This backend should:
352362
- represent uncertainty explicitly
353363
- support the current classification cases, including `COPLANAR`, `FRONT`,
354364
`BACK`, and `SPANNING` translation at the `csgrs` boundary
355-
- centralize epsilon or approximate comparison behavior in `hyperlimit`
356-
- leave room for a later `hyperreal` backend behind the same predicate surface
365+
- centralize legacy epsilon or approximate comparison behavior at named
366+
boundaries
367+
- feed the hyperreal-backed predicate surface rather than becoming a parallel
368+
topology backend
357369

358370
After this phase, `hyperlimit` should be able to replace the f64/epsilon
359-
predicate machinery in `csgrs` without requiring a full scalar or public API
360-
port.
371+
predicate machinery in `csgrs` without spreading primitive f64 decisions through
372+
the port.
361373

362374
`decorum` should remain a transition and evaluation tool unless it proves to be
363-
the right implementation detail for the approximate backend. The long-term
364-
numeric ownership model still routes scalar semantics through `hyperreal`; any
365-
`decorum` use should either disappear behind `hyperlimit`/`hyperlattice`
366-
backend traits or become an internal f64 compatibility backend.
375+
the right implementation detail for f64 edge adapters. The long-term numeric
376+
ownership model routes scalar semantics through `hyperreal`; any `decorum` use
377+
should either disappear behind `hyperlimit`/`hyperlattice` traits or remain an
378+
internal f64 compatibility adapter.
367379

368380
### Phase 4: Introduce explicit adapter boundaries
369381

@@ -430,7 +442,8 @@ correctness, not public API churn.
430442
### Phase 5: Replace predicate calls and rip out local epsilon guards
431443

432444
Replace direct robust predicate usage and local f64/epsilon guards in `csgrs`
433-
with `hyperlimit` approximate-backend calls.
445+
with `hyperlimit` calls that feed the hyperreal-backed predicate surface. f64
446+
compatibility behavior should remain confined to named boundary adapters.
434447

435448
Initial targets:
436449

@@ -549,7 +562,7 @@ Implementation plan:
549562
- add deprecation notes that point old `*_vector` and component methods toward
550563
the new trait-based input forms
551564
- route all coordinate conversion through the same finite/non-finite policy used
552-
by the approximate backend adapters
565+
by the f64 boundary adapters
553566
- add examples that demonstrate tuple, array, nalgebra, and future
554567
hyperlattice-compatible input forms side by side
555568
- add hyperreal constructor examples that demonstrate exact rational sketches,
@@ -614,19 +627,19 @@ are unavoidable, introduce them in a single documented release boundary.
614627
Today `csgrs` selects `Real` through `f32` and `f64` features. After the
615628
predicate and linear algebra ports are stable, decide whether `csgrs` should:
616629

617-
- keep `f32` / `f64` as the primary public modes and use the new stack
618-
internally for robustness, or
619-
- become generic over a `hyperlattice` backend, or
620-
- offer a small set of backend feature modes.
630+
- make the hyperreal-backed mode the primary public mode,
631+
- keep `f32` / `f64` only as compatibility/interop constructor and export
632+
features, or
633+
- expose a very small set of backend feature modes for advanced users.
621634

622635
The conservative default should be to preserve the current `Real`-based public
623-
API until the benefits of exposing backend generics are clear.
636+
API shape where possible while changing its internal backbone to hyperreal.
624637

625-
### Phase 9: Port the predicate backend toward `hyperreal`
638+
### Phase 9: Complete and optimize the hyperreal predicate backend
626639

627-
After the f64/epsilon system has been replaced by `hyperlimit`'s approximate
628-
backend, add or enable a `hyperreal`-backed implementation behind the same
629-
predicate-facing API.
640+
As the f64/epsilon system is replaced by `hyperlimit` boundary adapters and
641+
hyperreal-backed predicates, complete the `hyperreal` implementation behind the
642+
same predicate-facing API.
630643

631644
At this point, the semantic boundary should already be correct:
632645

@@ -835,12 +848,12 @@ Required fuzz targets:
835848

836849
- fuzz 2D predicate triples and compare classification invariants
837850
- fuzz 3D predicate quadruples and compare classification invariants
838-
- fuzz finite/non-finite scalar payloads into approximate backend adapters
851+
- fuzz finite/non-finite scalar payloads into f64 boundary adapters
839852
- fuzz serialized parity fixtures so corpus entries survive backend changes
840853

841-
### Phase 3 approximate backend and decorum tests
854+
### Phase 3 f64 boundary and decorum tests
842855

843-
The approximate backend must prove that it centralizes f64 policy:
856+
The f64 boundary layer must prove that it centralizes f64 policy:
844857

845858
- finite scalar wrapper tests
846859
- accepts ordinary finite values
@@ -863,7 +876,7 @@ The approximate backend must prove that it centralizes f64 policy:
863876
- uncertain results can be logged or inspected in diagnostics
864877
- uncertainty is not silently coerced in lower crates
865878
- epsilon centralization tests
866-
- there is one source of tolerance policy for f64 approximate predicates
879+
- there is one source of tolerance policy for f64 boundary predicates
867880
- per-call override behavior, if any, is explicit
868881
- old local tolerance helpers are not used after replacement
869882

@@ -1241,7 +1254,7 @@ When moving 2D contour logic toward a hyperreal-aware path:
12411254
- winding normalization
12421255
- differential tests:
12431256
- current `geo-buffer`/offset behavior vs new contour backend
1244-
- f64 transitional path vs hyperreal path
1257+
- f64 boundary path vs hyperreal path
12451258
- known simple analytic offsets
12461259
- fuzz tests:
12471260
- random closed polylines
@@ -1318,7 +1331,7 @@ internals:
13181331
- threshold sweeps
13191332
- large images and memory bounds
13201333
- cross-backend:
1321-
- exported geometry from f64 approximate backend imports under hyperreal mode
1334+
- exported geometry from f64 boundary adapters imports under hyperreal mode
13221335
- hyperreal-generated output can be approximated for ordinary file formats
13231336
- IO paths never require `hyperreal` public types unless explicitly enabled
13241337

@@ -1515,10 +1528,10 @@ Implementation plan:
15151528
decisions
15161529
- add lint/search gates that prevent direct `Real` determinant signs in CSG
15171530
control flow once the predicate layer is active
1518-
- model the first backend after CGAL's exact-predicate/inexact-construction
1519-
split: f64 storage with robust predicate classification
1520-
- add a second backend that uses exact or hyperreal constructions for selected
1521-
operations, starting with polygon splitting and surface intersection points
1531+
- model the primary backend after a hyperreal exact-predicate/exact-or-certified
1532+
construction split
1533+
- allow inexact/f64 construction adapters only at import/export or third-party
1534+
library boundaries
15221535
- include "construction poisoning" tests where an inexact split point is reused
15231536
by later predicates; the test should prove whether the backend refines,
15241537
reports uncertainty, or preserves the current f64 behavior intentionally
@@ -1863,8 +1876,8 @@ Implementation plan:
18631876
plane classification, and convex hull-style examples
18641877
- keep each demo minimal enough to explain in a failing assertion message
18651878
- add README or developer-doc snippets showing why each demo matters
1866-
- run the same demos against f64 approximate, `hyperlimit`, and hyperreal
1867-
backends
1879+
- run the same demos against f64 boundary adapters, `hyperlimit`, and hyperreal
1880+
paths
18681881
- preserve any old f64 failures as ignored tests or documented divergence tests
18691882
until replacement is complete
18701883

@@ -1935,8 +1948,9 @@ Show-off examples:
19351948
- IO formats should not leak lower-stack internals into public file APIs.
19361949
- WASM is a supported platform target and binding layer, not a consumed or
19371950
produced geometry file format.
1938-
- Non-`csgrs` algorithms start behind explicit f64 conversion adapters, then
1939-
move toward harvested or native hyperreal implementations.
1951+
- Non-`csgrs` algorithms start behind explicit f64 conversion adapters only
1952+
when unavoidable, then move toward harvested or native hyperreal
1953+
implementations.
19401954
- Avoid moving a type downward just because it contains coordinates.
19411955
- Avoid making `hyperlimit` responsible for CSG concepts such as polygon
19421956
splitting policy or manifold repair.
@@ -1955,7 +1969,8 @@ behavior is under test. A focused first change would:
19551969

19561970
1. Audit the existing `mesh::plane` f64/epsilon behavior.
19571971
2. Add `hyperlimit` parity and stress tests for that behavior.
1958-
3. Implement any approximate-backend features needed by those tests.
1972+
3. Implement any hyperlimit predicate or f64-boundary adapter features needed by
1973+
those tests.
19591974
4. Add conversion helpers from `csgrs::vertex::Vertex` and
19601975
`csgrs::mesh::plane::Plane` into `hyperlimit` predicate inputs.
19611976
5. Replace direct `robust::orient3d` comparisons with `hyperlimit::orient3d` or

0 commit comments

Comments
 (0)