# Phase 8 — CGAL Package Design > **Status: design frozen, implementation planned.** > This document captures the strategic decisions taken before the first > line of Phase 8 code is written. The decisions were taken on 2026-05-19 > after the docstring/architecture audit at the end of Phase 7. > > The design is informed by the CGAL package submission guidelines at > https://www.cgal.org/developers.html and by reading the existing > `Polygon_mesh_processing` and `Surface_mesh_parameterization` packages. --- ## Strategic position | Question | Decision | Rationale | |---|---|---| | Submission to CGAL? | **Pre-submission-ready, not submission-bound.** 12+ months horizon, optional. | Keep design freedom, no editor-review pressure. Structure is valuable on its own. | | License | **MIT preserved.** | CGAL submission would require LGPL — deferred. Current users (academic + industrial) profit from MIT. | | Mesh-type flexibility | **Generic `FaceGraph + HalfedgeGraph`.** | Maximum CGAL value: works with `Surface_mesh`, `Polyhedron_3`, OpenMesh-adapter, pmp. | | Parameter style | **Named Parameters** (`CGAL::parameters::vertex_curvature_map(...).max_iterations(50)`). | CGAL standard; identical UX to `PMP::triangulate_*`. | | Default kernel | **`CGAL::Simple_cartesian`.** | Status quo. Conformal geometry does not require exact predicates. | | Backward compatibility | **Dual-layer wrapper.** `code/include/*.hpp` stays as implementation; `include/CGAL/*.h` is thin wrapper. | Existing 176 + 36 tests unchanged. New API gets new tests. | | Algorithm code | **No duplication.** New CGAL headers delegate to existing code via property-map adapters. | Single source of truth; no parallel maintenance. | --- ## Architecture ### Three-layer model ``` ┌──────────────────────────────────────────────────────────────────┐ │ Layer 3: Public CGAL API include/CGAL/*.h │ │ ───────────────────────── │ │ • Conformal_map_traits.h ← concept + default model │ │ • Discrete_conformal_map.h ← user-facing entry │ │ • Conformal_layout.h, ... │ │ Named parameters, generic over FaceGraph, Doxygen-documented. │ └──────────────────────────────────────────────────────────────────┘ ▲ │ thin wrapper, no algorithm code │ ┌──────────────────────────────────────────────────────────────────┐ │ Layer 2: Adapter / Traits include/CGAL/Conformal_map/ │ │ ───────────────────────── │ │ • Default_traits.h ← maps generic FaceGraph to │ │ Surface_mesh property maps │ │ • Property_map_adapter.h ← read/write u, θ, α via │ │ boost::property_map traits │ └──────────────────────────────────────────────────────────────────┘ ▲ │ uses existing algorithms as-is │ ┌──────────────────────────────────────────────────────────────────┐ │ Layer 1: Implementation code/include/*.hpp │ │ ───────────────────────── │ │ euclidean_functional.hpp, layout.hpp, newton_solver.hpp, ... │ │ Hardcoded to Surface_mesh + Simple_cartesian — unchanged. │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## 8a — Traits class & concepts ### `ConformalMapTraits` concept The concept lists the types and operations every Traits model must provide. ```cpp namespace CGAL { // Concept (documentation only; no code): struct ConformalMapTraits { // Types using Triangle_mesh = ...; // model of FaceGraph + HalfedgeGraph using FT = ...; // typically double using Vertex_descriptor = boost::graph_traits::vertex_descriptor; using Halfedge_descriptor = ...; using Face_descriptor = ...; // Read access (input geometry) using Vertex_point_map = ...; // model of ReadablePropertyMap // key: Vertex_descriptor // value: K::Point_3 // Read/write access (conformal data) using Lambda_pmap = ...; // u_v (scale factor) RW using Theta_pmap = ...; // Θ_v (target curvature) R using Vertex_index_pmap = ...; // DOF index (−1 = pinned) RW using Edge_alpha_pmap = ...; // α_e (hyperbolic only) RW using Face_type_pmap = ...; // geometry tag per face R // Optional output using UV_pmap = ...; // halfedge → (u, v) ∈ ℝ² W using Holonomy_pmap = ...; // seam edge → ω ∈ ℂ W }; } ``` ### `Default_conformal_map_traits` The default model wraps `Surface_mesh` property maps so existing code keeps working through the new public API. ```cpp template > struct Default_conformal_map_traits; // Specialisation for Surface_mesh: template struct Default_conformal_map_traits, K> { using Triangle_mesh = CGAL::Surface_mesh; using FT = typename K::FT; using Vertex_point_map = typename Triangle_mesh::Point_property_map; using Lambda_pmap = typename Triangle_mesh::template Property_map; // ... etc, using "conformal:lambda" property names }; // Generic specialisation for other FaceGraph models will be added in 8a.2. ``` ### Concept-checks ```cpp // include/CGAL/Conformal_map_concept_checks.h template struct Conformal_map_traits_check { static_assert(boost::is_same<...>::value, "Traits::FT must be a floating-point type"); static_assert(is_face_graph::value); // ... }; ``` --- ## 8b — Public CGAL header hierarchy ### User-facing entry ```cpp // include/CGAL/Discrete_conformal_map.h namespace CGAL { template bool discrete_conformal_map_euclidean(TriangleMesh& mesh, const NamedParameters& np = parameters::default_values()); template bool discrete_conformal_map_spherical(TriangleMesh& mesh, const NamedParameters& np = ...); template bool discrete_conformal_map_hyperbolic(TriangleMesh& mesh, const NamedParameters& np = ...); } // namespace CGAL ``` ### Named parameter vocabulary | Parameter | Type | Default | Meaning | |---|---|---|---| | `vertex_curvature_map(pmap)` | ReadablePropertyMap | `2π` at interior, `π` at boundary | Θᵥ values | | `fixed_vertex_pmap(pmap)` | ReadablePropertyMap | First vertex pinned | Which vertices are pinned (gauge) | | `max_iterations(n)` | int | 200 | Newton iteration limit | | `gradient_tolerance(eps)` | FT | 1e-10 | `‖G‖∞` threshold | | `vertex_index_map(pmap)` | LvaluePropertyMap | DOF auto-assigned | Allows user to override DOF assignment | | `output_uv_map(pmap)` | WritablePropertyMap | none | If set, writes UV layout into pmap | | `cut_graph(cg)` | `Conformal_cut_graph` | auto-computed | Pre-computed seam edges (mandatory for closed surfaces) | | `geom_traits(t)` | model of ConformalMapTraits | `Default_*` | Custom traits | ### Modular headers ``` include/CGAL/ ├── Discrete_conformal_map.h ← user-facing entry (1 include for casual use) ├── Conformal_map_traits.h ← concept + Default_conformal_map_traits ├── Conformal_map_concept_checks.h ├── Conformal_newton_solver.h ← standalone Newton (advanced users) ├── Conformal_layout.h ← layout + holonomy ├── Conformal_cut_graph.h ← orthogonal algorithm ├── Conformal_period_matrix.h ← genus-1 τ (conformallab++ unique) ├── Conformal_holonomy.h ← Möbius holonomy (conformallab++ unique) └── Conformal_map/ ← CGAL convention: implementation details ├── Default_traits.h ├── Property_map_adapter.h ├── Newton_iteration.h └── Internal_helpers.h ``` --- ## 8c — CGAL-style documentation ``` doc/Conformal_map/ ├── PackageDescription.txt ← CGAL Doxygen package file ├── Conformal_map.txt ← Doxygen User_manual ├── examples.txt ← linkable example code ├── dependencies ← textual list └── fig/ ← pipeline diagrams, math figures ``` All public functions, concepts, and types require Doxygen. See **Phase 7.5** (below). --- ## 8d — CGAL test format ``` test/Conformal_map/ ├── CMakeLists.txt ← CGAL-format, uses find_package(CGAL) ├── test_euclidean_traits.cpp ← traits concept checks ├── test_polyhedron_3_backend.cpp ← tests with Polyhedron_3 as mesh ├── test_named_parameters.cpp └── data/ ← test meshes ``` The existing GTest suite at `code/tests/cgal/` remains; CGAL-format tests are added alongside as a separate target. CI runs both. --- ## 8e — Declarative YAML pipeline A lightweight YAML format for reproducible experiments. CLI accepts `--pipeline experiment.yml`; the validator checks `require`/`provide` tokens before execution. **Full spec:** [doc/concepts/declarative-pipeline.md](../concepts/declarative-pipeline.md) — token vocabulary, validation algorithm, 5 complete examples. ```yaml pipeline: name: flat_torus_period geometry: euclidean input: { source: data/torus.off } steps: - { id: setup, unit: setup_euclidean_maps, provide: [maps_initialised] } - { id: gb, unit: enforce_gauss_bonnet, require: [maps_initialised], provide: [gauss_bonnet_satisfied] } - { id: solve, unit: newton_euclidean, require: [gauss_bonnet_satisfied], provide: [x_converged] } - { id: cut, unit: compute_cut_graph, require: [mesh_closed], provide: [cut_graph] } - { id: layout, unit: euclidean_layout, require: [x_converged, cut_graph], provide: [layout_uv, holonomy] } - { id: period, unit: compute_period_matrix, require: [holonomy], provide: [tau] } output: layout: out/torus_layout.off json: out/torus_result.json ``` --- ## Phase 7.5 — Doxygen infrastructure (prerequisite) Before any Phase 8 code, the existing API surface must be extractable. This is the prerequisite that bridges Phase 7 → Phase 8. ``` Phase 7.5 — Doxygen infrastructure ────────────────────────────────── • Doxyfile (CGAL-conform: INPUT=code/include + include/CGAL, EXCLUDE_PATTERNS="* 2.hpp") • doxygen-awesome-css as theme (matches CGAL house style) • CMake target: cmake --build build --target doc • CI job: doc-build → publishes to Codeberg Pages or gitea-pages • Extract baseline once → snapshot what is actually exported today • Top-5 central headers (3 functional + conformal_mesh + layout) upgraded to Doxygen comments; the rest follows during Phase 8 implementation ``` The baseline snapshot doubles as the API-design review tool: before designing the public CGAL wrapper, we see exactly which functions, classes and free operators exist and need to be wrapped or hidden. --- ## Validation criteria Phase 8a is "done" when: 1. `cgal.ConformalTraits.Polyhedron_3_works` passes. 2. `cgal.ConformalTraits.Surface_mesh_default_works` passes — identical results to the legacy API. 3. The Inversive-Distance functional (Phase 9a) is implementable as the *first* new client of the traits API without architectural changes — no breaking changes to the trait concept. 4. A user can write `#include ` and call `discrete_conformal_map_euclidean(mesh, parameters::vertex_curvature_map(theta))` against a `Polyhedron_3` and get a valid layout. If any of these fail, the design is iterated before continuing. --- ## Implementation strategy — "Hybrid MVP" (decided 2026-05-19) After cost/benefit re-evaluation, the plan is **not** to build Phase 8 in full before resuming the port. Instead: ``` ┌────────────────────────────────────────────────────────────────────┐ │ PHASE 8 MVP (3–5 days) │ │ ───────────────────── │ │ Just enough CGAL-style architecture for Phase 9a to validate it. │ │ │ │ • Conformal_map_traits.h concept + Default │ │ • Discrete_conformal_map.h ONE entry: _euclidean() │ │ • 4 named parameters Θ-map, max_iter, tol, pin │ │ • Concept-check header │ │ • Doxygen on these 3 headers │ └────────────────────────────────────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────────┐ │ PHASE 9a — Inversive-Distance (3–5 days) │ │ ────────────────────────────────── │ │ Built directly against the new traits API. This is the │ │ acceptance test for the MVP. │ │ │ │ If painless → MVP design is sound, continue with Phase 9b/9c │ │ If painful → iterate the traits design before going further │ └────────────────────────────────────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────────┐ │ PHASE 9b — Analytic HyperIdeal Hessian (1 week) │ │ PHASE 9c — 4g-polygon fundamental domain (1 week) │ │ ──────────────────────────────────────── │ │ Port really finished. v0.9.0 release possible. │ └────────────────────────────────────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────────┐ │ PHASE 8 EXTENSIONS — only on demand │ │ ───────────────────────────────── │ │ • 8a.2 generic FaceGraph specialisation when Polyhedron_3 user │ │ • 8b extend to spherical + hyperbolic when 9a pattern proven │ │ • 8c full User_manual + Reference_manual when submission planned│ │ • 8d CGAL-format test directory when submission planned│ │ • 8e YAML pipeline + CLI flag orthogonal, any time │ │ │ │ Each extension only when there is a concrete trigger. No │ │ speculative architecture for a hypothetical CGAL submission. │ └────────────────────────────────────────────────────────────────────┘ ``` **Why this order?** - Port-completion (Phase 9) is the higher-confidence value: well-defined, ~3 weeks of work, finishes Goal A. - Full Phase 8 (3–4 weeks) speculative — only pays off if CGAL submission actually happens, which is uncertain. - Phase 8 MVP captures the architectural insight (traits + named params) without the long tail. If the rest of Phase 8 is ever wanted, it's additive — nothing built in the MVP needs to be thrown away. **Total committed budget: 2 weeks (MVP + 9a) + 2 weeks (9b + 9c) = ~4 weeks net work, 6–8 weeks calendar.** After that, the port is finished. ## Phase 8 MVP scope — what is and isn't in the first cut | Item | MVP | Later | Reason | |---|:---:|:---:|---| | `Conformal_map_traits.h` concept | ✅ | — | Core abstraction | | `Default_conformal_map_traits` | ✅ | — | Status-quo wrapper | | Generic `FaceGraph` specialisation | — | ✅ 8a.2 | Speculative until asked | | `Discrete_conformal_map.h` — `_euclidean()` | ✅ | — | First entry function | | `Discrete_conformal_map.h` — `_spherical()`, `_hyperbolic()` | — | ✅ 8b.2 | Pattern-replicates once 9a works | | Named parameters: `vertex_curvature_map`, `max_iterations`, `gradient_tolerance`, `fixed_vertex_pmap` | ✅ | — | Essential 4 | | Named parameters: rest (`output_uv_map`, `cut_graph`, …) | — | ✅ 8b.2 | Additive | | Doxygen on MVP headers | ✅ | — | Same time anyway | | Doxygen on legacy `code/include/*` | partial | ✅ 8c | Bulk later | | `PackageDescription.txt` | — | ✅ 8c | Only if submitting | | User_manual.md | — | ✅ 8c | Only if submitting | | `test/Conformal_map/` CGAL-style | — | ✅ 8d | Only if submitting | | YAML pipeline + CLI flag | — | ✅ 8e | Orthogonal, any time | --- ## TODO checklist ### MVP track (committed work, ~4 weeks) - [x] Phase 7.5: Doxyfile + CMake doc target + duplicate cleanup - [ ] **Phase 8 MVP — Traits + one wrapper** - [ ] `Conformal_map_traits.h` — concept documentation - [ ] `Default_conformal_map_traits` - [ ] `Conformal_map_concept_checks.h` - [ ] `Discrete_conformal_map.h` with `_euclidean()` only - [ ] 4 named parameters: Θ-map, max_iter, tol, pin - [ ] Test: `cgal.ConformalTraits.Surface_mesh_default_works` - [ ] **Phase 9a — Inversive-Distance (acceptance test for MVP)** - [ ] `inversive_distance_functional.hpp` against new traits - [ ] Gradient check + Newton convergence tests - [ ] Doxygen on new headers - [ ] **Phase 9b — Analytic HyperIdeal Hessian** - [ ] Replace FD in `hyper_ideal_hessian.hpp` - [ ] Symmetry + PSD checks unchanged - [ ] **Phase 9c — 4g-polygon for genus g > 1** - [ ] Extend `compute_fundamental_domain()` beyond genus 1 ### On-demand track (only with concrete trigger) - [ ] 8a.2: Generic `FaceGraph` specialisation (trigger: Polyhedron_3 user) - [ ] 8b.2: `_spherical()` + `_hyperbolic()` entry functions (trigger: pattern proven) - [ ] 8b.2: `Conformal_layout.h`, `Conformal_cut_graph.h` wrappers - [ ] 8c: `doc/Conformal_map/PackageDescription.txt` (trigger: submission planned) - [ ] 8c: User_manual + Reference_manual (trigger: submission planned) - [ ] 8d: `test/Conformal_map/` CGAL-style tests (trigger: submission planned) - [ ] 8e: YAML validator + CLI `--pipeline` flag (orthogonal, any time)