Files
ConformalLabpp/README.md
Tarik Moussa 5333ed143a docs: README vollständig überarbeitet — Phase 7 aktuell, Redundanzen entfernt
- Status-Banner: Phase 7 , 158 Tests (war: Phase 6, 121 Tests)
- Features-Tabelle: Phase 7 Zeilen ergänzt (Priority-BFS, MobiusMap,
  halfedge_uv, Möbius-Holonomie, Periodenmatrix, Fundamentalbereich)
- Bibliotheks-Nutzung: Holonomie/Periodenmatrix/Fundamentalbereich-Beispiele
- Öffentliche Header: period_matrix.hpp + fundamental_domain.hpp ergänzt
- Projektstruktur: neue Dateien + korrigierte Testzahlen
- Test-Suiten: 12 neue Suiten (Phase 7), Gesamt 158
- Mathematischer Umfang:  für Holonomie, Periodenmatrix Genus-1,
  halfedge_uv, exakte Trilateration, Schnittgraph
- Veraltete Abschnitte entfernt: "Porting the Java uniformization pipeline"
  Roadmap (Schritte 1-5 alle umgesetzt), Layout-Vergleich-Codeblöcke
  mit vorgeschlagenen Implementierungen (jetzt live)
- Roadmap: Phase 7  mit Details, Phase 8 geplant
- Sprache: auf Deutsch vereinheitlicht (war gemischt DE/EN)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 10:34:24 +02:00

