docs: restructure documentation into focused files
Some checks failed
C++ Tests / test-fast (push) Successful in 2m25s
C++ Tests / test-cgal (push) Failing after 1m58s

README.md: reduced from 703 to ~75 lines — what/why, status, quick
start, minimal usage example, navigation table to doc/ files.

doc/architecture/overall_pipeline.md: trimmed — roadmap, extension
points, declarative pipeline YAML, and references sections removed
(each now has its own dedicated file). Replaced with a link table.

New files:
  doc/getting-started.md       — build modes, single-test invocation, CLI
  doc/api/pipeline.md          — full pipeline API with code for all 3 geometries
  doc/api/extending.md         — new functionals, geometry modes, Java porting guide
  doc/api/contracts.md         — processing unit preconditions/provides table
  doc/api/cgal-package.md      — Phase 8 CGAL package design + YAML pipeline (TODO)
  doc/math/geometry-modes.md   — Euclidean/Spherical/HyperIdeal comparison
  doc/math/references.md       — all papers by module
  doc/roadmap/phases.md        — Phases 1–10 with porting/research boundary
  doc/roadmap/java-parity.md   — Java vs C++ feature parity table
  doc/contributing.md          — language policy, test standards, release flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-17 21:17:15 +02:00
parent 279f964b96
commit 14134b99ce
12 changed files with 1229 additions and 835 deletions

163
doc/api/cgal-package.md Normal file
View File

@@ -0,0 +1,163 @@
# Phase 8 — CGAL Package Design
> **Status: planned.** This document describes the target architecture for Phase 8.
> No code has been written yet. The design is informed by the CGAL package submission
> guidelines at https://www.cgal.org/developers.html
---
## Goal
Integrate conformallab++ into the CGAL library as a proper CGAL package:
`Discrete_conformal_map`. The package must satisfy all CGAL submission requirements:
traits-class design, Doxygen documentation, CGAL-format test suite, and coverage of
the CGAL coding conventions.
---
## 8a — Traits class & concepts
The current code is tightly coupled to `CGAL::Surface_mesh<Point3>`. Phase 8a introduces
a traits class that separates the mesh type from the algorithm:
```cpp
// TODO(Phase 8a): implement this header
// include/CGAL/Conformal_map_traits.h
template<
typename MeshType, // any CGAL halfedge mesh
typename KernelType, // CGAL kernel
typename ScalarType = double
>
struct Conformal_map_traits {
using Mesh = MeshType;
using Kernel = KernelType;
using FT = ScalarType;
// ... vertex/edge/face descriptor types
// ... property map access
};
```
Concept checks will ensure any user-provided mesh satisfies the halfedge mesh concept.
---
## 8b — Public header hierarchy
A clean public API separate from the internal implementation:
```
include/CGAL/
Discrete_conformal_map.h ← single user-facing include
Conformal_map_traits.h
Conformal_newton_solver.h
Conformal_layout.h
Conformal_cut_graph.h
conformal_map_package.h ← PackageDescription
```
All existing `include/*.hpp` headers remain as internal implementation details,
not part of the public CGAL API.
---
## 8c — CGAL-style documentation
```
doc/Conformal_map/
PackageDescription.txt
User_manual.md
Reference_manual.md
fig/ ← pipeline diagrams, mathematical figures
```
All public functions and concepts require Doxygen comments following the CGAL style.
---
## 8d — CGAL test format
```
test/Conformal_map/
CMakeLists.txt ← CGAL-format, uses find_package(CGAL)
test_euclidean_functional.cpp
test_newton_solver.cpp
...
```
The existing GTest suite remains. CGAL-format tests are added alongside as a separate
target, following the CGAL test infrastructure conventions.
---
## 8e — Declarative YAML pipeline
A lightweight YAML format for reproducible experiments. The CLI accepts
`--pipeline experiment.yml`; the validator checks `require`/`provide` tokens
before execution.
Example:
```yaml
pipeline:
name: flat_torus_period
geometry: euclidean
input:
source: data/torus.off
steps:
- id: setup
unit: setup_euclidean_maps
provide: [maps_initialised]
- id: gauss_bonnet
unit: enforce_gauss_bonnet
require: [maps_initialised]
provide: [gauss_bonnet_satisfied]
- id: solve
unit: newton_euclidean
require: [gauss_bonnet_satisfied]
params:
tol: 1.0e-10
max_iter: 200
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]
params:
normalise: true
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
tau: out/torus_tau.txt
```
The contract table in [contracts.md](contracts.md) defines the valid `require`/`provide`
token vocabulary.
---
## TODO
- [ ] Design `Conformal_map_traits.h` interface (8a)
- [ ] Define concept requirements for `MeshType` (8a)
- [ ] Create `include/CGAL/` header skeleton (8b)
- [ ] Write `PackageDescription.txt` (8c)
- [ ] Port GTest tests to CGAL format (8d)
- [ ] Implement YAML validator (8e)
- [ ] CLI: `--pipeline` flag (8e)

69
doc/api/contracts.md Normal file
View File

