feat(phase3c): port SphericalFunctional onto ConformalMesh; update README

New headers:
- spherical_geometry.hpp: spherical arc length l(λ) and half-angle formula
  for interior angles of a spherical triangle (SphericalFaceAngles struct)
- spherical_functional.hpp: SphericalMaps bundle, setup/assign DOF helpers,
  compute_lambda0_from_mesh(), gradient (Θ_v − Σα_v; Schläfli edge formula),
  energy via 10-point Gauss-Legendre path integral, gradient_check_spherical()

Updated:
- mesh_builder.hpp: add make_spherical_tetrahedron() (vertices on unit sphere)
  and make_octahedron_face() (single right-angled spherical triangle)
- tests/cgal/CMakeLists.txt: enable test_spherical_functional.cpp
- README.md: rewrite for CGAL-package goal, two test targets, all headers,
  updated project tree, Phase progress table, key design decisions

Tests (cgal.SphericalFunctional.*): 8 active + 1 skip
- OctaFaceAnglesAreRightAngles, SpherTetAngleSumExceedsPi
- GradientCheck_{OctaFaceVertex, SpherTetVertex, SpherTetAllDofs,
  SpherFan4Vertex, MixedPinnedVertices}
- AnglesFiniteAtKnownPoint
All 30 cgal.* tests pass (2 @Ignore skips).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-12 00:01:24 +02:00
parent 516ac89bd8
commit a4c2a89e7e
6 changed files with 851 additions and 33 deletions

155
README.md
View File

@@ -2,29 +2,42 @@
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.
> **Status:** early prototype stage. API, file formats, and CLI are subject to change.
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 complete. Core geometry (Clausen, hyper-ideal, spherical) and the CGAL mesh infrastructure are in place. Solvers and full CLI pipeline are coming next.
---
## Features
- Discrete conformal geometry utilities (Clausen function, hyper-ideal tetrahedra, surface curves)
- Mesh I/O and conversion using CGAL — optional, only needed for the CLI app
- Linear algebra routines with Eigen
- Interactive mesh viewer using libigl / GLFW — optional
- Lightweight CLI with CLI11 and JSON configuration
| 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 | 🔜 Phase 4 |
| Solvers (Newton, gradient flow) | 🔜 Phase 4 |
| XML serialisation / mesh I/O | 🔜 Phase 5 |
| Full CLI app | 🔜 Phase 5 |
---
## Build modes
The project uses three clearly separated CMake modes so you only pull in what you need.
| 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 |
| Mode | CMake flag | What gets built |
|------|-----------|-----------------|
| **Tests only** (default, used in CI) | *(none)* | `conformallab_tests` · deps: Eigen + GTest |
| **Viewer** | `-DWITH_VIEWER=ON` | `viewer` library · deps: libigl / GLFW / GLAD + Eigen |
| **Full app** | `-DWITH_CGAL=ON` | `conformallab_core` CLI + viewer · deps: CGAL + libigl / GLFW / GLAD + Eigen |
External dependencies are bundled as tarballs in `code/deps/tarballs/` and extracted lazily at CMake configure time (GTest is fetched from GitHub via `FetchContent`).
`-DWITH_CGAL=ON` automatically enables `WITH_VIEWER` because the CLI app uses the viewer library for mesh visualisation.
**Note on Boost:** `-DWITH_CGAL=ON` requires a system-installed Boost (header-only use by CGAL). The default `Tests only` mode needs no Boost.
External dependencies ship as tarballs in `code/deps/tarballs/` and are extracted lazily at CMake configure time — no internet access needed after cloning (GTest is the only exception: fetched from GitHub via FetchContent).
---
## Prerequisites
@@ -32,8 +45,9 @@ External dependencies ship as tarballs in `code/deps/tarballs/` and are extracte
|------|----------------|
| C++ compiler (GCC or Clang) | C++17 |
| CMake | 3.20 |
| Boost headers | 1.70 *(only with `-DWITH_CGAL=ON`)* |
No system-level libraries are required for the default tests-only build. CGAL and libigl are header-only and bundled in the repo.
---
## Getting started
@@ -42,7 +56,7 @@ git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
```
### Tests only (CI default)
### Tests only (CI default — no system deps needed)
```bash
cmake -S code -B build
@@ -50,6 +64,16 @@ 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: **30 tests pass, 2 skipped** (the two `@Ignore` Hessian stubs).
### Full CLI app (CGAL + viewer)
```bash
@@ -58,35 +82,102 @@ cmake --build build -j$(nproc)
./code/bin/conformallab_core --input data/off/example.off --show
```
### Viewer only (no CGAL)
---
```bash
cmake -S code -B build -DWITH_VIEWER=ON
cmake --build build --target viewer -j$(nproc)
```
## 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 / KolpakovMednykh) |
| `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 on `ConformalMesh` |
| `conformal_mesh.hpp` | `ConformalMesh` = `CGAL::Surface_mesh<Point3>`, 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/ # Public headers (Clausen, hyper-ideal, mesh utils, …)
├── 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 on ConformalMesh
│ ├── clausen.hpp # Clausen / Lobachevsky / ImLi₂
│ └── hyper_ideal_utility.hpp # Tetrahedron volumes
├── src/
│ ├── apps/v0/ # conformallab_core CLI app (requires WITH_CGAL)
│ └── viewer/ # simple_viewer (requires WITH_VIEWER)
├── tests/ # GTest unit tests (always built)
│ ├── 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 # 8 spherical 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)
├── 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, KolpakovMednykh)
### `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` | 8 | Angle formula correctness + gradient checks on spherical meshes |
---
## Key design decisions
**CGAL as CoHDS replacement.** `CGAL::Surface_mesh<Point3>` 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<Vertex_index, double>("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.
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:
@@ -99,6 +190,8 @@ docker buildx build \
.gitea/docker/
```
---
## License
conformallab++ is released under the MIT License (see [LICENSE](LICENSE)).