Files
ConformalLabpp/doc/math/geometry-modes.md
Tarik Moussa 14134b99ce
Some checks failed
C++ Tests / test-fast (push) Successful in 2m25s
C++ Tests / test-cgal (push) Failing after 1m58s
docs: restructure documentation into focused files
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>
2026-05-17 21:17:15 +02:00

4.7 KiB
Raw Blame History

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.

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.