@@ -0,0 +1,69 @@
# Processing Unit Contracts
Each pipeline unit has explicit preconditions and guarantees.
A pipeline is valid if every unit's preconditions are satisfied by the outputs
of all preceding units.
---
## Contract table
| Unit | Preconditions | Provides |
|---|---|---|
| `load_mesh()` | Valid file path, supported format (OFF/OBJ/PLY) | Manifold, oriented, triangulated `ConformalMesh` |
| `setup_*_maps()` | Triangulated mesh | Initialised property maps; `lambda0` zeroed |
| `compute_*_lambda0_from_mesh()` | `setup_*_maps()` called | `lambda0[e]` set from 3-D edge lengths |
| `check_gauss_bonnet()` | `theta_v[v]` set for all vertices | Throws `std::runtime_error` if Σ(2πΘᵥ) ≠ 2π·χ(M) |
| `enforce_gauss_bonnet()` | `theta_v[v]` set | Σ(2πΘᵥ) = 2π·χ(M) guaranteed; `theta_v` modified |
| `newton_euclidean()` | GB satisfied · DOFs assigned · `lambda0` initialised | `NewtonResult.x` — converged scale factors; `.converged`, `.iterations`, `.grad_inf_norm` |
| `newton_spherical()` | GB satisfied · DOFs assigned · gauge vertex pinned | Same as above |
| `newton_hyper_ideal()` | `assign_all_dof_indices()` called · `lambda0` initialised | Same as above |
| `compute_cut_graph()` | Closed, orientable, triangulated mesh | `CutGraph.cut_edge_flags` — 2g seam edges; `.genus` |
| `euclidean_layout()` | `newton_euclidean()` converged | `Layout2D.uv[v]` · `.halfedge_uv[h]` · `HolonomyData.translations` |
| `spherical_layout()` | `newton_spherical()` converged | `Layout3D.xyz[v]` |
| `hyper_ideal_layout()` | `newton_hyper_ideal()` converged | `Layout2D.uv[v]` · `.halfedge_uv[h]` · `HolonomyData.mobius_maps` |
| `normalise_euclidean()` | `layout.success == true` | Centroid at origin, major axis = x-axis |
| `normalise_hyperbolic()` | `layout.success == true` | Weighted centroid at Poincaré disk origin |
| `normalise_spherical()` | `layout.success == true` | Area centroid at north pole |
| `compute_period_matrix()` | `hol.translations.size() >= 2` | `PeriodData.tau ∈ `; optionally SL(2,)-reduced |
| `compute_fundamental_domain()` | `HolonomyData` (genus 1) | CCW parallelogram `{0, ω₁, ω₁+ω₂, ω₂}` + edge identifications |
| `tiling_neighbourhood()` | `Layout2D` + `HolonomyData` (genus 1) | `(2m+1)·(2n+1)` translated layout copies |
| `save_layout_off()` | `Layout2D` + mesh | OFF file with UV coordinates |
| `save_result_json/xml()` | `NewtonResult` + optional `Layout2D` | JSON/XML serialised result |
---
## DOF assignment conventions
```cpp
// Euclidean / Spherical: pin one vertex, assign sequential indices
maps.v_idx[first_vertex] = -1; // pinned: u_v = 0
int idx = 0;
for (auto v : remaining_vertices)
maps.v_idx[v] = idx++;
// HyperIdeal: all vertices and edges are free DOFs
int n_dofs = assign_all_dof_indices(mesh, maps);
// maps.v_idx[v] ∈ [0, n_v)
// maps.e_idx[e] ∈ [n_v, n_v + n_e)
```
`-1` in `v_idx` or `e_idx` means the DOF is pinned (fixed at its `lambda0` value).
The solver never writes to pinned DOFs. All indexing is 0-based and contiguous.
---
## GaussBonnet — the most common source of failure
Prescribing angles that violate GaussBonnet means no conformal factor can realise the
target metric — the Newton solver will iterate indefinitely without converging.
```cpp
// Option A: verify before solving (throws on violation)
check_gauss_bonnet(mesh, maps);
// Option B: auto-correct (redistributes defect uniformly across all vertices)
enforce_gauss_bonnet(mesh, maps);
```
The target violation is `|Σ(2πΘᵥ) 2π·χ(M)| > tol`. Default tolerance: `1e-10`.

141
doc/api/extending.md Normal file
View File

