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>
4.7 KiB
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.
Gauss–Bonnet constraint
Before calling any Newton solver, the target angles must satisfy the Gauss–Bonnet 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.
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.