|
| 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