Structured the development roadmap into four blocks with an explicit boundary marker separating direct Java ports (Phase 1–7) from infrastructure (Phase 8), remaining porting (Phase 9), and new research territory (Phase 10+). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
31 KiB
conformallab++
conformallab++ is a modern C++ reimplementation of 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
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 (Java, ~850 commits, v1.0.0 2018)
Author's website: sechel.de · LinkedIn: 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, Gauss–Bonnet, 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, Pinkall–Polthier) | ✅ 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 |
| Gauss–Bonnet 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
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
./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
#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)
#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
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
#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
git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
Nur Tests (CI-Standard — keine System-Abhängigkeiten)
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)
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
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 / Kolpakov–Mednykh) |
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 (Pinkall–Polthier) |
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, Erickson–Whittlesey 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, Flag–Index-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) | ✅ | ✅ |
| Gauss–Bonnet Konsistenzprüfung | ✅ | ✅ |
| Tree-Cotree-Schnittgraph (2g Kanten) | ✅ | ✅ Erickson–Whittlesey |
| 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
- Maps-Struct:
setup_my_maps(mesh)mit Property-Maps für λ, θ_v, v_idx - Energie + Gradient: Schleife über
mesh.faces(), akkumuliere ingrad[v_idx[v]] - Gradient-Check: Finite-Differenzen-Verifikation (Vorlage in jedem
test_*_functional.cpp) - Newton-Solver:
solve_linear_system(H, -G, &used_fallback)direkt nutzen
Halfedge-Mesh navigieren
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
auto [curv, created] = mesh.add_property_map<Vertex_index, double>("v:my_curv", 0.0);
curv[v] = 1.234;
Schnell-Start-Checkliste
examples/example_layout.cpplesen — zeigt die vollständige Pipeline in ~120 Zeilencmake -S code -B build -DWITH_CGAL=ON && cmake --build build --target example_layout- Gradient-Check-Test in
tests/cgal/hinzufügen (beliebigenGradientCheck_*-Block kopieren) - Verschiedene Zielwinkel ausprobieren:
maps.theta_v[v] = M_PI / 3für alle Innen-Vertices. Die Gauss–Bonnet-Bedingung Σ(2π − Θ_v) = 2π·χ(M) muss erfüllt sein. - Konvergenz beobachten:
NewtonResultenthältiterationsundgrad_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).
# 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
Legende: ✅ abgeschlossen · 🔲 geplant
Grenze Portierung / neue Forschung:
Phase 1–7 sind direkte Portierungen aus dem Java-Original bzw. seiner Dissertation.
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) ist Portierung ausstehender Java-Features.
— Phase 10+ ist eigenständige Forschung, die über das Java-Original hinausgeht.
◼ Portierungsphase abgeschlossen
Phase 1 Clausen / Lobachevsky / ImLi₂ ✅
Phase 2 Hyper-ideal Geometrie (ζ, lᵢⱼ, αᵢⱼ, σᵢ) ✅
Phase 3 CGAL-Infrastruktur + alle drei Funktionale
+ analytische Hessians (Eucl. + Sphär.) ✅
Phase 4 Newton-Solver (SimplicialLDLT + SparseQR-Fallback)
+ Mesh-I/O + Beispielprogramme ✅
Phase 5 Priority-BFS-Layout + CLI + JSON/XML ✅ 95 Tests
Phase 6 Layout-Parität I ✅ 121 Tests
→ gauss_bonnet.hpp — χ, Genus, Σ(2π-Θ_v) Check + Enforce
→ cut_graph.hpp — Tree-Cotree (Erickson–Whittlesey 2005), 2g Schnitt-Kanten
→ Exakte hyperbolische Trilateration (Möbius + Kosinussatz)
→ normalise_{euclidean,hyperbolic,spherical}
Phase 7 Layout-Parität II ✅ 158 Tests
→ MobiusMap — T(z)=(az+b)/(cz+d), from_three, compose, inverse
→ halfedge_uv — naht-bewusstes UV pro Halfedge (GPU-Texturatlas)
→ Möbius-Holonomie als SU(1,1)-Isometrie (hyperbolisch)
→ period_matrix.hpp — τ = ω₂/ω₁ ∈ ℍ, SL(2,ℤ)-Reduktion
→ fundamental_domain.hpp — CCW-Parallelogramm, Kachelung
◼ Infrastruktur (über Java-Bibliothek hinaus)
Phase 8 CGAL-Paket-Struktur 🔲 (nächste Phase)
Ziel: conformallab++ als eigenständiges CGAL-Paket, das in CGAL integriert
werden kann und dessen Konventionen vollständig erfüllt.
8a — Traits-Klasse & Konzepte
→ include/CGAL/Conformal_map_traits.h
Trennt MeshType, KernelType, ScalarType vom Algorithmus.
Ermöglicht Nutzung mit beliebigem CGAL-kompatiblem Mesh.
→ Konzept-Checks (static_assert / CGAL_concept_check)
8b — Öffentliche CGAL-Header-Hierarchie
→ include/CGAL/Discrete_conformal_map.h (zentraler Nutzer-Header)
→ include/CGAL/Conformal_newton_solver.h
→ include/CGAL/Conformal_layout.h
→ include/CGAL/Conformal_cut_graph.h
→ include/CGAL/conformal_map_package.h (Package-Description)
Alle bestehenden include/conformallab/*.hpp bleiben als Impl.-Detail.
8c — Dokumentation im CGAL-Stil
→ doc/Conformal_map/PackageDescription.txt
→ doc/Conformal_map/fig/ (Pipeline-Diagramme)
→ Doxygen-Kommentare für alle öffentlichen Konzepte + Funktionen
→ User_manual.md + Reference_manual.md
8d — CGAL-Testformat
→ test/Conformal_map/ (CMakeLists.txt im CGAL-Format)
Bestehende GTest-Tests bleiben; CGAL-Tests kommen als zweites Format.
8e — Declarative YAML-Pipeline
→ Leichtgewichtiges YAML-Format für reproduzierbare Experimente
(Spezifikation bereits in doc/architecture/overall_pipeline.md)
→ Validator: prüft require/provide-Tokens vor der Ausführung
→ Einbindung in CLI-App: conformallab_core --pipeline experiment.yml
◼ Ausstehende Portierung (Java-Features noch nicht übertragen)
Phase 9 Verbleibende Java-Parität 🔲
9a — Inversive-Distance-Funktional (Luo 2004 / Bowers–Stephenson)
→ inversive_distance_functional.hpp (folgt exakt dem Muster der
bestehenden drei Funktionale — niedrigstes Risiko)
→ newton_inversive_distance()
→ Neue Test-Suite: test_inversive_distance.cpp
9b — Analytischer HyperIdeal-Hessian
→ Direkte Ableitung durch die Kette
(b_i, a_e) → l_ij → ζ₁₃/ζ₁₄/ζ₁₅ → α_ij / β_i
→ Ersetzt den symmetrischen FD-Hessian in hyper_ideal_hessian.hpp
→ Relevant für Meshes > 500 DOFs (aktueller FD-Hessian ist dort langsam)
→ Aufwand: ~2 Wochen (viele verschachtelte Fallunterscheidungen)
9c — 4g-Polygon-Randlauf (Genus g > 1)
→ Boundary-Walk auf dem aufgeschnittenen Mesh
→ Befüllt fundamental_domain.hpp für g > 1 (aktuell: leeres Objekt)
→ Algorithmus-Skizze bereits als TODO(Phase 8) in fundamental_domain.hpp
◼ Neue Forschung (über das Java-Original hinaus)
Ab hier gibt es keine direkte Java-Referenzimplementierung mehr. Jedes Item ist eigenständige mathematische Arbeit.
Phase 10 Globale Uniformisierung Genus g ≥ 2 🔲 (Forschung)
10a — Holomorphe Differentiale auf diskreten Flächen
Integration ω_i längs der b-Zyklen des Schnittgraphen.
Mathematische Grundlage: Bobenko–Springborn (2004), §6.
10b — Siegel-Periodenmatrix Ω ∈ H_g (g×g, g ≥ 2)
Ω_ij = ∫_{b_j} ω_i — komplexe symmetrische Matrix,
Im(Ω) positiv definit (Siegel-Oberhalbebene H_g).
Reduktion auf den Siegel-Fundamentalbereich via Sp(2g,ℤ).
10c — Vollständige Uniformisierung
Für g ≥ 2: Einbettung als H²/Γ mit Γ ⊂ PSL(2,ℝ) Fuchssche Gruppe.
Erfordert 10a + 10b + stabilen Cut-Graph für g ≥ 2 (Phase 9c).
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 |
| Java-Originalbibliothek | github.com/varylab/conformallab |
| Website | sechel.de |
| 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).