573 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# conformallab++
conformallab++ is a modern C++ reimplementation of the [ConformalLab](https://github.com/sechel/conformallab) software by Stefan Sechelmann for experiments in discrete conformal geometry and related mesh transformations.
The long-term goal is a **CGAL package** that brings discrete conformal maps (hyper-ideal, spherical, Euclidean) to the CGAL ecosystem using `CGAL::Surface_mesh` as the underlying half-edge data structure.
> **Status:** Phase 7 vollständig abgeschlossen. Alle drei Geometrien lösbar via Newton-Solver (SimplicialLDLT + SparseQR-Fallback). Priority-BFS-Layout in ℝ²/S²/Poincaré-Disk mit exakter hyperbolischer Trilateration, GaussBonnet, Tree-Cotree-Schnittgraph, Möbius-Holonomie, Periodenmatrix (Genus 1), Fundamentalbereich-Polygon, halfedge_uv-Texturatlas. JSON/XML-Serialisierung, vollständige CLI-App. **158 Tests, 2 skipped**.
---
## Features
| Bereich | Status |
|---------|--------|
| Clausen / Lobachevsky / ImLi₂ Funktionen | ✅ Phase 1 |
| Hyper-ideal Geometrie (ζ, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ) | ✅ Phase 2 |
| CGAL `Surface_mesh` Infrastruktur + Mesh-Builder | ✅ Phase 3a |
| Hyper-ideal Funktional (Energie + Gradient) | ✅ Phase 3b |
| Sphärisches Funktional (Energie + Gradient + Gauge-Fix) | ✅ Phase 3c/3e |
| Euklidisches Funktional (Energie + Gradient) | ✅ Phase 3d |
| Euklidischer Hessian (Kotangenten-Laplace, PinkallPolthier) | ✅ Phase 3f |
| Sphärischer Hessian (∂α/∂u aus Kosinussatz) | ✅ Phase 3f |
| Hyper-ideal Hessian (numerisch FD, symmetrisiert) | ✅ Phase 4a |
| Newton-Solver — alle drei Geometrien | ✅ Phase 4a |
| **SparseQR-Fallback** für rangdefiziente H (Gauge-Moden) | ✅ Phase 4a |
| Mesh I/O (CGAL::IO — OFF / OBJ / PLY) | ✅ Phase 4b |
| End-to-End-Pipeline-Tests | ✅ Phase 4c |
| **Beispiel-Programme** (headless + interaktiver Viewer) | ✅ Phase 4d |
| **BFS-Layout** (ℝ², S², Poincaré-Disk) | ✅ Phase 5 |
| **CLI-App** (`conformallab_core`) | ✅ Phase 5 |
| **JSON + XML Serialisierung** | ✅ Phase 5 |
| **GaussBonnet Check + Enforce** | ✅ Phase 6 |
| **Tree-Cotree-Schnittgraph** (2g Naht-Kanten) | ✅ Phase 6 |
| **Exakte hyperbolische Trilateration** (Möbius + Kosinussatz) | ✅ Phase 6 |
| **Layout-Normalisierung** (PCA-Zentrierung / Möbius-Zentrierung) | ✅ Phase 6 |
| **Priority-BFS** (Min-Heap über BFS-Tiefe, minimiert Fehlerakkumulation) | ✅ Phase 7 |
| **MobiusMap** — T(z)=(az+b)/(cz+d), from_three, compose, inverse | ✅ Phase 7 |
| **halfedge_uv** — Naht-bewusstes UV pro Halfedge (GPU-Texturatlas) | ✅ Phase 7 |
| **Möbius-Holonomie** — SU(1,1)-Isometrie pro Schnitt-Kante (hyperbolisch) | ✅ Phase 7 |
| **Periodenmatrix** — τ = ω₂/ω₁ ∈ , SL(2,)-Reduktion (Genus 1) | ✅ Phase 7 |
| **Fundamentalbereich** — CCW-Parallelogramm, Kachelkopien | ✅ Phase 7 |
| Analytischer HyperIdeal-Hessian (ζ-Kette) | ❌ Phase 8 geplant |
| Inversive-Distance-Funktional (Luo 2004) | ❌ nicht portiert |
| Vollständige globale Uniformisierung Genus g ≥ 2 | ❌ Phase 8 geplant |
| Periodenmatrix Siegel Ω (g×g, g ≥ 2) | ❌ Phase 8 geplant |
---
## Quick Start — CLI-App
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -j4
# Konformes Layout für beliebige OFF/OBJ/PLY-Netze
./bin/conformallab_core -i input.off -g euclidean -o layout.off -j result.json -x result.xml
# Geometrien: euclidean | spherical | hyper_ideal
./bin/conformallab_core -i input.off -g spherical -o sphere.off
# Interaktiver Viewer
./bin/conformallab_core -i input.off -s
```
### Beispiel-Programme
```bash
./build/examples/example_layout [input.off] [layout.off] [result.json] [result.xml]
./build/examples/example_euclidean [input.off] [output.off]
./build/examples/example_hyper_ideal [input.off] [output.off]
./build/examples/example_viewer [input.off] # interaktiv (WITH_VIEWER)
```
---
## Bibliotheks-Nutzung
### Minimale euklidische Pipeline
```cpp
#include "conformal_mesh.hpp"
#include "mesh_io.hpp"
#include "euclidean_functional.hpp"
#include "newton_solver.hpp"
#include "layout.hpp"
using namespace conformallab;
int main() {
ConformalMesh mesh = load_mesh("input.off");
auto maps = setup_euclidean_maps(mesh);
compute_euclidean_lambda0_from_mesh(mesh, maps);
// DOFs zuweisen — ersten Vertex pinnen (Gauge-Fix)
auto vit = mesh.vertices().begin();
maps.v_idx[*vit++] = -1;
int idx = 0;
for (; vit != mesh.vertices().end(); ++vit)
maps.v_idx[*vit] = idx++;
// Zielwinkel: natürliches Gleichgewicht (x* = 0)
std::vector<double> x0(idx, 0.0);
auto G0 = euclidean_gradient(mesh, x0, maps);
for (auto v : mesh.vertices()) {
int iv = maps.v_idx[v];
if (iv >= 0) maps.theta_v[v] -= G0[iv];
}
auto res = newton_euclidean(mesh, x0, maps);
if (res.converged)
save_mesh("output.off", mesh);
return res.converged ? 0 : 1;
}
```
### Layout + Holonomie (geschlossene Flächen)
```cpp
#include "layout.hpp"
#include "cut_graph.hpp"
#include "period_matrix.hpp"
#include "fundamental_domain.hpp"
// Schnittgraph berechnen (Tree-Cotree, 2g Kanten)
CutGraph cg = compute_cut_graph(mesh);
// Layout mit Holonomie-Tracking
HolonomyData hol;
Layout2D lay = euclidean_layout(mesh, res.x, maps, &cg, &hol, /*normalise=*/true);
// Periodenmatrix (Genus 1)
PeriodData pd = compute_period_matrix(hol); // τ = ω₂/ω₁ ∈ , SL(2,)-reduziert
std::cout << "τ = " << pd.tau << "\n";
// Fundamentalbereich-Parallelogramm
FundamentalDomain fd = compute_fundamental_domain(hol);
// fd.vertices — 4 Ecken (CCW)
// fd.generators — ω₁, ω₂
// Kachelkopie für Universalüberlagerung
Layout2D tile = tiling_copy(lay, fd.generators[0], fd.generators[1], 1, -1);
// halfedge_uv — Naht-bewusstes UV pro Halfedge (GPU-Texturatlas)
// lay.halfedge_uv[h.idx()] = UV von source(h) aus Sicht von face(h)
```
### HyperIdeal-Geometrie
```cpp
auto maps = setup_hyper_ideal_maps(mesh);
int n = assign_all_dof_indices(mesh, maps);
auto result = newton_hyper_ideal(mesh, x0, maps);
// Möbius-Holonomie (SU(1,1)-Isometrien pro Schnitt-Kante)
HolonomyData hol;
Layout2D lay = hyper_ideal_layout(mesh, result.x, maps, &cg, &hol);
// hol.mobius_maps[i] = T_i (Möbius-Abbildung für i-te Schnitt-Kante)
```
### SparseQR-Fallback direkt nutzen
```cpp
#include "newton_solver.hpp"
bool used_fallback = false;
auto dx = conformallab::solve_linear_system(H, rhs, &used_fallback);
if (used_fallback)
std::cout << "SparseQR verwendet (H ist rangdefizient)\n";
```
---
## Build-Modi
| Modus | CMake-Flags | Was wird gebaut |
|-------|------------|-----------------|
| **Nur Tests** (Standard) | *(keine)* | `conformallab_tests` — Eigen + GTest |
| **CGAL-Tests + Beispiele** | `-DWITH_CGAL=ON` | `conformallab_cgal_tests`, Beispiel-Programme, CLI |
| **Interaktiver Viewer** | `-DWITH_CGAL=ON` | + `example_viewer`, Viewer in CLI integriert |
Externe Abhängigkeiten sind als Tarballs in `code/deps/tarballs/` enthalten und werden beim CMake-Configure-Schritt extrahiert (GTest via `FetchContent`). **Boost** wird nur mit `-DWITH_CGAL=ON` benötigt (Header-Only durch CGAL 6.x).
---
## Voraussetzungen
| Tool | Minimum |
|------|---------|
| C++ Compiler (GCC oder Clang) | C++17 |
| CMake | 3.20 |
| Boost Headers | 1.70 *(nur mit `-DWITH_CGAL=ON`)* |
---
## Einstieg
```bash
git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
```
### Nur Tests (CI-Standard — keine System-Abhängigkeiten)
```bash
cmake -S code -B build
cmake --build build --target conformallab_tests -j$(nproc)
ctest --test-dir build --output-on-failure
```
### CGAL-Tests + Beispiele (benötigt System-Boost)
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -j$(nproc)
ctest --test-dir build -R "^cgal\." --output-on-failure
./build/examples/example_layout
./bin/conformallab_core -i input.off -g euclidean -o layout.off
```
Erwartet: **158 Tests bestanden, 2 skipped** (die zwei `@Ignore`-Hessian-Stubs).
### Interaktiver Viewer
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -t example_viewer -j$(nproc)
./build/examples/example_viewer data/off/example.off
```
---
## Öffentliche Header (`code/include/`)
| Header | Beschreibung |
|--------|-------------|
| `clausen.hpp` | Clausen Cl₂, Lobachevsky Л, ImLi₂ |
| `hyper_ideal_geometry.hpp` | ζ-Funktionen, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ |
| `hyper_ideal_utility.hpp` | Tetraeder-Volumen (Meyerhoff / KolpakovMednykh) |
| `hyper_ideal_functional.hpp` | HyperIdeal Energie + Gradient auf `ConformalMesh` |
| `hyper_ideal_hessian.hpp` | HyperIdeal Hessian (numerisch FD, symmetrisiert) |
| `hyper_ideal_visualization_utility.hpp` | Poincaré-Disk-Projektion, Umkreis-Helfer |
| `spherical_geometry.hpp` | Sphärische Bogenlänge, Halbwinkelformel |
| `spherical_functional.hpp` | Sphärisch: Energie + Gradient + Gauge-Fix |
| `spherical_hessian.hpp` | Sphärischer Hessian (∂α/∂u, Kosinussatz) |
| `euclidean_geometry.hpp` | Euklidischer Eckenwinkel (t-Wert / atan2) |
| `euclidean_functional.hpp` | Euklidisch: Energie + Gradient |
| `euclidean_hessian.hpp` | Kotangenten-Laplace Hessian (PinkallPolthier) |
| `newton_solver.hpp` | `newton_{euclidean,spherical,hyper_ideal}` + öffentliches `solve_linear_system` |
| `conformal_mesh.hpp` | `ConformalMesh` = `CGAL::Surface_mesh<Point3>` + Property-Map-Helfer |
| `mesh_builder.hpp` | `make_triangle` / `make_tetrahedron` / `make_quad_strip` / `make_fan` / … |
| `mesh_io.hpp` | `read_mesh` / `write_mesh` / `load_mesh` / `save_mesh` |
| `mesh_utils.hpp` | CGAL → Eigen Konvertierung (`cgal_to_eigen`) |
| `serialization.hpp` | `save/load_result_json` + `save/load_result_xml` |
| `gauss_bonnet.hpp` | `euler_characteristic`, `genus`, `gauss_bonnet_sum/rhs/deficit`, `check_gauss_bonnet`, `enforce_gauss_bonnet` |
| `cut_graph.hpp` | `CutGraph` + `compute_cut_graph` (Tree-Cotree, EricksonWhittlesey 2005) |
| `layout.hpp` | `euclidean/spherical/hyper_ideal_layout``Layout2D/3D`; `MobiusMap`; `halfedge_uv`; Priority-BFS; `HolonomyData`; `normalise_*` |
| `period_matrix.hpp` | `PeriodData`, `compute_period_matrix`, `reduce_to_fundamental_domain`, `is_in_fundamental_domain` |
| `fundamental_domain.hpp` | `FundamentalDomain`, `compute_fundamental_domain_{genus1,}`, `tiling_copy`, `tiling_neighbourhood` |
| `constants.hpp` | `conformallab::PI`, `TWO_PI` |
---
## Projektstruktur
```
code/
├── include/ # Alle öffentlichen Header (Header-Only-Bibliothek)
│ ├── conformal_mesh.hpp
│ ├── mesh_builder.hpp
│ ├── mesh_io.hpp / mesh_utils.hpp
│ ├── newton_solver.hpp # 3 Newton-Solver + solve_linear_system
│ ├── layout.hpp # Priority-BFS, MobiusMap, halfedge_uv, Holonomie
│ ├── serialization.hpp
│ ├── gauss_bonnet.hpp
│ ├── cut_graph.hpp # Tree-Cotree
│ ├── period_matrix.hpp # τ ∈ , SL(2,)-Reduktion (Genus 1)
│ ├── fundamental_domain.hpp # Parallelogramm, Kacheln; 4g-Polygon TODO Phase 8
│ ├── hyper_ideal_{functional,hessian,geometry,utility,visualization_utility}.hpp
│ ├── spherical_{functional,hessian,geometry}.hpp
│ ├── euclidean_{functional,hessian,geometry}.hpp
│ ├── clausen.hpp
│ └── constants.hpp
├── examples/
│ ├── example_euclidean.cpp
│ ├── example_hyper_ideal.cpp
│ ├── example_layout.cpp # Solve → Layout → OFF/JSON/XML + Round-Trip
│ └── example_viewer.cpp # Interaktiver libigl-Viewer
├── src/
│ ├── apps/v0/conformallab_cli.cpp # CLI-App (Phase 5)
│ └── viewer/simple_viewer.cpp
├── tests/
│ ├── *.cpp # conformallab_tests (kein CGAL)
│ └── cgal/
│ ├── test_conformal_mesh.cpp # 14 Tests
│ ├── test_hyper_ideal_functional.cpp # 7 Tests
│ ├── test_spherical_functional.cpp # 12 Tests (1 skipped)
│ ├── test_euclidean_functional.cpp # 11 Tests (1 skipped)
│ ├── test_euclidean_hessian.cpp # 9 Tests
│ ├── test_spherical_hessian.cpp # 8 Tests
│ ├── test_newton_solver.cpp # 14 Tests
│ ├── test_mesh_io.cpp # 9 Tests
│ ├── test_pipeline.cpp # 5 Tests
│ ├── test_layout.cpp # 8 Tests (Layout + JSON/XML)
│ ├── test_phase6.cpp # 26 Tests (GB, CutGraph, Trilateration)
│ └── test_phase7.cpp # 37 Tests (MobiusMap, Priority-BFS,
│ # halfedge_uv, Periodenmatrix, FD)
└── deps/
├── eigen-3.4.0/
├── CGAL-6.1.1/
├── libigl-2.6.0/
├── glfw-3.4/
└── single_includes/ # CLI11, json.hpp
```
---
## Test-Suiten
### `conformallab_tests` (CI — immer gebaut)
Reine Mathe-Tests, nur Eigen: Clausen / Lobachevsky / ImLi₂, Hyper-ideal Geometrie, Tetraeder-Volumina.
### `conformallab_cgal_tests` (lokal — `-DWITH_CGAL=ON`)
| Suite | Tests | Was geprüft wird |
|-------|------:|-----------------|
| `ConformalMeshTopology` | 4 | Euler-Charakteristik, Vertex/Edge/Face-Anzahl |
| `ConformalMeshTraversal` | 4 | Halfedge-Iteration, Valenz, Opposite |
| `ConformalMeshProperties` | 5 | Property-Maps (λ, θ, idx, α, Geometrietyp) |
| `ConformalMeshValidity` | 1 | CGAL-Validität für alle Factory-Meshes |
| `HyperIdealFunctional` | 7 | FD-Gradient-Checks + Hessian-Symmetrie |
| `SphericalFunctional` | 12 | Winkelformel + Gradient + Gauge-Fix (1 skipped) |
| `EuclideanFunctional` | 11 | Winkelformel + Gradient (1 skipped) |
| `EuclideanHessian` | 9 | Kotangenten-Laplace-Struktur, FD-Übereinstimmung, PSD, Nullraum |
| `SphericalHessian` | 8 | Ableitungskorrektheit, NSD am Gleichgewicht |
| `NewtonSolver` | 11 | Konvergenz (Eucl. ×3, Sphär. ×4, HyperIdeal ×4) |
| `SparseQRFallback` | 3 | Full-Rank-LDLT · singuläre Matrix → QR · geschlossenes Mesh |
| `MeshIO` | 9 | OFF/OBJ Round-Trips, Fehlerbehandlung |
| `Pipeline` | 5 | End-to-End: Build → Setup → Solve → Export → Reload |
| `Layout` | 8 | Kantenlängen-Erhaltung (Eucl./Sphär.), Poincaré-Disk |
| `Serialization` | 2 | JSON- und XML-Round-Trips (DOF + Layout) |
| `GaussBonnet` | 8 | χ, Genus, Summe/RHS, Defizit, Check, Enforce |
| `CutGraph` | 6 | Tree-Cotree, offene/geschlossene Meshes, FlagIndex-Konsistenz |
| `HyperbolicTrilateration` | 4 | Möbius + Kosinussatz: exakte Abstände, Disk-Inneres, off-origin |
| `Normalisation` | 4 | Eukl. Schwerpunkt, Längenverhältnisse, Möbius-Zentrierung |
| `MobiusMap` | 8 | Identity, Inverse, Compose, from_three, apply(Vector2d) |
| `BestRootFace` | 2 | Gültige Wurzel-Fläche, Interior-Bonus |
| `HalfedgeUV` | 4 | Größe = #Halfedges, Naht-Konsistenz, Randhalfedges = 0 |
| `PriorityBFS` | 3 | Erfolg, kein Seam bei offenen Meshes, alle Vertices platziert |
| `NormaliseEuclidean` | 2 | UV-Schwerpunkt = 0, halfedge_uv-Schwerpunkt = 0 |
| `PeriodMatrix` | 7 | τ ∈ , SL(2,)-Reduktion, Ausnahme außerhalb |
| `FundamentalDomain` | 7 | Genus-1-Parallelogramm CCW, Generatoren, g>1 leer |
| `TilingCopy/Neighbourhood` | 4 | Verschiebung korrekt, Anzahl Kacheln |
| **Gesamt** | **158** | **2 skipped** (Hessian-Stubs, identisch mit Java `@Ignore`) |
---
## Newton-Solver & SparseQR-Fallback
`newton_solver.hpp` stellt drei Solver mit einheitlicher Schnittstelle bereit:
```
NewtonResult newton_euclidean (mesh, x0, maps [, tol, max_iter])
NewtonResult newton_spherical (mesh, x0, maps [, tol, max_iter])
NewtonResult newton_hyper_ideal(mesh, x0, maps [, tol, max_iter, hess_eps])
```
Jede Iteration: Gradient **G** → Hessian **H** → löse **H·Δx = G** (SimplicialLDLT, Fallback SparseQR) → Backtracking-Liniensuche.
| Geometrie | **G** | **H**-Vorzeichen |
|-----------|-------|-----------------|
| Euklidisch | Θ_v Σα_v | PSD → LDLT auf H |
| Sphärisch | Θ_v Σα_v | NSD → LDLT auf **H** |
| HyperIdeal | Σβ_v Θ_v | PSD → LDLT auf H |
**SparseQR-Fallback** (`solve_linear_system`): Bei rangdefizientem **H** (Gauge-Moden bei geschlossenen Meshes ohne gepinnten Vertex) findet SparseQR den minimalen Newton-Schritt orthogonal zum Nullraum.
---
## Mathematischer Umfang — C++ vs. Java-Original
| Mathematische Schicht | Java ConformalLab | conformallab++ |
|---|---|---|
| Euklidisches Funktional — Energie, Gradient | ✅ | ✅ |
| Sphärisches Funktional — Energie, Gradient, Gauge-Fix | ✅ | ✅ |
| HyperIdeal Funktional — Energie, Gradient | ✅ | ✅ |
| Inversive-Distance-Funktional (Luo 2004) | ✅ | ❌ nicht portiert |
| Euklidischer Hessian — Kotangenten-Laplace | ✅ analytisch | ✅ analytisch |
| Sphärischer Hessian — ∂α/∂u aus Kosinussatz | ✅ analytisch | ✅ analytisch |
| HyperIdeal Hessian — ζ → lᵢⱼ → β/α Kette | ✅ analytisch | ⚠️ symmetrisches FD |
| Newton-Solver | ✅ | ✅ |
| SparseQR-Fallback für Gauge-Moden | ? | ✅ |
| Kegelmetriken — vorgeschriebenes Θ_v ≠ 2π | ✅ vollständig | ⚠️ nur Datenstruktur |
| Layout / Einbettung — ℝ² / H² / S² | ✅ | ✅ Priority-BFS, alle drei |
| Exakte hyperbolische Trilateration | ✅ Möbius | ✅ Möbius + Kosinussatz |
| halfedge_uv — Naht-bewusstes UV (Texturatlas) | ✅ | ✅ |
| GaussBonnet Konsistenzprüfung | ✅ | ✅ |
| Tree-Cotree-Schnittgraph (2g Kanten) | ✅ | ✅ EricksonWhittlesey |
| Holonomie / Monodromie — Euklidisch (Translationen) | ✅ | ✅ |
| Holonomie — Hyperbolisch (SU(1,1) Möbius-Mappe) | ✅ | ✅ |
| Periodenmatrix τ — Genus 1 (SL(2,)-reduziert) | ✅ | ✅ |
| Fundamentalbereich-Polygon — Genus 1 | ✅ | ✅ CCW-Parallelogramm |
| 4g-Polygon-Randlauf — Genus g > 1 | ✅ | ❌ TODO Phase 8 |
| Periodenmatrix Siegel Ω — Genus g ≥ 2 | ✅ | ❌ TODO Phase 8 |
| Globale Uniformisierung — Genus g ≥ 2 | ✅ | ❌ Phase 8 geplant |
| Clausen / Lobachevsky / ImLi₂ | ✅ | ✅ |
| Poincaré-Disk / Lorentz-Boost Visualisierung | ✅ | ✅ |
| Mesh I/O + Serialisierung | ✅ XML/CoHDS | ✅ OFF/OBJ/PLY + JSON/XML |
| Interaktiver Viewer | ✅ jReality | ✅ libigl/GLFW |
### HyperIdeal Hessian — numerisch vs. analytisch
Der analytische Hessian des HyperIdeal-Funktionals erfordert Differentiation durch die Kette `(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/₁₄/₁₅ → αᵢⱼ / βᵢ` (vier Vertex-Typ-Kombinationen pro Kante). conformallab++ verwendet stattdessen einen symmetrisierten Finite-Differenzen-Hessian:
```
H[i,j] = ( G(x + ε·eⱼ)[i] G(x ε·eⱼ)[i] ) / (2ε)
```
O(ε²)-genau (≈ 10⁻¹⁰ relativer Fehler bei ε = 10⁻⁵), PSD durch strikte Konvexität (Springborn 2020), kostet n zusätzliche Gradient-Auswertungen pro Newton-Schritt. Für Meshes mit < 500 DOFs ist der Unterschied in der Wandzeit vernachlässigbar. Der analytische Hessian ist für Phase 8 geplant.
---
## Für Mathematiker — Bibliothek erweitern
### Mentales Modell
```
ConformalMesh — Halfedge-Mesh (CGAL::Surface_mesh)
+ Property-Maps — per-Vertex/Edge Daten (λ, θ, α, DOF-Index, …)
Maps-Struct — sammelt alle Property-Maps für ein Funktional
theta_v[v] — Zielwinkel bei Vertex v (Eingabe)
v_idx[v] — DOF-Index, oder 1 wenn gepinnt
e_idx[e] — DOF-Index für Kanten-DOFs (nur HyperIdeal)
x ∈ ℝⁿ — DOF-Vektor, den der Solver optimiert
evaluate_*(mesh, x, maps) → { Energie, Gradient, … }
newton_*(mesh, x0, maps) → { x*, Iterationen, converged, … }
```
Die Mesh-Geometrie (Vertex-Positionen) dient nur zur Initialisierung der Log-Kantenlängen λ°. Danach arbeitet der Solver ausschließlich im x-Raum.
### Neues Funktional hinzufügen
1. **Maps-Struct**: `setup_my_maps(mesh)` mit Property-Maps für λ, θ_v, v_idx
2. **Energie + Gradient**: Schleife über `mesh.faces()`, akkumuliere in `grad[v_idx[v]]`
3. **Gradient-Check**: Finite-Differenzen-Verifikation (Vorlage in jedem `test_*_functional.cpp`)
4. **Newton-Solver**: `solve_linear_system(H, -G, &used_fallback)` direkt nutzen
### Halfedge-Mesh navigieren
```cpp
for (auto f : mesh.faces()) {
auto h0 = mesh.halfedge(f);
auto h1 = mesh.next(h0);
auto h2 = mesh.next(h1);
Vertex_index v_opp = mesh.target(h2); // dem Halfedge h0 gegenüberliegend
int dof = maps.v_idx[v_opp]; // 1 = gepinnt
bool is_boundary = mesh.is_border(mesh.opposite(h0));
}
```
### Neue Daten am Mesh befestigen
```cpp
auto [curv, created] = mesh.add_property_map<Vertex_index, double>("v:my_curv", 0.0);
curv[v] = 1.234;
```
### Schnell-Start-Checkliste
1. `examples/example_layout.cpp` lesen zeigt die vollständige Pipeline in ~120 Zeilen
2. `cmake -S code -B build -DWITH_CGAL=ON && cmake --build build --target example_layout`
3. Gradient-Check-Test in `tests/cgal/` hinzufügen (beliebigen `GradientCheck_*`-Block kopieren)
4. Verschiedene Zielwinkel ausprobieren: `maps.theta_v[v] = M_PI / 3` für alle Innen-Vertices. Die GaussBonnet-Bedingung Σ( Θ_v) = ·χ(M) muss erfüllt sein.
5. Konvergenz beobachten: `NewtonResult` enthält `iterations` und `grad_inf_norm`
### Weiterführende Literatur
| Quelle | Bezug |
|--------|-------|
| Springborn *Ideal Hyperbolic Polyhedra and Discrete Uniformization* (2020) | HyperIdeal-Funktional; ζ₁₃/₁₄/₁₅ in `hyper_ideal_geometry.hpp` |
| Pinkall, Polthier *Computing Discrete Minimal Surfaces* (1993) | Kotangenten-Laplace in `euclidean_hessian.hpp` |
| Luo *Combinatorial Yamabe Flow on Surfaces* (2004) | Inversive-Distance-Funktional (noch nicht portiert) |
| Bobenko, Springborn *Variational Principles for Circle Patterns* (2004) | Hintergrund für das Winkelsum-Variationsprinzip |
| Erickson, Whittlesey *Greedy Optimal Homotopy and Homology Generators* (SODA 2005) | Tree-Cotree-Algorithmus in `cut_graph.hpp` |
---
## Schlüssel-Designentscheidungen
**CGAL als CoHDS-Ersatz.** `CGAL::Surface_mesh<Point3>` ersetzt die Java-`CoHDS`-Halfedge-Datenstruktur. Vertex/Edge/Face/Halfedge-Deskriptoren sind typisierte Integer.
**Property-Maps.** `mesh.add_property_map<Vertex_index, double>("v:lambda", 0.0)` ersetzt das Java-Adapter/Decorator-Pattern.
**DOF-Vektor-Konvention.** Alle Funktionale verwenden `x` indiziert durch `v_idx[v]` / `e_idx[e]` (1 = gepinnt). Einheitlich über alle drei Geometrien.
**Priority-BFS.** Faces werden in aufsteigender BFS-Tiefe verarbeitet (Min-Heap über `depth = max(depth[v_src], depth[v_tgt]) + 1`). Dies minimiert die Akkumulation von Trilaterations-Fehlern je weiter eine Fläche vom Ursprung entfernt ist, desto später wird sie platziert.
**halfedge_uv-Semantik.** `halfedge_uv[h.idx()]` ist das UV von `source(h)` aus Sicht von `face(h)`. An Naht-Halfedges tragen die beiden gegenüberliegenden Halfedges unterschiedliche UV-Werte so erhält jede Fläche ihre eigene Kopie eines Naht-Vertex für GPU-Texturatlas ohne Vertex-Duplizierung.
**HyperIdeal Hessian via FD.** Der analytische Hessian durch `ζ13/14/15 → lij → β/α` ist auf Phase 8 verschoben. Ein symmetrischer FD-Hessian ist O(ε²)-genau, PSD durch strikte Konvexität und für < 500 DOFs ausreichend.
**Sphärischer Hessian Vorzeichen.** Die sphärische Energie ist **konkav** (Hessian NSD). Newton löst `(H)·Δx = G`, das Vorzeichen wird transparent in `newton_spherical` behandelt.
---
## CI
Tests laufen automatisch bei Push auf `main`, `dev` und `claude/**`-Branches via selbst-gehostetem Gitea-Actions-Runner (`eulernest`, ARM64). **Nur `conformallab_tests` läuft in CI** (kein Boost/CGAL dort).
```bash
# CI-Image neu bauen und pushen
docker buildx build \
--platform linux/arm64 \
-f .gitea/docker/Dockerfile.ci-cpp \
-t git.eulernest.eu/conformallab/ci-cpp:latest \
--push \
.gitea/docker/
```
---
## Roadmap
```
Phase 1 Clausen / Lobachevsky / ImLi₂ ✅ abgeschlossen
Phase 2 Hyper-ideal Geometrie (ζ, lᵢⱼ, αᵢⱼ, σᵢ) ✅ abgeschlossen
Phase 3 CGAL Infrastruktur + alle drei Funktionale
+ analytische Hessians (Eucl. + Sphär.) ✅ abgeschlossen
Phase 4 Newton-Solver + SparseQR-Fallback + Mesh-I/O
+ Beispiel-Programme ✅ abgeschlossen
Phase 5 BFS-Layout + CLI + JSON/XML-Serialisierung ✅ abgeschlossen
→ 95 Tests
Phase 6 Layout-Erweiterung (Java-Parität I) ✅ abgeschlossen
→ gauss_bonnet.hpp: χ, Genus, Σ(2π-Θ_v) Check + Enforce
→ cut_graph.hpp: Tree-Cotree (EricksonWhittlesey 2005), 2g Schnitt-Kanten
→ Exakte hyperbolische Trilateration (Möbius + Kosinussatz)
→ normalise_{euclidean,hyperbolic,spherical}
→ CutGraph* + HolonomyData* in allen Layout-Funktionen
→ 121 Tests (+26 Phase-6-Tests)
Phase 7 Layout-Erweiterung (Java-Parität II) ✅ abgeschlossen
→ layout.hpp: Priority-BFS (Min-Heap, BFS-Tiefe)
→ layout.hpp: MobiusMap — T(z)=(az+b)/(cz+d), from_three, compose
→ layout.hpp: halfedge_uv — Naht-bewusstes UV pro Halfedge
→ layout.hpp: Möbius-Holonomie (SU(1,1) pro Schnitt-Kante, hyperbolisch)
→ layout.hpp: best_root_face (größte 3D-Fläche, 1.5× Interior-Bonus)
→ layout.hpp: Flächen-gewichtete iterative Möbius-Zentrierung (Fréchet-Mittel)
→ period_matrix.hpp: τ = ω₂/ω₁ ∈ , SL(2,)-Reduktion
→ fundamental_domain.hpp: CCW-Parallelogramm, Kanten-Identifikationen,
Kachelkopien; 4g-Polygon-Randlauf → TODO Phase 8
→ 158 Tests (+37 Phase-7-Tests)
Phase 8 (geplant)
→ Analytischer HyperIdeal-Hessian (direkte Ableitung durch ζ-Kette)
→ 4g-Polygon-Randlauf für Genus g > 1 (Grenzwert-Walk auf geschnittenem Mesh)
→ Siegel-Periodenmatrix Ω (g×g, g ≥ 2) via Integration holomorpher Differentiale
→ Vollständige globale Uniformisierung geschlossener Flächen beliebigen Genus
→ Inversive-Distance-Funktional (Luo 2004)
```
---
## Lizenz
conformallab++ steht unter der MIT-Lizenz (siehe [LICENSE](LICENSE)).