# 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 3 vollständig abgeschlossen. Alle drei Kern-Geometrien (Hyper-Ideal, Sphärisch, Euklidisch) plus analytische Hessians (Kotangenten-Laplace) sind auf `ConformalMesh` portiert. **62 Tests, 3 skipped**. Nächster Schritt: Phase 4 (Newton-Solver) — siehe [Roadmap](#roadmap). --- ## Features | Area | Status | |------|--------| | Clausen / Lobachevsky / ImLi₂ functions | ✅ Phase 1 | | Hyper-ideal geometry (ζ, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ) | ✅ Phase 2 | | Hyper-ideal functional (energy + gradient, CGAL mesh) | ✅ Phase 3b | | Spherical functional (energy + gradient, CGAL mesh) | ✅ Phase 3c | | CGAL `Surface_mesh` infrastructure + mesh builders | ✅ Phase 3a | | Euclidean functional (energy + gradient, CGAL mesh) | ✅ Phase 3d | | Spherical gauge-fix (scale gauge for closed surfaces) | ✅ Phase 3e | | Euclidean Hessian (cotangent-Laplace operator) | ✅ Phase 3f | | Spherical Hessian (∂α/∂u from law of cosines) | ✅ Phase 3f | | Solvers (Newton, gradient flow) | 🔜 Phase 4 | | XML serialisation / mesh I/O | 🔜 Phase 5 | | Full CLI app | 🔜 Phase 5 | --- ## Build modes | Mode | CMake flag | What gets built | CI | |------|-----------|-----------------|-----| | **Tests only** (default) | *(none)* | `conformallab_tests` · Eigen + GTest | ✅ runs automatically | | **CGAL tests** | `-DWITH_CGAL=ON` | `conformallab_cgal_tests` · above + CGAL + system Boost | local only | | **Viewer** | `-DWITH_VIEWER=ON` | `viewer` library · libigl / GLFW / GLAD | local only | | **Full app** | `-DWITH_CGAL=ON` | `conformallab_core` CLI · all of the above | local only | External dependencies are bundled as tarballs in `code/deps/tarballs/` and extracted lazily at CMake configure time (GTest is fetched from GitHub via `FetchContent`). **Note on Boost:** `-DWITH_CGAL=ON` requires a system-installed Boost (header-only use by CGAL). The default `Tests only` mode needs no Boost. --- ## Prerequisites | Tool | Minimum version | |------|----------------| | C++ compiler (GCC or Clang) | C++17 | | CMake | 3.20 | | Boost headers | 1.70 *(only with `-DWITH_CGAL=ON`)* | --- ## Getting started ```bash git clone https://codeberg.org/TMoussa/ConformalLabpp cd ConformalLabpp ``` ### Tests only (CI default — no system deps needed) ```bash cmake -S code -B build cmake --build build --target conformallab_tests -j$(nproc) ctest --test-dir build --output-on-failure ``` ### CGAL mesh + functional tests (requires system Boost) ```bash cmake -S code -B build -DWITH_CGAL=ON cmake --build build --target conformallab_cgal_tests -j$(nproc) ctest --test-dir build -R "^cgal\." --output-on-failure ``` Expected output: **45 tests pass, 3 skipped** (the three `@Ignore` Hessian stubs, one per functional). ### Full CLI app (CGAL + viewer) ```bash cmake -S code -B build -DWITH_CGAL=ON cmake --build build -j$(nproc) ./code/bin/conformallab_core --input data/off/example.off --show ``` --- ## Public headers (`code/include/`) | Header | Description | |--------|-------------| | `clausen.hpp` | Clausen integral Cl₂, Lobachevsky Л, ImLi₂ | | `hyper_ideal_geometry.hpp` | Pure-math ζ functions, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ | | `hyper_ideal_utility.hpp` | Tetrahedron volume (Meyerhoff / Kolpakov–Mednykh) | | `hyper_ideal_functional.hpp` | Hyper-ideal energy + gradient on `ConformalMesh` | | `spherical_geometry.hpp` | Spherical arc length, half-angle angle formula | | `spherical_functional.hpp` | Spherical energy + gradient + gauge-fix on `ConformalMesh` | | `euclidean_geometry.hpp` | Euclidean corner-angle formula (t-value / atan2) | | `euclidean_functional.hpp` | Euclidean energy + gradient on `ConformalMesh` | | `conformal_mesh.hpp` | `ConformalMesh` = `CGAL::Surface_mesh`, index types, property-map helpers | | `mesh_builder.hpp` | Factory meshes: triangle, tetrahedron, quad strip, fan, spherical tetrahedron, octahedron face | | `discrete_elliptic_utility.hpp` | Discrete elliptic integrals | | `matrix_utility.hpp` | Small linear-algebra helpers | | `projective_math.hpp` | Projective geometry utilities | --- ## Project structure ``` code/ ├── include/ │ ├── conformal_mesh.hpp # CGAL mesh type + property-map helpers │ ├── mesh_builder.hpp # make_triangle / make_tetrahedron / … │ ├── hyper_ideal_geometry.hpp # ζ, lᵢⱼ, αᵢⱼ — pure math │ ├── hyper_ideal_functional.hpp # HyperIdealFunctional on ConformalMesh │ ├── spherical_geometry.hpp # spherical arc length + angles │ ├── spherical_functional.hpp # SphericalFunctional + gauge-fix on ConformalMesh │ ├── euclidean_geometry.hpp # Euclidean corner-angle formula (t-value) │ ├── euclidean_functional.hpp # EuclideanCyclicFunctional on ConformalMesh │ ├── clausen.hpp # Clausen / Lobachevsky / ImLi₂ │ └── hyper_ideal_utility.hpp # Tetrahedron volumes ├── src/ │ ├── apps/v0/ # conformallab_core CLI (requires WITH_CGAL) │ └── viewer/ # simple_viewer (requires WITH_VIEWER) ├── tests/ │ ├── CMakeLists.txt │ ├── *.cpp # conformallab_tests (no CGAL) │ └── cgal/ │ ├── CMakeLists.txt │ ├── test_conformal_mesh.cpp # 14 mesh infrastructure tests │ ├── test_hyper_ideal_functional.cpp # 6 hyper-ideal gradient checks │ ├── test_spherical_functional.cpp # 11 spherical gradient + gauge-fix checks │ └── test_euclidean_functional.cpp # 11 Euclidean gradient checks └── deps/ ├── tarballs/ # bundled dependency archives ├── eigen-3.4.0/ # header-only linear algebra (always extracted) ├── CGAL-6.1.1/ # header-only geometry (extracted with WITH_CGAL) ├── libigl-2.6.0/ # header-only viewer toolkit (extracted with WITH_VIEWER) ├── glfw-3.4/ # windowing (extracted with WITH_VIEWER) ├── libigl-glad/ # OpenGL loader (extracted with WITH_VIEWER) └── single_includes/ # CLI11, json.hpp ``` --- ## Test suites ### `conformallab_tests` (always built, runs in CI) Pure-math tests requiring only Eigen: - Clausen function, Lobachevsky function, ImLi₂ - Hyper-ideal geometry (ζ₁₃, ζ₁₄, ζ₁₅, lᵢⱼ, αᵢⱼ) - Tetrahedron volume formulas (Meyerhoff, Kolpakov–Mednykh) ### `conformallab_cgal_tests` (built with `-DWITH_CGAL=ON`) CGAL `Surface_mesh` tests (test prefix `cgal.`): | Suite | Tests | Description | |-------|-------|-------------| | `ConformalMeshTopology` | 4 | Euler characteristic, vertex/edge/face counts | | `ConformalMeshTraversal` | 4 | Halfedge iteration, valence, opposite-halfedge | | `ConformalMeshProperties` | 5 | Property maps: λ, θ, idx, α, geometry type | | `ConformalMeshValidity` | 1 | CGAL validity check for all factory meshes | | `HyperIdealFunctional` | 6 | Finite-difference gradient checks on triangle, tetrahedron, quad strip, fan | | `SphericalFunctional` | 11 | Angle formula + gradient checks on spherical meshes + 3 gauge-fix tests | | `EuclideanFunctional` | 11 | Angle formula + gradient checks on Euclidean meshes (triangle, quad strip, fan, tetrahedron) | --- ## Key design decisions **CGAL as CoHDS replacement.** `CGAL::Surface_mesh` replaces the Java `CoHDS` half-edge data structure. Vertex/edge/face/halfedge descriptors are `Vertex_index`, `Edge_index`, `Face_index`, `Halfedge_index` (typed integers, not raw handles). **Property maps.** `mesh.add_property_map("v:lambda", 0.0)` replaces the Java adapter/decorator pattern. Multiple maps can be attached to one mesh without subclassing. **Energy parameterisation.** Both functionals use a **DOF vector** `x` indexed by `v_idx[v]` / `e_idx[e]` (−1 = pinned). This matches the Java `FunctionalTest` gradient-check convention. **Spherical edge gradient.** For the spherical parameterisation where `Λᵢⱼ = λ°ᵢⱼ + uᵢ + uⱼ + λₑ` (additive edge DOF), the Schläfli identity gives `∂E/∂λₑ = (2α_opp − S_f)/2` per face (Euclidean limit: `S_f = π`, recovering the familiar `α_opp⁺ + α_opp⁻ − π`). --- ## CI Tests run automatically on push to `main`, `dev`, and `claude/**` branches via a self-hosted Gitea Actions runner (`eulernest`, ARM64 Raspberry Pi). The pipeline uses a minimal Docker image (`git.eulernest.eu/conformallab/ci-cpp:latest`) with cmake, g++, git, and Node.js 20 pre-installed. **Only `conformallab_tests` runs in CI** (no Boost/CGAL dependency in the CI image). The Dockerfile for the CI image lives in `.gitea/docker/Dockerfile.ci-cpp`. Build and push it once whenever the image needs updating: ```bash 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 3 ist vollständig abgeschlossen. Phase 4 (Newton-Solver) ist der nächste Schritt. Die Zeitangaben sind grobe Schätzungen. --- ``` Phase 3a CGAL Surface_mesh Infrastruktur ✅ abgeschlossen → conformal_mesh.hpp, mesh_builder.hpp → 14 Tests: Topologie, Traversal, Properties, Validity Phase 3b HyperIdealFunctional portieren ✅ abgeschlossen → hyper_ideal_functional.hpp: Energie + Gradient → 6 Tests (1 skipped): Gradient-Checks, FD-Tests Phase 3c SphericalFunctional portieren ✅ abgeschlossen → spherical_functional.hpp: Energie + Gradient → Tests: Winkelformel, Gradient-Checks Phase 3d EuclideanCyclicFunctional portieren ✅ abgeschlossen → euclidean_functional.hpp: Energie + Gradient auf ConformalMesh → Tests: Winkelformel, Gradient-Checks, NaN-Test, Fan, Mixed-Pinned Phase 3e Gauge-Fix für SphericalFunctional ✅ abgeschlossen → spherical_gauge_shift() + apply_spherical_gauge() in spherical_functional.hpp — Newton + Backtracking → Tests: ZerosSumGv, ApplyInPlace, AlreadyAtGauge Phase 3f Analytische Hessians ✅ abgeschlossen → euclidean_hessian.hpp: Kotangenten-Laplace (Pinkall–Polthier 1993) mit korrektem 1/2-Normierungsfaktor; 8 Tests → spherical_hessian.hpp: ∂α_i/∂u_j direkt aus sphärischem Cosinussatz abgeleitet + Chain-Rule mit ∂l/∂λ = tan(l/2); 8 Tests → Erkenntnis: Sphärische Energie ist konkav (H ist NSD), nicht konvex Phase 3g PI-Konstante konsolidieren ✅ abgeschlossen → constants.hpp mit conformallab::PI und TWO_PI → 5 Dateien bereinigt; PI_SPHER-Alias rückwärtskompatibel Phase 4a Minimaler Newton-Solver (1–2 Tage) → Eigen SimplicialLDLT (bereits Projektabhängigkeit) → Newton-Schritt: Δx = −H⁻¹·g mit Hessian aus 3f → Kein externer PETSc-Solver nötig für erste Tests → Konvergenzkriterium: ||g||∞ < tol Phase 4b CGAL::IO für Mesh-Import/Export (< 1 Tag) → CGAL::IO::read_OBJ / write_OBJ auf Surface_mesh: null Eigenentwicklung, sofort nutzbar → Ermöglicht Round-Trip-Tests gegen Java-Referenz-Meshes → Mittelfristig: CGAL::IO::read_OFF für .off-Dateien (ersetzt Java-XML-Serialisierung für Testzwecke) ``` --- ## License conformallab++ is released under the MIT License (see [LICENSE](LICENSE)).