Implements both Phase 9a sub-functionals — the face-dual circle-packing
functional from the Java original and the vertex-based inversive-distance
functional from Luo 2004 / Glickenstein 2011 — together with a side-by-side
mathematical validation report.
CGAL test count: 194 → 205 (+11 from 9a.2, +10 from 9a.1, was already
+1 from 9a.1's setup defaults regression).
Phase 9a.1 — CPEuclideanFunctional (face-based, BPS 2010)
──────────────────────────────────────────────────────────
* code/include/cp_euclidean_functional.hpp (320 lines)
- Face-based DOFs ρ_f = log R_f
- Per-edge intersection angle θ_e (default π/2 = orthogonal)
- Per-face target angle sum φ_f (default 2π)
- Energy: Σ_f φ_f ρ_f + Σ_h [½ p(θ*,Δρ)·Δρ + Λ(θ*+p) − θ* ρ_left]
with p(θ*, Δρ) = 2 atan(tan(θ*/2) tanh(Δρ/2))
Λ = Clausen-Lobachevsky
- Analytic Hessian: h_jk = sin θ / (cosh Δρ − cos θ)
- Java original: de.varylab.discreteconformal.functional.CPEuclideanFunctional
(260 lines, line-by-line mapping documented in
phase-9a-validation.md §1)
* code/tests/cgal/test_cp_euclidean_functional.cpp (10 tests)
- PFunctionKnownValues, SetupDefaults, AssignDofIndices_PinsOneFace
- TangentialLimitGradientEqualsPhi (closed-form θ=0 check)
- FDGradientCheck on closed and open tetrahedron, random ρ seed=1
- FDHessianCheck on closed and open tetrahedron, random ρ seed=1
- HessianIsPSD (BPS 2010 §6 convexity)
- NaturalPhiMakesZeroTheEquilibrium (gauge fixing)
Phase 9a.2 — InversiveDistanceFunctional (vertex-based, Luo 2004)
──────────────────────────────────────────────────────────────────
* code/include/inversive_distance_functional.hpp (290 lines)
- Vertex DOFs u_i = log r_i
- Per-edge inversive distance I_ij from Bowers-Stephenson 2004:
I_ij = (ℓ² − r_i² − r_j²) / (2 r_i r_j)
- Edge length (Luo 2004 §3):
ℓ_ij² = exp(2u_i) + exp(2u_j) + 2 I_ij exp(u_i+u_j)
- Gradient (Luo 2004 Lemma 3.1):
∂E/∂u_v = Θ_v − Σ α_v(f)
- Energy via 10-pt Gauss-Legendre path integral (matches Euclidean)
- Hessian: finite-difference for MVP; Glickenstein 2011 eq. 4.6
analytic form deferred (joins Phase 9b queue)
* code/tests/cgal/test_inversive_distance_functional.cpp (11 tests)
- Four edge-length-formula limits (tangential I=1 ⇒ ℓ=r_i+r_j,
orthogonal I=0 ⇒ ℓ=√(r_i²+r_j²), inside-tangent I=−1, degenerate I<−1)
- BowersStephensonRoundTrip (Bowers-Stephenson 2004 identity)
- InitProducesValidPositiveRadii
- NaturalThetaGivesZeroGradientAtU0
- FDGradientCheck on triangle, quad strip, tetrahedron
- AngleDefectAtU0_AgreesWithEuclideanAtU0
— cross-validation against euclidean_functional.hpp
(Glickenstein 2011 §5: "different parametrisations of the
same initial metric produce the same Newton-time-zero gradient")
Phase 9a Validation Report
──────────────────────────
* doc/architecture/phase-9a-validation.md (350 lines)
- Line-by-line mapping CPEuclideanFunctional.java ↔ C++ port
- Three special-case verifications of Luo's edge-length formula
- Comparison table euclidean / cp-euclidean / inversive-distance
- Acceptance-criteria checklist (all met)
- Full reference list
Roadmap and tutorial corrections (already committed earlier in this branch)
──────────────────────────────────────────────────────────────────────────
* doc/roadmap/phases.md — Phase 9a split into 9a.1 + 9a.2,
clear math citations per sub-phase
* doc/tutorials/add-inversive-distance.md — corrects the prior claim
that InversiveDistanceFunctional.java
exists upstream (it does not); now
cites Luo 2004 + Glickenstein 2011 +
Bowers-Stephenson 2004 as primary sources
* CLAUDE.md — adds phase-9a-validation.md to doc map
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
conformallab++
C++17 reimplementation of ConformalLab — Stefan Sechelmann's Java research library for discrete conformal geometry (TU Berlin). The long-term goal is a CGAL package for discrete conformal maps.
Algorithmic foundation:
Stefan Sechelmann — Variational Methods for Discrete Surface Parameterization: Applications and Implementation, TU Berlin 2016. DOI: 10.14279/depositonce-5415 · CC BY-SA 4.0 · Java original · sechel.de
Status: Phase 7 complete. Newton solver for all three geometries (Euclidean / Spherical / HyperIdeal), priority-BFS layout in ℝ²/S²/Poincaré disk, Gauss–Bonnet, tree-cotree cut graph, Möbius holonomy, period matrix (genus 1), fundamental domain, halfedge_uv texture atlas, JSON/XML serialisation, CLI app. 176 CGAL tests + 36 non-CGAL tests.
Quick start
git clone https://codeberg.org/TMoussa/ConformalLabpp && cd ConformalLabpp
# Fast tests — no system dependencies
cmake -S code -B build && cmake --build build --target conformallab_tests -j$(nproc)
ctest --test-dir build --output-on-failure
# CGAL tests headless (apt install libboost-dev / brew install boost)
cmake -S code -B build -DWITH_CGAL_TESTS=ON
cmake --build build --target conformallab_cgal_tests -j$(nproc)
ctest --test-dir build -R "^cgal\." --output-on-failure
# Full build with CLI + viewer (requires Wayland/X11 dev headers)
cmake -S code -B build -DWITH_CGAL=ON && cmake --build build -j$(nproc)
./bin/conformallab_core -i input.off -g euclidean -o layout.off -j result.json
# API documentation (requires doxygen: brew/apt install doxygen)
cmake --build build --target doc
open doc/doxygen/html/index.html
Minimal usage
#include "conformal_mesh.hpp"
#include "mesh_io.hpp"
#include "euclidean_functional.hpp"
#include "gauss_bonnet.hpp"
#include "newton_solver.hpp"
#include "layout.hpp"
using namespace conformallab;
ConformalMesh mesh = load_mesh("input.off");
EuclideanMaps maps = setup_euclidean_maps(mesh);
compute_euclidean_lambda0_from_mesh(mesh, maps);
// Assign DOFs — pin first vertex (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++;
// Natural equilibrium target: x* = 0 by construction
std::vector<double> x0(idx, 0.0);
auto G0 = euclidean_gradient(mesh, x0, maps);
for (auto v : mesh.vertices())
if (maps.v_idx[v] >= 0) maps.theta_v[v] -= G0[maps.v_idx[v]];
check_gauss_bonnet(mesh, maps);
NewtonResult res = newton_euclidean(mesh, x0, maps);
Layout2D layout = euclidean_layout(mesh, res.x, maps);
Documentation
| Getting started — build modes, single-test invocation, CLI, Docker | doc/getting-started.md |
| Pipeline API — all three geometries, holonomy, serialisation | doc/api/pipeline.md |
| Public headers — all 24 headers with descriptions | doc/api/headers.md |
| Test suites — 35 suites, 176+36 tests, individual counts | doc/api/tests.md |
| Extending — new functionals, geometry modes, porting from Java | doc/api/extending.md |
| Processing unit contracts — preconditions / provides table | doc/api/contracts.md |
| CGAL package design — Phase 8 target, YAML pipeline | doc/api/cgal-package.md |
| Architecture & pipeline diagram | doc/architecture/overall_pipeline.md |
| geometry-central comparison — shared core, demarcation, adoption candidates, scientific added value | doc/architecture/geometry-central-comparison.md |
| Design decisions — key architectural choices + rationale | doc/architecture/design-decisions.md |
| Project structure — directory tree + build targets | doc/architecture/project-structure.md |
| Discrete conformal theory — mathematical background for collaborators | doc/math/discrete-conformal-theory.md |
| Validation — known analytic results + how to verify them | doc/math/validation.md |
| Validation protocol — concrete commands with expected outputs | doc/math/validation-protocol.md |
| Tutorial: add a new functional — step-by-step Inversive-Distance port | doc/tutorials/add-inversive-distance.md |
| Declarative YAML pipeline — concept, token vocabulary, 5 examples | doc/concepts/declarative-pipeline.md |
| Geometry modes — Euclidean / Spherical / HyperIdeal comparison | doc/math/geometry-modes.md |
| References — all papers by module | doc/math/references.md |
| Software landscape — how conformallab++ relates to libigl, CGAL, geometry-central | doc/math/software-landscape.md |
| Novelty statement — unique features, target audience, what this is not | doc/math/novelty-statement.md |
| Complexity & scalability — O() analysis, measured timings on real meshes, HyperIdeal bottleneck | doc/math/complexity.md |
| Roadmap — Phases 1–10 | doc/roadmap/phases.md |
| Java parity table — what is ported, what is planned | doc/roadmap/java-parity.md |
| Contributing — language policy, test standards, release flow | doc/contributing.md |
| Claude Code context | CLAUDE.md |
Citing
If you use conformallab++ in your research, please cite it using the metadata
in CITATION.cff. GitHub and Codeberg show a "Cite this repository"
button that generates BibTeX and APA automatically.
The primary algorithmic source is:
Stefan Sechelmann — Variational Methods for Discrete Surface Parameterization: Applications and Implementation, TU Berlin 2016. DOI: 10.14279/depositonce-5415
Bugs & questions
- Bug reports / feature requests: Gitea Issues
- Code mirror (read-only): Codeberg
- Contact: Tarik Moussa · Tarik.moussa95@gmail.com
License
conformallab++ is released under the MIT License (see LICENSE).
Copyright © 2024–2026 Tarik Moussa.
The dissertation (Sechelmann 2016) is CC BY-SA 4.0.