Files
ConformalLabpp/README.md
Tarik Moussa a937edcafe
All checks were successful
C++ Tests / test-fast (push) Successful in 2m5s
C++ Tests / test-cgal (push) Has been skipped
docs: Dissertation, GitHub-Repo, Website und LinkedIn von Stefan Sechelmann ergänzt
README:
- Neuer Einstieg mit vollständiger Dissertation-Referenz (Titel, TU Berlin 2016,
  DOI 10.14279/depositonce-5415, CC BY-SA 4.0)
- Links zu Original-Java-Repo, sechel.de und linkedin.com/in/sechel
- Neuer Abschnitt "Ursprung & Danksagung" vor der Lizenz

doc/architecture/overall_pipeline.md:
- Neuer "Origin"-Abschnitt ganz oben mit vollständiger Quellenangabe
- Literaturabschnitt erweitert: Dissertation als "Primary source" hervorgehoben,
  Java-Original-Repo als direkter Port-Bezug dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 12:33:30 +02:00

609 lines
28 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
[ConformalLab](https://github.com/varylab/conformallab) —
the research software for discrete conformal geometry by
**Stefan Sechelmann** (TU Berlin, Institut für Mathematik).
The algorithmic foundation is his doctoral dissertation:
> Stefan Sechelmann —
> **Variational Methods for Discrete Surface Parameterization: Applications and Implementation**
> Doctoral thesis, Technische Universität Berlin, 2016.
> DOI: [10.14279/depositonce-5415](https://depositonce.tu-berlin.de/items/8e2988b2-d991-45b5-aad5-9fb7988f3b2f)
> License: CC BY-SA 4.0
The dissertation develops the variational framework for discrete conformal equivalence
on triangulations — discrete uniformization of Riemann surfaces, cone metrics, period
matrices — that forms the mathematical core of both the Java original and this C++ port.
**Original Java library:** [github.com/varylab/conformallab](https://github.com/varylab/conformallab) (Java, ~850 commits, v1.0.0 2018)
**Author's website:** [sechel.de](https://sechel.de/) · **LinkedIn:** [linkedin.com/in/sechel](https://www.linkedin.com/in/sechel/)
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)
```
---
## Ursprung & Danksagung
conformallab++ wäre ohne die Grundlagenarbeit von **Stefan Sechelmann** nicht möglich.
Die Algorithmen, die Variationsformulierung und die Idee, diskrete konforme Geometrie
als Newton-Problem auf Winkel-Summen-Energie-Funktionalen zu behandeln, stammen aus:
| | |
|---|---|
| **Dissertation** | Stefan Sechelmann *Variational Methods for Discrete Surface Parameterization: Applications and Implementation*, TU Berlin 2016 |
| **DOI** | [10.14279/depositonce-5415](https://depositonce.tu-berlin.de/items/8e2988b2-d991-45b5-aad5-9fb7988f3b2f) |
| **Java-Originalbibliothek** | [github.com/varylab/conformallab](https://github.com/varylab/conformallab) |
| **Website** | [sechel.de](https://sechel.de/) |
| **LinkedIn** | [linkedin.com/in/sechel](https://www.linkedin.com/in/sechel/) |
Die Dissertation steht unter Creative Commons Attribution ShareAlike 4.0 (CC BY-SA 4.0).
---
## Lizenz
conformallab++ steht unter der MIT-Lizenz (siehe [LICENSE](LICENSE)).