@@ -0,0 +1,141 @@
# Extending conformallab++
## Adding a new functional
All three existing functionals (`euclidean_functional.hpp`, `spherical_functional.hpp`,
`hyper_ideal_functional.hpp`) follow the same pattern. Copy the structure of the
simplest one (`euclidean_functional.hpp`) as a template.
### Step 1 — Maps struct
```cpp
// my_functional.hpp
struct MyMaps {
ConformalMesh::Property_map<Vertex_index, double> lambda0; // initial log-lengths
ConformalMesh::Property_map<Vertex_index, double> theta_v; // target angles
ConformalMesh::Property_map<Vertex_index, int> v_idx; // DOF index, -1 = pinned
// add edge DOFs if needed:
ConformalMesh::Property_map<Edge_index, int> e_idx;
};
MyMaps setup_my_maps(ConformalMesh& mesh);
void compute_my_lambda0_from_mesh(ConformalMesh& mesh, MyMaps& maps);
```
### Step 2 — Gradient
The gradient must satisfy: `G_v = Σ(angle contributions at v) theta_v[v]`.
```cpp
std::vector<double> my_gradient(
const ConformalMesh& mesh,
const std::vector<double>& x,
const MyMaps& maps)
{
std::vector<double> G(n_dofs, 0.0);
for (auto f : mesh.faces()) {
// compute angles in face f given current x
// accumulate into G[maps.v_idx[v]] for each vertex v of f
}
// subtract target angles
for (auto v : mesh.vertices())
if (maps.v_idx[v] >= 0)
G[maps.v_idx[v]] -= maps.theta_v[v];
return G;
}
```
### Step 3 — Gradient check test
Before claiming correctness, verify with finite differences. Copy any `GradientCheck_*`
test suite from `tests/cgal/test_*_functional.cpp`:
```cpp
TEST(MyFunctional, GradientCheck_Triangle) {
ConformalMesh mesh = make_single_triangle();
MyMaps maps = setup_my_maps(mesh);
// ... assign DOFs, set natural theta ...
const double eps = 1e-5;
auto G = my_gradient(mesh, x0, maps);
for (int i = 0; i < n; ++i) {
std::vector<double> xp = x0, xm = x0;
xp[i] += eps; xm[i] -= eps;
double fd = (my_energy(mesh, xp, maps) - my_energy(mesh, xm, maps)) / (2*eps);
EXPECT_NEAR(G[i], fd, 1e-7) << "DOF " << i;
}
}
```
### Step 4 — Hessian and Newton wrapper
```cpp
// Reuse solve_linear_system from newton_solver.hpp
Eigen::SparseMatrix<double> H = my_hessian(mesh, x, maps);
bool used_fallback;
auto dx = conformallab::solve_linear_system(H, -G, &used_fallback);
```
Or write a thin `newton_my()` wrapper following the structure of `newton_euclidean()`.
---
## Adding a new geometry mode
To add a new space (e.g. de Sitter, flat 3-torus):
1. **Trilateration function** — implement `trilaterate_my(p1, p2, l12, l13, l23)` that
places a third point given two placed points and three edge lengths.
This is the only geometry-specific part of the layout.
2. **BFS structure** — reuse the priority-BFS loop from `euclidean_layout()` in `layout.hpp`.
The loop itself is geometry-agnostic; swap in your trilateration function.
3. **Holonomy** — if the space has a holonomy group, record the transition maps at seam edges
the same way `HolonomyData` does for translations (Euclidean) or Möbius maps (hyperbolic).
---
## Adding a new processing unit
1. Declare preconditions and outputs explicitly (see [contracts.md](contracts.md)).
2. Write a header-only implementation in `code/include/my_unit.hpp`.
3. Add tests in `code/tests/cgal/test_my_unit.cpp` and register in
`code/tests/cgal/CMakeLists.txt`.
4. Pipeline validation is currently manual (documented contracts). A compile-time or
runtime check via the declarative YAML pipeline (Phase 8e) is the planned upgrade —
see [cgal-package.md](cgal-package.md).
---
## Porting from Java
When porting a class from the Java library:
1. Locate the original at [github.com/varylab/conformallab](https://github.com/varylab/conformallab)
under `src/main/java/de/varylab/discreteconformal/`.
2. The Java library uses `CoHDS` (half-edge data structure) with intrusive vertex/edge data.
Map these to CGAL property maps:
```
Java: vertex.getLambda() → C++: maps.lambda0[v]
Java: edge.getAlpha() → C++: maps.e_alpha[e]
Java: vertex.getTheta() → C++: maps.theta_v[v]
Java: vertex.getSolverIndex() → C++: maps.v_idx[v]
```
3. Java uses `HalfedgeInterface` adapters with named accessors like `getOppositeVertex()`.
C++ equivalent:
```cpp
// Java: h.getOppositeVertex()
Vertex_index v_opp = mesh.target(mesh.next(h));
// Java: h.getNextHalfedge().getOppositeVertex()
Vertex_index v_opp2 = mesh.target(mesh.next(mesh.next(h)));
```
4. Port the test cases from the Java `@Test` methods. The "natural theta" trick
(`theta_v[v] = actual_angle_sum`) works the same way in both languages.

214
doc/api/pipeline.md Normal file
View File

@@ -0,0 +1,214 @@
# Pipeline API Reference
The full pipeline from mesh loading to layout and serialisation.
See [doc/architecture/overall_pipeline.md](../architecture/overall_pipeline.md) for the
Mermaid diagram and stage descriptions.
---
## Minimal Euclidean pipeline
```cpp
#include "conformal_mesh.hpp"
#include "mesh_io.hpp"
#include "euclidean_functional.hpp"
#include "gauss_bonnet.hpp"
#include "newton_solver.hpp"
#include "layout.hpp"
using namespace conformallab;
ConformalMesh mesh = load_mesh("input.off");
// 1. Set up property maps and initialise log-edge-lengths from 3-D positions
EuclideanMaps maps = setup_euclidean_maps(mesh);
compute_euclidean_lambda0_from_mesh(mesh, maps);
// 2. Assign DOF indices — pin first vertex (gauge fix for open meshes)
auto vit = mesh.vertices().begin();
maps.v_idx[*vit++] = -1; // pinned: u_v = 0
int idx = 0;
for (; vit != mesh.vertices().end(); ++vit)
maps.v_idx[*vit] = idx++;
// 3. Set target angles — "natural equilibrium" makes x* = 0
std::vector<double> x0(idx, 0.0);
auto G0 = euclidean_gradient(mesh, x0, maps);
for (auto v : mesh.vertices())
if (maps.v_idx[v] >= 0)
maps.theta_v[v] -= G0[maps.v_idx[v]];
// 4. Check GaussBonnet (mandatory before solving)
check_gauss_bonnet(mesh, maps); // throws if Σ(2πΘᵥ) ≠ 2π·χ(M)
// 5. Solve
NewtonResult res = newton_euclidean(mesh, x0, maps);
// res.converged, res.x, res.iterations, res.grad_inf_norm
// 6. Layout
Layout2D layout = euclidean_layout(mesh, res.x, maps);
// layout.uv[v.idx()], layout.halfedge_uv[h.idx()]
```
---
## Layout with holonomy (closed surfaces)
```cpp
#include "cut_graph.hpp"
#include "period_matrix.hpp"
#include "fundamental_domain.hpp"
// Tree-cotree cut graph — 2g seam edges
CutGraph cg = compute_cut_graph(mesh);
// cg.cut_edge_flags[e.idx()] — true if seam edge
// cg.genus — topological genus g
// Layout with holonomy tracking
HolonomyData hol;
Layout2D layout = euclidean_layout(mesh, res.x, maps, &cg, &hol, /*normalise=*/true);
// hol.translations[i] — lattice generator ωᵢ ∈ (Euclidean)
// Period matrix (genus 1 flat torus)
PeriodData pd = compute_period_matrix(hol);
// pd.tau — complex period ratio τ = ω₂/ω₁ ∈
// pd.omega — {ω₁, ω₂} as complex<double>
// pd.in_fundamental_domain — true if SL(2,)-reduced to |τ|≥1, |Re(τ)|<½
// Fundamental domain parallelogram
FundamentalDomain fd = compute_fundamental_domain(hol);
// fd.vertices[0..3] — CCW corners: {0, ω₁, ω₁+ω₂, ω₂}
// fd.generators[0..1] — ω₁, ω₂
// Tiling copies for universal cover visualisation
auto tiles = tiling_neighbourhood(layout, hol, /*m_max=*/2, /*n_max=*/2);
// returns (2·m_max+1)·(2·n_max+1) translated layout copies
```
---
## HyperIdeal pipeline
```cpp
#include "hyper_ideal_functional.hpp"
#include "newton_solver.hpp"
#include "layout.hpp"
#include "cut_graph.hpp"
HyperIdealMaps maps = setup_hyper_ideal_maps(mesh);
compute_hyper_ideal_lambda0_from_mesh(mesh, maps);
// HyperIdeal has both vertex and edge DOFs — assign all automatically
int n_dofs = assign_all_dof_indices(mesh, maps);
// No vertex needs to be pinned — strictly convex functional
std::vector<double> x0(n_dofs, 0.0);
NewtonResult res = newton_hyper_ideal(mesh, x0, maps);
// Layout with Möbius holonomy
CutGraph cg = compute_cut_graph(mesh);
HolonomyData hol;
Layout2D layout = hyper_ideal_layout(mesh, res.x, maps, &cg, &hol);
// hol.mobius_maps[i] — Möbius isometry Tᵢ ∈ SU(1,1) per cut edge
```
---
## Spherical pipeline
```cpp
#include "spherical_functional.hpp"
#include "newton_solver.hpp"
#include "layout.hpp"
SphericalMaps maps = setup_spherical_maps(mesh);
compute_spherical_lambda0_from_mesh(mesh, maps);
// Pin one vertex (gauge fix) + assign DOFs
auto vit = mesh.vertices().begin();
maps.v_idx[*vit++] = -1;
int idx = 0;
for (; vit != mesh.vertices().end(); ++vit)
maps.v_idx[*vit] = idx++;
std::vector<double> x0(idx, 0.0);
NewtonResult res = newton_spherical(mesh, x0, maps);
// 3-D layout on the unit sphere
Layout3D slayout = spherical_layout(mesh, res.x, maps);
// slayout.xyz[v.idx()] — 3-D position on S²
```
---
## SparseQR fallback — direct use
```cpp
#include "newton_solver.hpp"
bool used_fallback = false;
Eigen::VectorXd dx = conformallab::solve_linear_system(H, rhs, &used_fallback);
if (used_fallback)
std::cerr << "Warning: H is rank-deficient, used SparseQR\n";
```
The fallback is automatically invoked by all three `newton_*` functions when
`SimplicialLDLT` fails. It finds the minimum-norm Newton step orthogonal to the null space.
---
## Serialisation
```cpp
#include "serialization.hpp"
#include "mesh_io.hpp"
// Save layout as OFF mesh file
save_layout_off("layout.off", mesh, layout);
// Full result: DOF vector + metadata + layout UVs
save_result_json("result.json", res, "euclidean", mesh, &layout);
save_result_xml ("result.xml", res, "euclidean", mesh, &layout);
// Round-trip load
NewtonResult res2;
std::string geom;
Layout2D uv2;
load_result_json("result.json", &res2, &geom, &uv2);
```
---
## Attaching custom property maps
```cpp
// Add a custom per-vertex map
auto [curv, created] = mesh.add_property_map<Vertex_index, double>("v:my_curv", 0.0);
curv[v] = 3.14;
// Retrieve an existing map
auto [curv2, found] = mesh.property_map<Vertex_index, double>("v:my_curv");
```
---
## Halfedge traversal conventions
```cpp
for (auto f : mesh.faces()) {
auto h0 = mesh.halfedge(f); // canonical halfedge of face f
auto h1 = mesh.next(h0);
auto h2 = mesh.next(h1);
Vertex_index v1 = mesh.source(h0); // = mesh.target(h2)
Vertex_index v2 = mesh.source(h1);
Vertex_index v3 = mesh.source(h2);
// Angle at v3 is opposite to halfedge h0 (edge v1v2)
// h_alpha[h0] = α₃, h_alpha[h1] = α₁, h_alpha[h2] = α₂
Edge_index e0 = mesh.edge(h0);
bool is_seam = cg.cut_edge_flags[e0.idx()];
bool is_boundary = mesh.is_border(mesh.opposite(h0));
}
```

View File

@@ -388,177 +388,14 @@ Normalise PCA centring Rodrigues to N pole weighted Möbius centrin
---
## Extension points
## Further documentation
### Adding a new functional
1. Create `my_functional.hpp` with a `Maps` struct and `evaluate_my_functional()`.
2. The gradient must satisfy: `G_v = Σ(angle contributions) theta_v[v]`.
3. Verify with a finite-difference gradient check (copy any `GradientCheck_*` test).
4. Pass to `solve_linear_system(H, -G)` or write a thin `newton_my` wrapper.
### Adding a new geometry mode
Implement `trilaterate_my()` with the correct local placement formula,
then follow the same BFS structure as `euclidean_layout` (see `layout.hpp`).
The priority BFS, holonomy tracking, and `halfedge_uv` population are geometry-agnostic.
### Adding a new processing unit
Declare its preconditions and capabilities explicitly (see table above).
The pipeline validation is currently manual (documented contracts); a
compile-time or runtime check is a natural Phase 8 extension.
---
## Declarative pipeline (target for Phase 8)
A lightweight YAML description for reproducible experiments:
```yaml
pipeline:
name: flat_torus_period
geometry: euclidean
input:
source: data/torus.off
steps:
- id: setup
unit: setup_euclidean_maps
provide: [maps_initialised]
- id: gauss_bonnet
unit: enforce_gauss_bonnet
require: [maps_initialised]
provide: [gauss_bonnet_satisfied]
- id: solve
unit: newton_euclidean
require: [gauss_bonnet_satisfied]
params:
tol: 1.0e-10
max_iter: 200
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]
params:
normalise: true
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
tau: out/torus_tau.txt
```
Each unit declares `require` (preconditions) and `provide` (capabilities).
A pipeline is valid if for every step, all `require` keys are satisfied by the
accumulated `provide` set of all preceding steps.
This mirrors exactly the contract table in this document.
---
## Development Roadmap
> **Grenze Portierung / neue Forschung:**
> Phase 17 sind direkte Portierungen aus dem Java-Original (Sechelmann 2016).
> Ab Phase 8 geht die Arbeit über den Umfang der Java-Bibliothek hinaus.
> — Phase 8 (CGAL-Paket) ist **Infrastruktur**, kein neuer Algorithmus.
> — Phase 9 (Inversive-Distance, Analytischer Hessian, 4g-Polygon) ist **Portierung** ausstehender Java-Features.
> — Phase 10+ ist **eigenständige Forschung**, die über das Java-Original hinausgeht.
---
### ◼ Portierungsphase abgeschlossen — Phase 17
```
Phase 1 Clausen / Lobachevsky / ImLi₂ ✅
Phase 2 Hyper-ideal Geometrie (ζ, lᵢⱼ, αᵢⱼ, σᵢ) ✅
Phase 3 CGAL-Infrastruktur + alle drei Funktionale (E/S/H) ✅
Phase 4 Newton-Solver (SimplicialLDLT + SparseQR-Fallback) ✅ 68 Tests
Phase 5 Priority-BFS-Layout + CLI + JSON/XML ✅ 95 Tests
Phase 6 GaussBonnet, Tree-Cotree-Schnittgraph, Normalisierung ✅ 121 Tests
Phase 7 MobiusMap, halfedge_uv, Möbius-Holonomie, Periodenmatrix,
Fundamentalbereich (Genus 1), Java-Parität abgeschlossen ✅ 158 Tests
```
---
### ◼ Infrastruktur (über Java-Bibliothek hinaus) — Phase 8: CGAL-Paket
```
8a Traits-Klasse & Konzepte → include/CGAL/Conformal_map_traits.h
8b Öffentliche CGAL-Header-Hierarchie → include/CGAL/Discrete_conformal_map.h etc.
8c Dokumentation im CGAL-Stil → doc/Conformal_map/PackageDescription.txt
8d CGAL-Testformat → test/Conformal_map/
8e Declarative YAML-Pipeline → pipeline validator (require/provide tokens)
```
See the [Declarative pipeline](#declarative-pipeline-target-for-phase-8) section above
for the YAML schema that Phase 8e will validate at runtime.
---
### ◼ Ausstehende Portierung (Java-Features noch nicht übertragen) — Phase 9
```
9a Inversive-Distance-Funktional (Luo 2004)
→ InversiveDistanceMaps + functional + Hessian
→ discrete uniformization via inversive distances
9b Analytischer HyperIdeal-Hessian (ζ-Kette)
→ replace FD Hessian in hyper_ideal_hessian.hpp
→ reduces Newton iterations for large meshes
9c 4g-Polygon-Randlauf (Genus g > 1)
→ extend compute_fundamental_domain() beyond genus 1
→ algorithm outline already in fundamental_domain.hpp as TODO(Phase 9)
```
---
### ◼ Neue Forschung (über das Java-Original hinaus) — Phase 10+
```
Phase 10 Globale Uniformisierung Genus g ≥ 2
10a Holomorphe Differentiale auf diskreten Flächen
→ discrete harmonic 1-forms; integration along cut graph cycles
10b Siegel-Periodenmatrix Ω ∈ H_g (g×g komplex-symmetrisch, Im(Ω) > 0)
→ extend compute_period_matrix() to genus g ≥ 2
→ requires holomorphic differentials from 10a
10c Vollständige Uniformisierung
→ uniformize arbitrary genus-g surface to canonical constant-curvature metric
→ depends on 10a + 10b
```
---
## Recommended reading
### Primary source — the dissertation this library implements
| | |
| Topic | Document |
|---|---|
| **Sechelmann***Variational Methods for Discrete Surface Parameterization: Applications and Implementation*, TU Berlin 2016 | The mathematical foundation of the entire library: discrete conformal equivalence, variational angle-sum functionals, Newton solver, uniformization, period matrices. DOI: [10.14279/depositonce-5415](https://depositonce.tu-berlin.de/items/8e2988b2-d991-45b5-aad5-9fb7988f3b2f) |
| **Java original** — [github.com/varylab/conformallab](https://github.com/varylab/conformallab) | Reference implementation in Java — the direct source for all algorithms ported to C++ |
### Further references
| Source | Relevance in conformallab++ |
|--------|----------------------------|
| Springborn — *Ideal Hyperbolic Polyhedra and Discrete Uniformization* (2020) | HyperIdeal functional; ζ₁₃/ζ₁₄/ζ₁₅ in `hyper_ideal_geometry.hpp` |
| Pinkall, Polthier — *Computing Discrete Minimal Surfaces* (1993) | Cotangent-Laplace Hessian in `euclidean_hessian.hpp` |
| Bobenko, Springborn — *Variational Principles for Circle Patterns* (2004) | Angle-sum variational framework used throughout |
| Luo — *Combinatorial Yamabe Flow on Surfaces* (2004) | Inversive-distance functional (not yet ported) |
| Erickson, Whittlesey — *Greedy Optimal Homotopy Generators* (SODA 2005) | Tree-cotree algorithm in `cut_graph.hpp` |
| Extending the library (new functionals, geometry modes, Java porting guide) | [api/extending.md](../api/extending.md) |
| Processing unit contracts (preconditions / provides table) | [api/contracts.md](../api/contracts.md) |
| Phase 8 CGAL package design + declarative pipeline YAML | [api/cgal-package.md](../api/cgal-package.md) |
| Three geometry modes in detail | [math/geometry-modes.md](../math/geometry-modes.md) |
| References and papers | [math/references.md](../math/references.md) |
| Development roadmap (Phases 110) | [roadmap/phases.md](../roadmap/phases.md) |
| Java vs. C++ feature parity table | [roadmap/java-parity.md](../roadmap/java-parity.md) |

88
doc/contributing.md Normal file
View File

@@ -0,0 +1,88 @@
# Contributing
## Language
**All code, comments, documentation, commit messages, and test descriptions must be in English.**
The project targets CGAL submission and international collaboration. When editing
files that still contain German-language comments or documentation, replace them
with English.
---
## Git workflow
- `main` is protected on `origin` (Gitea). Push to `dev`, then open a pull request.
- `codeberg/main` can be pushed to directly (public mirror, no CI).
- Both remotes must stay in sync after every significant change:
```bash
git push origin HEAD:dev # triggers CI
git push codeberg main # updates public mirror
```
- Branch naming: `feature/<topic>`, `fix/<topic>`, `phase<N>-<topic>`
---
## CI
Two jobs run on push to `dev`/`main` or on pull requests:
| Job | What it tests | Trigger |
|---|---|---|
| `test-fast` | 36 non-CGAL tests, no Boost | all branches |
| `test-cgal` | 158 CGAL tests + 2 skips | `main`, `dev`, PRs only |
A PR is ready to merge when both jobs pass.
The runner is a self-hosted Raspberry Pi (ARM64). See `.gitea/workflows/cpp-tests.yml`
and `.gitea/docker/Dockerfile.ci-cpp`.
---
## Test standards
Every new algorithm needs:
1. **Gradient check** — finite-difference verification of `G(x) = ∂E/∂x`.
Copy any `GradientCheck_*` test suite from `tests/cgal/test_*_functional.cpp`.
2. **Convergence test** — Newton converges on a small mesh using the "natural theta"
trick (see [CLAUDE.md](../CLAUDE.md) and [api/extending.md](api/extending.md)).
3. **Registration** — add the `.cpp` file to `code/tests/cgal/CMakeLists.txt`.
Expected CI result: **36 + 158 tests pass, exactly 2 skipped**.
The 2 skips are intentional `GTEST_SKIP()` stubs for Phase 9b (analytic HyperIdeal Hessian)
and Phase 9c (genus-2 homology). Do not remove them.
---
## Code style
- C++17. Header-only (`code/include/*.hpp`). No compiled library.
- `#pragma once` at the top of every header.
- Everything in the `conformallab` namespace, internal helpers in `conformallab::detail`.
- Property map names follow the prefix convention: `"v:"` (vertex), `"e:"` (edge), `"f:"` (face).
- DOF index `-1` always means "pinned/fixed".
---
## Releases
Release tags follow `vMAJOR.MINOR.PATCH`:
```bash
# Merge dev → main, then tag
git checkout main && git merge --no-ff dev
git tag -a vX.Y.Z -m "vX.Y.Z — <one-line summary>"
git push origin main && git push origin vX.Y.Z
git push codeberg main && git push codeberg vX.Y.Z
```
---
## TODO
- [ ] Define code review checklist
- [ ] Add `.clang-format` configuration
- [ ] Document how to request CGAL package review

142
doc/getting-started.md Normal file
View File

@@ -0,0 +1,142 @@
# Getting Started
## Prerequisites
| Tool | Minimum | Notes |
|---|---|---|
| C++ compiler (GCC or Clang) | C++17 | GCC 11+ or Clang 14+ recommended |
| CMake | 3.20 | |
| Boost headers | 1.70 | Only for `-DWITH_CGAL_TESTS=ON` or `-DWITH_CGAL=ON` |
| Wayland/X11 dev headers | — | Only for `-DWITH_CGAL=ON` (viewer) |
All other dependencies (Eigen 3.4, CGAL 6.1.1, libigl 2.6, GLFW 3.4, GTest 1.14)
are bundled as tarballs in `code/deps/tarballs/` and extracted automatically at CMake
configure time. No internet access is required at build time (except GTest, fetched via
`FetchContent` from GitHub).
Install Boost on your system:
```bash
# Ubuntu / Debian
apt install libboost-dev
# macOS
brew install boost
```
---
## Clone
```bash
git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
```
---
## Build modes
Three modes with increasing dependencies:
### Mode 1 — Fast tests (default, no system dependencies)
Pure-math tests: Clausen functions, hyper-ideal geometry, matrix utilities.
```bash
cmake -S code -B build
cmake --build build --target conformallab_tests -j$(nproc)
ctest --test-dir build --output-on-failure
```
Expected: **36 tests pass**.
### Mode 2 — CGAL tests, headless (recommended for CI and development)
Full CGAL test suite. Requires Boost headers only — no display, no Wayland, no GLFW.
```bash
cmake -S code -B build -DWITH_CGAL_TESTS=ON
cmake --build build --target conformallab_cgal_tests -j$(nproc)
ctest --test-dir build -R "^cgal\." --output-on-failure
```
Expected: **158 tests pass, 2 skipped** (intentional stubs for Phase 9 items).
### Mode 3 — Full local build (CLI app + interactive viewer)
Requires Wayland or X11 development packages (`wayland-scanner`, `libx11-dev`, etc.).
Automatically enables the viewer library (GLFW + libigl).
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -j$(nproc)
```
> **Note:** `-DWITH_CGAL=ON` implies `-DWITH_VIEWER=ON`. Do not use this in headless
> environments — it will fail with `Failed to find wayland-scanner`.
---
## Running a single test
```bash
# By GTest filter (fastest, full output)
./build/conformallab_cgal_tests --gtest_filter="NewtonSolver*"
./build/conformallab_tests --gtest_filter="Clausen*"
# By CTest regex
ctest --test-dir build -R "cgal.NewtonSolver" --output-on-failure
```
All CGAL tests have the prefix `cgal.` in CTest (set in `tests/cgal/CMakeLists.txt`
via `TEST_PREFIX "cgal."`).
---
## First run — CLI app
After a full build (`-DWITH_CGAL=ON`):
```bash
# Euclidean conformal layout
./bin/conformallab_core -i input.off -g euclidean -o layout.off -j result.json
# Spherical layout
./bin/conformallab_core -i input.off -g spherical -o sphere.off
# Hyperbolic layout (HyperIdeal)
./bin/conformallab_core -i input.off -g hyper_ideal -o hyperbolic.off
# Show input mesh in interactive viewer
./bin/conformallab_core -i input.off -s
# All options
./bin/conformallab_core --help
```
## Example programs
```bash
./build/examples/example_layout [input.off] [layout.off] [result.json]
./build/examples/example_euclidean [input.off] [output.off]
./build/examples/example_hyper_ideal [input.off] [output.off]
./build/examples/example_viewer [input.off] # interactive, requires WITH_VIEWER
```
`example_layout.cpp` is the best starting point — it shows the complete pipeline in ~120 lines.
---
## Rebuilding the CI Docker image
The CI runner is a self-hosted Raspberry Pi (ARM64). After changes to
`.gitea/docker/Dockerfile.ci-cpp`:
```bash
docker buildx build \
--platform linux/arm64 \
-f .gitea/docker/Dockerfile.ci-cpp \
-t git.eulernest.eu/conformallab/ci-cpp:latest \
--push \
.gitea/docker/
```

112
doc/math/geometry-modes.md Normal file
View File

@@ -0,0 +1,112 @@
# The Three Geometry Modes
conformallab++ implements discrete conformal geometry in three model spaces.
All three share the same algorithmic structure — only the angle formula,
the trilateration geometry, and the Hessian sign differ.
---
## Comparison
```
Euclidean Spherical Hyper-ideal
─────────────────────────────────────────────────────
Space ℝ² S² H² (Poincaré disk)
Curvature K = 0 K = +1 K = 1
Typical genus any (cone metrics) 0 ≥ 1
Angle sum Σαᵥ = Θᵥ Σαᵥ = Θᵥ Σβᵥ = Θᵥ
Gradient sign G_v = actual Θᵥ G_v = Θᵥ actual G_v = actual Θᵥ
Hessian PSD (cotangent-Lap.) NSD (sign-flip) PSD (FD, strict conv.)
Newton solve SimplicialLDLT(H) SimplicialLDLT(H) SimplicialLDLT(H)
Holonomy translations ωᵢ rotations (2-D) Möbius maps Tᵢ ∈ SU(1,1)
Period τ = ω₂/ω₁ ∈ — axis of Tᵢ
Normalise PCA centring Rodrigues to N pole weighted Möbius centring
Layout Layout2D (ℝ²) Layout3D (unit sphere) Layout2D (Poincaré disk)
```
---
## Euclidean (ℝ²)
**Energy:** the cotangent-weighted angle defect energy (Pinkall & Polthier 1993).
**Effective log-length:**
```
Λ̃ᵢⱼ = λ°ᵢⱼ + uᵢ + uⱼ
```
**Gradient:** `G_v = Σ_{faces adj. v} α_v(face) Θᵥ` — the actual angle sum minus the target.
**Hessian:** cotangent Laplacian, assembled in `euclidean_hessian.hpp`. PSD with one zero
eigenvalue (constant function) for closed meshes — handled by pinning one vertex or SparseQR.
**Normalisation:** centroid → origin, major axis → x-axis via PCA (`normalise_euclidean`).
**Holonomy:** lattice translations ω₁, ω₂ ∈ for closed surfaces.
Period ratio τ = ω₂/ω₁ ∈ is the conformal modulus of the torus.
---
## Spherical (S²)
**Typical use:** genus-0 (sphere-like) surfaces.
**Gradient:** `G_v = Θᵥ Σ α_v(face)` — note the **sign reversal** vs. Euclidean.
**Hessian:** NSD (the spherical energy is concave). Newton solves `(H)·Δx = G`, i.e.
`SimplicialLDLT` is called on `H`. This is handled transparently in `newton_spherical()`.
**Gauge fix:** for a closed spherical surface, one additional DOF must be pinned to remove
the rotational gauge mode. `SphericalMaps` has a dedicated `gauge_vertex` field.
**Normalisation:** `normalise_spherical()` rotates the layout so the area centroid
maps to the north pole (Rodrigues rotation formula).
---
## Hyper-ideal (H²)
**Typical use:** genus-g surfaces (g ≥ 1), hyperbolic cone metrics.
**DOFs:** both vertex variables `bᵢ` (hyper-ideal radius) and edge variables `aₑ`
(intersection angle). `assign_all_dof_indices(mesh, maps)` assigns both automatically.
No vertex needs to be pinned — the functional is strictly convex.
**Geometry functions** (in `hyper_ideal_geometry.hpp`):
```
ζ₁₃(b, a) ζ₁₄(b, a) ζ₁₅(b, a) — the three fundamental Springborn functions
lᵢⱼ(ζ) — edge length from ζ value
αᵢⱼ(l₁, l₂, l₃) — interior angle
βᵢ(l₁, l₂, l₃) — vertex angle sum contribution
```
**Hessian:** currently a symmetric finite-difference approximation (see `hyper_ideal_hessian.hpp`).
The analytic Hessian through the `(bᵢ, aₑ) → lᵢⱼ → ζ → αᵢⱼ/βᵢ` chain is Phase 9b.
**Holonomy:** Möbius isometries Tᵢ ∈ SU(1,1) (orientation-preserving isometries of the Poincaré disk).
`MobiusMap` in `layout.hpp`: T(z) = (az+b)/(cz+d).
**Normalisation:** `normalise_hyperbolic()` performs iterative face-area-weighted Möbius centring
(Fréchet mean, 30 iterations) to map the weighted centroid to the disk origin.
---
## GaussBonnet constraint
Before calling any Newton solver, the target angles must satisfy the GaussBonnet equation:
```
Σᵥ (2π Θᵥ) = 2π · χ(M) (Euclidean / flat)
Σᵥ (2π Θᵥ) > 0 (spherical, χ > 0)
Σᵥ (2π Θᵥ) < 0 (hyperbolic, χ < 0)
```
If this is violated, no conformal factor can realise the target angles and Newton will
fail to converge without a visible error.
```cpp
check_gauss_bonnet(mesh, maps); // throws if violated
enforce_gauss_bonnet(mesh, maps); // redistributes residual uniformly across all vertices
```
**This is the most common source of silent non-convergence.** Always call one of these before solving.

35
doc/math/references.md Normal file
View File

@@ -0,0 +1,35 @@
# References
## Primary source
This library implements the algorithms from:
| | |
|---|---|
| **Sechelmann***Variational Methods for Discrete Surface Parameterization: Applications and Implementation*, Doctoral thesis, TU Berlin 2016 | The complete mathematical foundation: discrete conformal equivalence, variational angle-sum functionals, Newton solver, uniformization, period matrices, holonomy. DOI: [10.14279/depositonce-5415](https://depositonce.tu-berlin.de/items/8e2988b2-d991-45b5-aad5-9fb7988f3b2f) · CC BY-SA 4.0 |
Java reference implementation: [github.com/varylab/conformallab](https://github.com/varylab/conformallab)
---
## References by module
| Reference | Used in |
|---|---|
| **Springborn***Ideal Hyperbolic Polyhedra and Discrete Uniformization*, Discrete & Computational Geometry (2020) | `hyper_ideal_geometry.hpp` — ζ₁₃/ζ₁₄/ζ₁₅ functions; `hyper_ideal_functional.hpp` |
| **Pinkall, Polthier***Computing Discrete Minimal Surfaces and Their Conjugates*, Experimental Mathematics (1993) | `euclidean_hessian.hpp` — cotangent Laplacian |
| **Bobenko, Springborn***Variational Principles for Circle Patterns and Koebe's Theorem*, Transactions AMS (2004) | Variational angle-sum framework underlying all three functionals |
| **Luo***Combinatorial Yamabe Flow on Surfaces*, Communications in Contemporary Mathematics (2004) | Inversive-distance functional — **not yet ported**, Phase 9a |
| **Erickson, Whittlesey***Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm |
| **Bobenko, Springborn***A Discrete LaplaceBeltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights |
| **Desbrun, Kanso, Tong***Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a |
---
## Phase 10 references (future research)
| Reference | Relevant for |
|---|---|
| **Farkas, Kra***Riemann Surfaces*, Springer GTM 71 | Siegel period matrix, Teichmüller theory |
| **Siegel***Topics in Complex Function Theory, Vol. 2*, Wiley | Siegel upper half-space H_g, Sp(2g,) reduction |
| **Bobenko, Mercat, Schmies***Period Matrices of Polyhedral Surfaces*, in: Computational Approach to Riemann Surfaces (2011) | Discrete period matrices on polyhedral surfaces |

View File

@@ -0,0 +1,86 @@
# Java ConformalLab vs. conformallab++ — Feature Parity
Reference: [github.com/varylab/conformallab](https://github.com/varylab/conformallab)
Java package root: `de.varylab.discreteconformal`
When porting a Java class, locate the original in the Java repository and use it
as the reference implementation for expected behaviour, edge cases, and test cases.
---
## Algorithm parity
| Mathematical layer | Java ConformalLab | conformallab++ | Notes |
|---|---|---|---|
| Euclidean functional — energy, gradient | ✅ | ✅ | |
| Spherical functional — energy, gradient, gauge-fix | ✅ | ✅ | |
| HyperIdeal functional — energy, gradient | ✅ | ✅ | |
| Inversive-distance functional (Luo 2004) | ✅ | ❌ Phase 9a | `InversiveDistanceFunctional.java` |
| Euclidean Hessian — cotangent Laplacian | ✅ analytic | ✅ analytic | PinkallPolthier (1993) |
| Spherical Hessian — ∂α/∂u via law of cosines | ✅ analytic | ✅ analytic | |
| HyperIdeal Hessian — ζ → lᵢⱼ → β/α chain | ✅ analytic | ⚠️ symmetric FD | Phase 9b |
| Newton solver | ✅ | ✅ | |
| SparseQR fallback for gauge modes | unknown | ✅ | New in C++ |
| Cone metrics — prescribed Θᵥ ≠ 2π | ✅ fully | ⚠️ data structure only | |
| Layout / embedding — ℝ² / H² / S² | ✅ | ✅ priority-BFS all three | |
| Exact hyperbolic trilateration | ✅ Möbius | ✅ Möbius + law of cosines | |
| halfedge_uv — seam-aware UV (texture atlas) | ✅ | ✅ | |
| GaussBonnet consistency check | ✅ | ✅ | |
| Tree-cotree cut graph (2g edges) | ✅ | ✅ EricksonWhittlesey (2005) | |
| Holonomy — Euclidean (translations) | ✅ | ✅ | |
| Holonomy — Hyperbolic (SU(1,1) Möbius maps) | ✅ | ✅ | |
| Period matrix τ — genus 1, SL(2,)-reduced | ✅ | ✅ | |
| Fundamental domain — genus 1 | ✅ | ✅ CCW parallelogram | |
| 4g-polygon boundary walk — genus g > 1 | ✅ | ❌ Phase 9c | `FundamentalDomainUtility.java` |
| Siegel period matrix Ω — genus g ≥ 2 | ✅ | ❌ Phase 10b | |
| Global uniformization — genus g ≥ 2 | ✅ | ❌ Phase 10c | |
| Clausen / Lobachevsky / ImLi₂ | ✅ | ✅ | |
| Poincaré disk / Lorentz boost visualisation | ✅ | ✅ | |
| Mesh I/O + serialisation | ✅ XML/CoHDS | ✅ OFF/OBJ/PLY + JSON/XML | |
| Interactive viewer | ✅ jReality | ✅ libigl/GLFW | |
---
## Java utility classes not yet ported
These exist in `de.varylab.discreteconformal.util` in the Java library.
They are candidates for Phase 9 or Phase 10.
| Java class | Description | Phase |
|---|---|---|
| `InversiveDistanceFunctional` | Inversive-distance conformal energy | 9a |
| `DiscreteHarmonicFormUtility` | Discrete harmonic 1-forms | 10a prerequisite |
| `DiscreteHolomorphicFormUtility` | Holomorphic differentials on discrete surfaces | 10a |
| `DiscreteRiemannUtility` | Discrete Riemann surfaces | 10 |
| `CanonicalBasisUtility` | Canonical homology basis for genus g | 9c / 10 |
| `HomologyUtility` | Homology computation | 9c |
| `HomotopyUtility` | Homotopy generators | 9c |
| `SpanningTreeUtility` | Spanning tree algorithms | 8 / infrastructure |
| `SurgeryUtility` | Mesh surgery (cut/glue) | — |
| `StitchingUtility` | Seam stitching | — |
| `CuttingUtility` | Advanced cutting (beyond tree-cotree) | 9c |
| `HyperellipticUtility` | Hyperelliptic surfaces | 10 |
| `LaplaceUtility` | Discrete Laplace operators | 9 / infrastructure |
| `ConformalStructureUtility` | Conformal structure extraction | 10 |
---
## HyperIdeal Hessian: FD vs. analytic
The Java library computes the HyperIdeal Hessian analytically through the chain:
```
(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ / βᵢ
```
conformallab++ uses a **symmetric finite-difference approximation**:
```
H[i,j] = ( G(x + ε·eⱼ)[i] G(x ε·eⱼ)[i] ) / (2ε), ε = 1e-5
```
Accuracy: O(ε²) ≈ 10⁻¹⁰ relative error. PSD guaranteed by strict convexity (Springborn 2020).
Cost: n extra gradient evaluations per Newton step.
Impact: negligible for meshes < 500 DOFs; measurable for larger meshes.
The analytic Hessian is deferred to Phase 9b.

116
doc/roadmap/phases.md Normal file
View File

@@ -0,0 +1,116 @@
# Development Roadmap
> **Legend:** ✅ complete · 🔲 planned
>
> **Porting / research boundary:**
> Phases 17 are direct ports of the Java original and its dissertation.
> From Phase 8 onwards the work goes beyond the scope of the Java library.
> Phase 8 (CGAL package) is infrastructure. Phase 9 is porting of remaining Java features.
> Phase 10+ is independent research with no direct Java reference implementation.
---
## ◼ Porting complete — Phases 17
```
Phase 1 Clausen / Lobachevsky / ImLi₂ special functions ✅
Phase 2 Hyper-ideal geometry (ζ, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ) ✅
Phase 3 CGAL Surface_mesh infrastructure + all three functionals
(Euclidean, Spherical, HyperIdeal) + analytical Hessians ✅
Phase 4 Newton solver (SimplicialLDLT + SparseQR fallback)
+ Mesh I/O (OFF/OBJ/PLY) + example programs ✅ 68 tests
Phase 5 Priority-BFS layout + CLI app + JSON/XML serialisation ✅ 95 tests
Phase 6 GaussBonnet check/enforce, tree-cotree cut graph (2g),
exact hyperbolic trilateration, layout normalisation ✅ 121 tests
Phase 7 MobiusMap, halfedge_uv, Möbius holonomy (SU(1,1)),
period matrix τ∈ℍ + SL(2,) reduction,
fundamental domain parallelogram + tiling ✅ 158 tests
```
---
## ◼ Infrastructure — Phase 8: CGAL Package
Goal: conformallab++ as a standalone CGAL package, submission-ready, fulfilling all
CGAL package conventions with a traits-class design compatible with any CGAL-conforming
mesh type.
```
8a Traits class & concepts
→ include/CGAL/Conformal_map_traits.h
Separates MeshType, KernelType, ScalarType from the algorithm.
Enables use with any CGAL-compatible mesh, not just Surface_mesh.
→ Concept checks via static_assert / CGAL_concept_check
8b Public CGAL header hierarchy
→ include/CGAL/Discrete_conformal_map.h (user-facing entry header)
→ include/CGAL/Conformal_newton_solver.h
→ include/CGAL/Conformal_layout.h
→ include/CGAL/Conformal_cut_graph.h
All existing include/conformallab/*.hpp remain as implementation details.
8c CGAL-style documentation
→ doc/Conformal_map/PackageDescription.txt
→ doc/Conformal_map/fig/ (pipeline diagrams)
→ Doxygen comments on all public concepts and functions
→ User_manual.md + Reference_manual.md
8d CGAL test format
→ test/Conformal_map/CMakeLists.txt (CGAL-style CMake)
Existing GTest tests remain; CGAL-format tests are added alongside.
8e Declarative YAML pipeline
→ Lightweight YAML format for reproducible experiments
(specification in doc/api/cgal-package.md)
→ Validator: checks require/provide tokens before execution
→ CLI integration: conformallab_core --pipeline experiment.yml
```
---
## ◼ Remaining porting — Phase 9
Java features from `de.varylab.discreteconformal` not yet in C++:
```
9a Inversive-distance functional (Luo 2004 / BowersStephenson)
→ inversive_distance_functional.hpp
Follows the exact same pattern as the three existing functionals.
→ newton_inversive_distance()
→ New test suite: test_inversive_distance.cpp
9b Analytic HyperIdeal Hessian
→ Replace FD Hessian in hyper_ideal_hessian.hpp
Direct differentiation through the chain:
(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ / βᵢ
Relevant for meshes > 500 DOFs (current FD Hessian is slow there).
9c 4g-polygon boundary walk (genus g > 1)
→ Extend compute_fundamental_domain() beyond genus 1
Algorithm outline already in fundamental_domain.hpp as TODO(Phase 9).
Java reference: FundamentalDomainUtility.java
```
---
## ◼ New research — Phase 10+
No direct Java reference implementation exists for these items.
```
Phase 10 Global uniformization for genus g ≥ 2
10a Discrete holomorphic differentials
Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
Mathematical basis: BobenkoSpringborn (2004), §6.
Java partial reference: DiscreteHolomorphicFormUtility.java
10b Siegel period matrix Ω ∈ H_g (g×g complex symmetric, Im(Ω) > 0)
Ωᵢⱼ = ∫_{bⱼ} ωᵢ
Reduction to Siegel fundamental domain via Sp(2g,).
Requires: 10a
10c Full uniformization for genus g ≥ 2
Embedding as H²/Γ with Γ ⊂ PSL(2,) a Fuchsian group.
Requires: 10a + 10b + stable cut graph for g ≥ 2 (Phase 9c)
```