Skip to content

Commit 466dd41

Browse files
committed
porting plan
1 parent c75b009 commit 466dd41

1 file changed

Lines changed: 366 additions & 0 deletions

File tree

PORTING_PLAN.md

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
# Porting Plan: hyperlimit, hyperlattice, and hyperreal
2+
3+
This plan describes how `csgrs` should be ported onto the `hyperlimit`,
4+
`hyperlattice`, and `hyperreal` stack without blurring ownership boundaries.
5+
The goal is to make `csgrs` more robust while keeping it focused on CSG and CAD
6+
modeling rather than turning it into a numeric kernel.
7+
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+
## Target ownership model
18+
19+
The stack should have clear vertical responsibilities:
20+
21+
```text
22+
hyperreal = scalar semantics and exact/structural real arithmetic
23+
hyperlattice = vectors, points, matrices, transforms, and scalar-backed linear algebra
24+
hyperlimit = robust geometric predicates and predicate carrier types
25+
csgrs = CSG objects, modeling operations, topology, metadata, IO, and user API
26+
```
27+
28+
### `hyperreal`
29+
30+
`hyperreal` should own scalar behavior:
31+
32+
- exact rationals
33+
- symbolic and computable reals
34+
- lazy approximation
35+
- sign, zero, magnitude, and structural facts
36+
- refinement and conservative comparison support
37+
38+
It should not own CSG, polygon, mesh, or CAD-specific geometry types.
39+
40+
### `hyperlattice`
41+
42+
`hyperlattice` should own the general linear algebra layer:
43+
44+
- `Scalar`
45+
- `Vector2`, `Vector3`, `Vector4`
46+
- `Point2`, `Point3` if the point types participate in affine APIs
47+
- `Matrix3`, `Matrix4`
48+
- transforms, dot products, cross products, normalization, and affine operations
49+
50+
It should not know about:
51+
52+
- polygon winding
53+
- BSP splitting
54+
- mesh manifoldness
55+
- CSG Boolean operations
56+
- triangulation policy
57+
- file formats
58+
- metadata propagation
59+
60+
### `hyperlimit`
61+
62+
`hyperlimit` should own robust predicate-facing geometry:
63+
64+
- minimal `Point2<S>` and `Point3<S>` carrier types
65+
- `Plane3<S>` in implicit form
66+
- predicate case structs for batching, where useful
67+
- orientation and classification results
68+
69+
It should provide:
70+
71+
- `orient2d`
72+
- `orient3d`
73+
- `incircle2d`
74+
- `insphere3d`
75+
- point-line classification
76+
- point-plane classification
77+
- oriented point-plane classification
78+
79+
These types should remain small and policy-free. `hyperlimit` should not own
80+
rich polygon, mesh, sketch, vertex, toolpath, or CSG types.
81+
82+
### `csgrs`
83+
84+
`csgrs` should continue to own product-level geometry:
85+
86+
- `Sketch<S>`
87+
- `Mesh<S>`
88+
- `Polygon<S>`
89+
- `Vertex`
90+
- BSP nodes and splitting logic
91+
- optional `BMesh` / manifold-backed representations
92+
- shape constructors
93+
- extrusion, revolve, sweep, loft, offset, and modeling operations
94+
- triangulation orchestration
95+
- smoothing, quality, manifold, and connectivity utilities
96+
- CNC/toolpath-facing types
97+
- import/export glue for STL, OBJ, PLY, DXF, Gerber, SVG, glTF, AMF, and WASM
98+
- metadata propagation rules
99+
100+
`csgrs` may re-export or alias lower-level point/vector/matrix types for user
101+
convenience, but it should avoid owning a new fundamental numeric geometry
102+
kernel once `hyperlattice` is available.
103+
104+
## Current `csgrs` type disposition
105+
106+
### Keep in `csgrs`
107+
108+
Keep these as `csgrs` types because they encode CSG or product semantics:
109+
110+
- `mesh::Mesh<S>`
111+
- `sketch::Sketch<S>`
112+
- `polygon::Polygon<S>`
113+
- `vertex::Vertex`
114+
- `bmesh::BMesh<S>`
115+
- `voxels` module types
116+
- `toolpath` module types
117+
- IO module types
118+
- shape-constructor APIs
119+
120+
`Vertex` should remain in `csgrs` while it means "mesh/render/CSG vertex" with a
121+
position, normal, interpolation behavior, and export implications. A lower-level
122+
point type should not absorb normals or shading semantics.
123+
124+
### Convert or wrap
125+
126+
The current `mesh::plane::Plane` should eventually stop being the authoritative
127+
robust predicate type. It can remain as a CSG face-plane cache or wrapper, but
128+
classification and splitting should delegate to `hyperlimit`.
129+
130+
Recommended direction:
131+
132+
- store face-plane data in whichever form is most useful for `Polygon<S>`
133+
- convert to `hyperlimit::Plane3` or oriented `hyperlimit::Point3` triples at
134+
predicate boundaries
135+
- use `hyperlimit` outcomes to classify vertices and polygons
136+
- keep CSG policy decisions, such as `COPLANAR`, `FRONT`, `BACK`, and
137+
`SPANNING`, in `csgrs`
138+
139+
### Stop owning long term
140+
141+
Long term, `csgrs` should not own independent definitions of fundamental:
142+
143+
- scalar semantics
144+
- generic vectors
145+
- generic points
146+
- generic matrices
147+
- generic robust predicates
148+
149+
Those should come from `hyperreal`, `hyperlattice`, and `hyperlimit`.
150+
151+
## Migration phases
152+
153+
### Phase 1: Audit the existing f64/epsilon predicate surface
154+
155+
Inventory every `csgrs` path that makes geometric decisions using f64,
156+
epsilon-based guards, or approximate equality.
157+
158+
Initial targets:
159+
160+
- `mesh::plane::Plane::eq`
161+
- point-plane classification
162+
- polygon splitting
163+
- BSP front/back/coplanar/spanning classification
164+
- coplanarity checks
165+
- point-line and point-plane tests used by triangulation or projection logic
166+
- any local robust predicate wrappers
167+
- guards that turn small magnitudes into zero
168+
- equality checks that affect topology or metadata propagation
169+
170+
For each path, record:
171+
172+
- the input type and coordinate source
173+
- the epsilon or tolerance rule
174+
- the output classification
175+
- the downstream policy decision in `csgrs`
176+
- whether the behavior is required compatibility or just an implementation
177+
accident
178+
179+
The audit output should become tests before implementation changes are made.
180+
181+
### Phase 2: Add `hyperlimit` parity and stress tests
182+
183+
Add `hyperlimit` tests that match the current `csgrs` predicate needs before
184+
replacing code in `csgrs`.
185+
186+
The test set should include:
187+
188+
- parity cases for current f64/epsilon behavior
189+
- near-coplanar polygons
190+
- near-degenerate triangles
191+
- spanning polygons with vertices close to the plane
192+
- point equality and near-equality cases that affect topology
193+
- oriented point-plane classification
194+
- point-line classification used by projection or triangulation
195+
- cases where current `csgrs` behavior is unstable or under-specified
196+
197+
The goal is not to freeze every old epsilon decision forever. The goal is to
198+
make the intended compatibility surface explicit, then let `hyperlimit` exceed
199+
it with better uncertainty handling and clearer classifications.
200+
201+
### Phase 3: Add the `hyperlimit` approximate backend needed by `csgrs`
202+
203+
Implement the `hyperlimit` approximate backend as the first replacement target
204+
for `csgrs`'s current f64 system.
205+
206+
This backend should:
207+
208+
- accept current `csgrs` f64-like coordinate data through adapters
209+
- expose the predicate results `csgrs` needs without exposing CSG policy
210+
- represent uncertainty explicitly
211+
- support the current classification cases, including `COPLANAR`, `FRONT`,
212+
`BACK`, and `SPANNING` translation at the `csgrs` boundary
213+
- centralize epsilon or approximate comparison behavior in `hyperlimit`
214+
- leave room for a later `hyperreal` backend behind the same predicate surface
215+
216+
After this phase, `hyperlimit` should be able to replace the f64/epsilon
217+
predicate machinery in `csgrs` without requiring a full scalar or public API
218+
port.
219+
220+
### Phase 4: Introduce explicit adapter boundaries
221+
222+
Add internal conversion helpers between current `csgrs` numeric types and the
223+
new stack:
224+
225+
- `nalgebra::Point2<Real>` to `hyperlimit::Point2<RealLike>`
226+
- `nalgebra::Point3<Real>` to `hyperlimit::Point3<RealLike>`
227+
- `mesh::plane::Plane` to oriented point triples or `hyperlimit::Plane3`
228+
- `nalgebra::Matrix4<Real>` to the chosen `hyperlattice` transform type once
229+
that API is stable enough
230+
231+
Keep these adapters private at first. The first milestone is internal
232+
correctness, not public API churn.
233+
234+
### Phase 5: Replace predicate calls and rip out local epsilon guards
235+
236+
Replace direct robust predicate usage and local f64/epsilon guards in `csgrs`
237+
with `hyperlimit` approximate-backend calls.
238+
239+
Initial targets:
240+
241+
- `mesh::plane::Plane::eq`
242+
- vertex classification in polygon splitting
243+
- coplanarity checks
244+
- point-line and point-plane tests used by triangulation or projection logic
245+
246+
The CSG layer should translate `hyperlimit` results into existing `csgrs`
247+
classification constants or enums.
248+
249+
Once coverage proves the replacement, remove the duplicated local predicate
250+
machinery from `csgrs`. `csgrs` should keep modeling policy such as
251+
`COPLANAR`, `FRONT`, `BACK`, and `SPANNING`, but it should not keep a second
252+
epsilon-based predicate implementation beside `hyperlimit`.
253+
254+
### Phase 6: Move linear algebra usage behind aliases
255+
256+
Introduce crate-local aliases for the public numeric types used throughout
257+
`csgrs`.
258+
259+
For example, instead of importing concrete third-party point/vector/matrix types
260+
throughout the codebase, route them through `float_types` or a successor module:
261+
262+
- `Point2`
263+
- `Point3`
264+
- `Vector2`
265+
- `Vector3`
266+
- `Matrix4`
267+
- `Real`
268+
269+
This makes the eventual switch from `nalgebra`-centered internals to
270+
`hyperlattice` incremental instead of global.
271+
272+
### Phase 7: Port transforms and constructors
273+
274+
Move transform-heavy APIs onto the chosen `hyperlattice` types:
275+
276+
- `translate`
277+
- `rotate`
278+
- `scale`
279+
- `mirror`
280+
- `transform`
281+
- shape constructors that build many points or normals
282+
- sweep, revolve, loft, and extrusion routines
283+
284+
Preserve existing user-facing ergonomics where possible. If public type changes
285+
are unavoidable, introduce them in a single documented release boundary.
286+
287+
### Phase 8: Revisit scalar configurability
288+
289+
Today `csgrs` selects `Real` through `f32` and `f64` features. After the
290+
predicate and linear algebra ports are stable, decide whether `csgrs` should:
291+
292+
- keep `f32` / `f64` as the primary public modes and use the new stack
293+
internally for robustness, or
294+
- become generic over a `hyperlattice` backend, or
295+
- offer a small set of backend feature modes.
296+
297+
The conservative default should be to preserve the current `Real`-based public
298+
API until the benefits of exposing backend generics are clear.
299+
300+
### Phase 9: Port the predicate backend toward `hyperreal`
301+
302+
After the f64/epsilon system has been replaced by `hyperlimit`'s approximate
303+
backend, add or enable a `hyperreal`-backed implementation behind the same
304+
predicate-facing API.
305+
306+
At this point, the semantic boundary should already be correct:
307+
308+
- `csgrs` owns CSG policy
309+
- `hyperlimit` owns predicate classification
310+
- `hyperreal` owns scalar refinement and exact/structural arithmetic
311+
312+
The hyperreal port should therefore focus on backend behavior, performance, and
313+
additional certificates rather than rewriting `csgrs` modeling logic again.
314+
315+
### Phase 10: Public API cleanup
316+
317+
After internals are stable:
318+
319+
- decide which lower-stack types to re-export
320+
- document the ownership model in the crate docs
321+
- deprecate redundant public helpers gradually
322+
- keep compatibility shims for common `nalgebra` interop if downstream users
323+
rely on it
324+
325+
## Design rules during the port
326+
327+
- Lower crates provide facts; `csgrs` makes modeling decisions.
328+
- Predicate uncertainty should be represented explicitly until `csgrs` decides
329+
how to handle it.
330+
- Metadata behavior remains entirely owned by `csgrs`.
331+
- IO formats should not leak lower-stack internals into public file APIs.
332+
- Avoid moving a type downward just because it contains coordinates.
333+
- Avoid making `hyperlimit` responsible for CSG concepts such as polygon
334+
splitting policy or manifold repair.
335+
- Prefer private adapters first, then public API changes after behavior is
336+
proven.
337+
338+
## Suggested first implementation target
339+
340+
Start with `mesh::plane`.
341+
342+
It is the highest-leverage boundary because polygon splitting and BSP Booleans
343+
depend on point-plane classification. A focused first change would:
344+
345+
1. Audit the existing `mesh::plane` f64/epsilon behavior.
346+
2. Add `hyperlimit` parity and stress tests for that behavior.
347+
3. Implement any approximate-backend features needed by those tests.
348+
4. Add conversion helpers from `csgrs::vertex::Vertex` and
349+
`csgrs::mesh::plane::Plane` into `hyperlimit` predicate inputs.
350+
5. Replace direct `robust::orient3d` comparisons with `hyperlimit::orient3d` or
351+
`hyperlimit::classify_point_oriented_plane`.
352+
6. Keep the existing `COPLANAR`, `FRONT`, `BACK`, and `SPANNING` constants.
353+
7. Remove the local epsilon predicates after `hyperlimit` coverage is in place.
354+
8. Add regression tests for near-coplanar and spanning polygons.
355+
9. Only then evaluate whether the internal `Plane` representation should change.
356+
357+
This gives an early robustness win without forcing a broad public API rewrite.
358+
359+
## Non-goals
360+
361+
- Do not move `Mesh<S>` or `Sketch<S>` into the lower stack.
362+
- Do not make `hyperlimit` a mesh-processing crate.
363+
- Do not make `hyperlattice` aware of file formats or CSG operations.
364+
- Do not expose backend generics everywhere until the ergonomics are proven.
365+
- Do not remove `nalgebra` interop until replacement ergonomics are clearly
366+
better for existing users.

0 commit comments

Comments
 (0)