From 95d48c434a97e3d7e51ddfef9d6705145970a387 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Sun, 17 May 2026 21:40:05 +0200 Subject: [PATCH] chore: .gitignore + vergessene Doc-Dateien nachgetragen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .gitignore: build-Verzeichnisse, .DS_Store, .claude/, CMake-Artefakte Doc-Dateien die beim Restructure-Commit fehlten: doc/api/headers.md — alle 24 Public-Header mit Beschreibung doc/api/tests.md — 26 Suiten, 158 Tests, Einzelzahlen doc/architecture/design-decisions.md — Architekturentscheidungen + Begründung doc/architecture/project-structure.md — Verzeichnisbaum + Build-Targets README.md: Links zu den vier neuen Doc-Dateien ergänzt Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 29 ++++++ README.md | 4 + doc/api/headers.md | 74 +++++++++++++++ doc/api/tests.md | 80 +++++++++++++++++ doc/architecture/design-decisions.md | 124 ++++++++++++++++++++++++++ doc/architecture/project-structure.md | 115 ++++++++++++++++++++++++ 6 files changed, 426 insertions(+) create mode 100644 .gitignore create mode 100644 doc/api/headers.md create mode 100644 doc/api/tests.md create mode 100644 doc/architecture/design-decisions.md create mode 100644 doc/architecture/project-structure.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed6e921 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Build directories +build/ +build-*/ +build_*/ +code/build*/ + +# CMake +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +CTestTestfile.cmake + +# Test output +*.xml +Testing/ + +# IDE +.idea/ +.vscode/ +*.user +*.suo + +# Claude Code worktrees +.claude/ diff --git a/README.md b/README.md index 099fb8d..eb893b5 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,14 @@ Layout2D layout = euclidean_layout(mesh, res.x, maps); |---|---| | **Getting started** — build modes, single-test invocation, CLI, Docker | [doc/getting-started.md](doc/getting-started.md) | | **Pipeline API** — all three geometries, holonomy, serialisation | [doc/api/pipeline.md](doc/api/pipeline.md) | +| **Public headers** — all 24 headers with descriptions | [doc/api/headers.md](doc/api/headers.md) | +| **Test suites** — 26 suites, 158 tests, individual counts | [doc/api/tests.md](doc/api/tests.md) | | **Extending** — new functionals, geometry modes, porting from Java | [doc/api/extending.md](doc/api/extending.md) | | **Processing unit contracts** — preconditions / provides table | [doc/api/contracts.md](doc/api/contracts.md) | | **CGAL package design** — Phase 8 target, YAML pipeline | [doc/api/cgal-package.md](doc/api/cgal-package.md) | | **Architecture & pipeline diagram** | [doc/architecture/overall_pipeline.md](doc/architecture/overall_pipeline.md) | +| **Design decisions** — key architectural choices + rationale | [doc/architecture/design-decisions.md](doc/architecture/design-decisions.md) | +| **Project structure** — directory tree + build targets | [doc/architecture/project-structure.md](doc/architecture/project-structure.md) | | **Geometry modes** — Euclidean / Spherical / HyperIdeal comparison | [doc/math/geometry-modes.md](doc/math/geometry-modes.md) | | **References** — all papers by module | [doc/math/references.md](doc/math/references.md) | | **Roadmap** — Phases 1–10 | [doc/roadmap/phases.md](doc/roadmap/phases.md) | diff --git a/doc/api/headers.md b/doc/api/headers.md new file mode 100644 index 0000000..cf02b63 --- /dev/null +++ b/doc/api/headers.md @@ -0,0 +1,74 @@ +# Public Headers (`code/include/`) + +All algorithms are header-only. Include the headers you need directly — +there is no compiled library to link against (only GTest for tests and +CGAL/Eigen for the CGAL-dependent headers). + +## Core mesh type + +| Header | Description | +|---|---| +| `conformal_mesh.hpp` | `ConformalMesh` = `CGAL::Surface_mesh`. Property-map naming convention. Index type aliases. `GeometryType` enum. | +| `constants.hpp` | `conformallab::PI`, `TWO_PI` | +| `mesh_builder.hpp` | `make_triangle()` / `make_tetrahedron()` / `make_quad_strip()` / `make_fan()` / `make_open_cylinder()` — test mesh factories | +| `mesh_io.hpp` | `load_mesh()` / `save_mesh()` via `CGAL::IO` (OFF / OBJ / PLY) | +| `mesh_utils.hpp` | `cgal_to_eigen()` — convert `ConformalMesh` vertex positions to `Eigen::MatrixXd` | + +## Special functions + +| Header | Description | +|---|---| +| `clausen.hpp` | `clausen_cl2(θ)` (Clausen Cl₂), `lobachevsky(θ)` (Л), `im_li2(θ)` (ImLi₂ = imaginary part of dilogarithm) | + +## HyperIdeal geometry (H²) + +| Header | Description | +|---|---| +| `hyper_ideal_geometry.hpp` | `ζ₁₃`, `ζ₁₄`, `ζ₁₅` (Springborn 2020), `l_from_zeta()`, `alpha_ij()`, `beta_i()`, `sigma_i()`, `sigma_ij()` | +| `hyper_ideal_utility.hpp` | Tetrahedron volumes (Meyerhoff formula, Kolpakov–Mednykh) | +| `hyper_ideal_visualization_utility.hpp` | Poincaré disk projection, circumcircle helpers, Lorentz boost | +| `hyper_ideal_functional.hpp` | `HyperIdealMaps`, `setup_hyper_ideal_maps()`, `compute_hyper_ideal_lambda0_from_mesh()`, `assign_all_dof_indices()`, `hyper_ideal_gradient()`, `hyper_ideal_energy()` | +| `hyper_ideal_hessian.hpp` | `hyper_ideal_hessian()` — symmetric FD Hessian (Phase 9b: analytic) | + +## Spherical geometry (S²) + +| Header | Description | +|---|---| +| `spherical_geometry.hpp` | Spherical arc-length, half-angle formula, spherical law of cosines | +| `spherical_functional.hpp` | `SphericalMaps`, `setup_spherical_maps()`, `compute_spherical_lambda0_from_mesh()`, `spherical_gradient()`, `spherical_energy()` | +| `spherical_hessian.hpp` | `spherical_hessian()` — analytic Hessian via ∂α/∂u from law of cosines | + +## Euclidean geometry (ℝ²) + +| Header | Description | +|---|---| +| `euclidean_geometry.hpp` | Euclidean corner angle (t-value / atan2), edge lengths from DOF vector | +| `euclidean_functional.hpp` | `EuclideanMaps`, `setup_euclidean_maps()`, `compute_euclidean_lambda0_from_mesh()`, `euclidean_gradient()`, `euclidean_energy()` | +| `euclidean_hessian.hpp` | `euclidean_hessian()` — cotangent Laplacian (Pinkall–Polthier 1993) | + +## Solver + +| Header | Description | +|---|---| +| `newton_solver.hpp` | `newton_euclidean()`, `newton_spherical()`, `newton_hyper_ideal()`, `solve_linear_system()` (SimplicialLDLT + SparseQR fallback), `NewtonResult` struct | + +## Preprocessing + +| Header | Description | +|---|---| +| `gauss_bonnet.hpp` | `euler_characteristic()`, `genus()`, `gauss_bonnet_sum()`, `gauss_bonnet_rhs()`, `gauss_bonnet_deficit()`, `check_gauss_bonnet()`, `enforce_gauss_bonnet()` | + +## Layout and holonomy + +| Header | Description | +|---|---| +| `cut_graph.hpp` | `CutGraph` struct, `compute_cut_graph()` — tree-cotree algorithm (Erickson–Whittlesey 2005), produces 2g seam edges | +| `layout.hpp` | `euclidean_layout()`, `spherical_layout()`, `hyper_ideal_layout()`, `normalise_{euclidean,hyperbolic,spherical}()`. Structs: `Layout2D`, `Layout3D`, `HolonomyData`. `MobiusMap` (T(z)=(az+b)/(cz+d), `from_three`, `compose`, `inverse`, `apply`). Priority-BFS, `halfedge_uv`. | + +## Post-processing + +| Header | Description | +|---|---| +| `period_matrix.hpp` | `PeriodData`, `compute_period_matrix()`, `reduce_to_fundamental_domain()`, `is_in_fundamental_domain()` — period ratio τ = ω₂/ω₁ ∈ ℍ, SL(2,ℤ) reduction | +| `fundamental_domain.hpp` | `FundamentalDomain`, `compute_fundamental_domain()` (genus 1: CCW parallelogram; genus > 1: empty, TODO Phase 9c), `tiling_copy()`, `tiling_neighbourhood()` | +| `serialization.hpp` | `save_result_json()`, `load_result_json()`, `save_result_xml()`, `load_result_xml()`, `save_layout_off()` | diff --git a/doc/api/tests.md b/doc/api/tests.md new file mode 100644 index 0000000..c914a9c --- /dev/null +++ b/doc/api/tests.md @@ -0,0 +1,80 @@ +# Test Suites + +## `conformallab_tests` — always built (no CGAL) + +Pure-math tests, only Eigen required. Covers Java utilities ported in Phase 1–2. + +| File | What it tests | +|---|---| +| `test_clausen.cpp` | Clausen Cl₂, Lobachevsky Л, ImLi₂ — values at known points | +| `test_hyper_ideal_utility.cpp` | Tetrahedron volumes (Meyerhoff / Kolpakov–Mednykh) | +| `test_matrix_utility.cpp` | Matrix helpers | +| `test_surface_curve_utility.cpp` | Surface curve utilities | +| `test_discrete_elliptic_utility.cpp` | Discrete elliptic functions | +| `test_p2_utility.cpp` | P2 projective utilities | +| `test_hyper_ideal_visualization_utility.cpp` | Poincaré disk projection, circumcircle | + +**Total: 36 tests, 0 skipped.** + +--- + +## `conformallab_cgal_tests` — built with `-DWITH_CGAL_TESTS=ON` or `-DWITH_CGAL=ON` + +All tests have CTest prefix `cgal.` (set via `TEST_PREFIX "cgal."` in CMakeLists). + +| Suite | File | Tests | What is verified | +|---|---|---:|---| +| `ConformalMeshTopology` | `test_conformal_mesh.cpp` | 4 | Euler characteristic, vertex/edge/face counts | +| `ConformalMeshTraversal` | `test_conformal_mesh.cpp` | 4 | Halfedge iteration, valence, opposite | +| `ConformalMeshProperties` | `test_conformal_mesh.cpp` | 5 | Property maps (λ, θ, idx, α, geometry type) | +| `ConformalMeshValidity` | `test_conformal_mesh.cpp` | 1 | CGAL validity for all factory meshes | +| `HyperIdealFunctional` | `test_hyper_ideal_functional.cpp` | 7 | FD gradient checks + Hessian symmetry | +| `SphericalFunctional` | `test_spherical_functional.cpp` | 12 | Angle formula + gradient + gauge-fix *(1 skipped)* | +| `EuclideanFunctional` | `test_euclidean_functional.cpp` | 11 | Angle formula + gradient *(1 skipped)* | +| `EuclideanHessian` | `test_euclidean_hessian.cpp` | 9 | Cotangent Laplacian structure, FD agreement, PSD, null space | +| `SphericalHessian` | `test_spherical_hessian.cpp` | 8 | Derivative correctness, NSD at equilibrium | +| `NewtonSolver` | `test_newton_solver.cpp` | 11 | Convergence: Euclidean ×3, Spherical ×4, HyperIdeal ×4 | +| `SparseQRFallback` | `test_newton_solver.cpp` | 3 | Full-rank LDLT · singular matrix → QR · closed mesh gauge mode | +| `MeshIO` | `test_mesh_io.cpp` | 9 | OFF/OBJ round-trips, error handling | +| `Pipeline` | `test_pipeline.cpp` | 5 | End-to-end: build → setup → solve → export → reload | +| `Layout` | `test_layout.cpp` | 8 | Edge-length preservation (Eucl./Spher.), Poincaré disk layout | +| `Serialization` | `test_layout.cpp` | 2 | JSON and XML round-trips (DOF vector + layout UVs) | +| `GaussBonnet` | `test_phase6.cpp` | 8 | χ, genus, sum/RHS, deficit, check, enforce | +| `CutGraph` | `test_phase6.cpp` | 6 | Tree-cotree, open/closed meshes, flag–index consistency | +| `HyperbolicTrilateration` | `test_phase6.cpp` | 4 | Möbius + law of cosines: exact distances, disk interior, off-origin | +| `Normalisation` | `test_phase6.cpp` | 4 | Euclidean centroid, length ratios, Möbius centring | +| `MobiusMap` | `test_phase7.cpp` | 8 | Identity, inverse, compose, `from_three`, `apply(Vector2d)` | +| `BestRootFace` | `test_phase7.cpp` | 2 | Valid root face selection, interior bonus | +| `HalfedgeUV` | `test_phase7.cpp` | 4 | Size = #halfedges, seam consistency, boundary halfedges = 0 | +| `PriorityBFS` | `test_phase7.cpp` | 3 | Success, no seam on open meshes, all vertices placed | +| `NormaliseEuclidean` | `test_phase7.cpp` | 2 | UV centroid = 0, halfedge_uv centroid = 0 | +| `PeriodMatrix` | `test_phase7.cpp` | 7 | τ ∈ ℍ, SL(2,ℤ) reduction, exception outside ℍ | +| `FundamentalDomain` | `test_phase7.cpp` | 7 | Genus-1 parallelogram CCW, generators, g > 1 empty | +| `TilingCopy/Neighbourhood` | `test_phase7.cpp` | 4 | Translation correct, tile count | +| `GeometryUtils` | `test_geometry_utils.cpp` | 6 | Java CuttingUtility, UnwrapUtility, ConvergenceUtility, HomologyTest ports (Tests 1–6); Test 7 GTEST_SKIP stub | + +**Total: 158 tests, 2 intentional skips.** + +The 2 skips are: +- `SphericalFunctional` — analytic gauge-fix stub (Phase 9b) +- `GeometryUtils` Test 7 — genus-2 homology (Phase 9c) + +Both correspond to Java `@Ignore`-annotated tests in the original library. + +--- + +## Running tests + +```bash +# All CGAL tests +ctest --test-dir build -R "^cgal\." --output-on-failure + +# One suite +./build/conformallab_cgal_tests --gtest_filter="PeriodMatrix*" + +# One specific test +./build/conformallab_cgal_tests --gtest_filter="PeriodMatrix.TauInUpperHalfPlane" + +# Verbose output with timing +./build/conformallab_cgal_tests --gtest_filter="NewtonSolver*" --gtest_print_time=1 +``` diff --git a/doc/architecture/design-decisions.md b/doc/architecture/design-decisions.md new file mode 100644 index 0000000..9e40bb2 --- /dev/null +++ b/doc/architecture/design-decisions.md @@ -0,0 +1,124 @@ +# Key Design Decisions + +Rationale for the architectural choices that distinguish conformallab++ from the +Java original and from generic geometry-processing frameworks. + +--- + +## CGAL `Surface_mesh` as the halfedge data structure + +The Java library uses `CoHDS` — a custom intrusive halfedge data structure with +`CoVertex`, `CoEdge`, `CoFace` types that carry domain-specific data directly as fields. + +conformallab++ replaces this with `CGAL::Surface_mesh` and attaches data via +**named property maps**: + +```cpp +// Java: vertex.getLambda() → C++: maps.lambda0[v] +// Java: edge.getAlpha() → C++: maps.e_alpha[e] +// Java: vertex.getSolverIndex() → C++: maps.v_idx[v] + +auto [lambda0, ok] = mesh.add_property_map("e:lambda0", 0.0); +lambda0[e] = 1.234; +``` + +This decouples the mesh topology from the algorithm data, makes it straightforward +to attach multiple independent data sets to the same mesh, and will enable the Phase 8 +traits-class design to work with any CGAL-conforming mesh type. + +--- + +## DOF vector convention + +All three functionals use the same indexing scheme: a flat `std::vector x` +indexed by `v_idx[v]` (vertices) and `e_idx[e]` (edges, HyperIdeal only). +Index value `-1` means "pinned" — the DOF is fixed at zero and excluded from the +Newton system. + +``` +x[maps.v_idx[v]] = uᵥ (conformal scale factor, Euclidean/Spherical) +x[maps.e_idx[e]] = λₑ (edge log-length variable, HyperIdeal only) +-1 pinned — u_v = 0 / λ_e = 0 +``` + +This is consistent across all three geometry modes, enabling the same Newton solver +and linear system infrastructure to serve all three without branching. + +--- + +## Priority-BFS layout + +A naive BFS layout places faces in arbitrary order; trilateration errors accumulate +along the BFS frontier. conformallab++ uses a **priority min-heap on BFS depth**: + +``` +depth(face) = max(depth[v_src], depth[v_tgt]) + 1 for each new face +``` + +Faces with smaller depth (closer to the root) are placed first. This means each +face's trilateration uses the two most accurately-placed adjacent vertices, minimising +error propagation across the mesh. + +Root face selection: largest 3-D area face, with an additional 1.5× bonus for +interior faces over boundary faces. This heuristic places the root where metric +distortion is lowest. + +--- + +## `halfedge_uv` semantics + +`layout.uv[v.idx()]` gives the *primary* UV coordinate of vertex `v` — the position +from the shallowest BFS visit. At seam edges this is insufficient for GPU rendering: +two faces sharing a seam vertex need *different* UV values for that vertex. + +`layout.halfedge_uv[h.idx()]` stores the UV of `source(h)` **as seen from `face(h)`**: + +``` +halfedge h → face(h) → source(h) has UV = halfedge_uv[h.idx()] +opposite(h) → face(h') → source(h) has UV = halfedge_uv[opposite(h).idx()] + (different value at a seam) +``` + +At seam halfedges the two opposite halfedges carry different UV values — each face +gets its own copy of the seam vertex. This enables a proper GPU texture atlas +without vertex duplication in the index buffer. + +--- + +## Spherical Hessian sign convention + +The spherical energy functional is **concave** (negative semidefinite Hessian). +Standard Newton would require solving `H·Δx = −G` with NSD `H`, which Cholesky +cannot handle. + +`newton_spherical()` solves `(−H)·Δx = G` instead — algebraically identical, +but `−H` is PSD and `SimplicialLDLT` works correctly. This sign flip is handled +transparently inside `newton_spherical()`; callers need not be aware of it. + +The gradient sign in spherical mode is also flipped vs. Euclidean: +- Euclidean: `G_v = actual_sum − Θᵥ` +- Spherical: `G_v = Θᵥ − actual_sum` + +Both conventions drive the same equilibrium condition `G = 0`. + +--- + +## HyperIdeal Hessian via finite differences + +The analytic HyperIdeal Hessian requires differentiating through the chain +`(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ` with four vertex-type combinations +per edge — substantial implementation complexity. + +conformallab++ uses a **symmetric finite-difference Hessian** instead: + +``` +H[i,j] = (G(x + ε·eⱼ)[i] − G(x − ε·eⱼ)[i]) / (2ε), ε = 1e-5 +``` + +Properties: +- O(ε²) accuracy — relative error ≈ 10⁻¹⁰ at ε = 10⁻⁵ +- PSD guaranteed by strict convexity of the HyperIdeal energy (Springborn 2020) +- Symmetrised automatically: `H = (H + Hᵀ) / 2` +- Cost: n extra gradient evaluations per Newton step (acceptable for < 500 DOFs) + +The analytic Hessian is deferred to Phase 9b. See [roadmap/java-parity.md](../roadmap/java-parity.md). diff --git a/doc/architecture/project-structure.md b/doc/architecture/project-structure.md new file mode 100644 index 0000000..ab893dd --- /dev/null +++ b/doc/architecture/project-structure.md @@ -0,0 +1,115 @@ +# Project Structure + +``` +ConformalLabpp/ +├── CLAUDE.md # Claude Code context file +├── README.md # Entry point — what/why, quick start, doc index +├── LICENSE # MIT +│ +├── code/ # All C++ source +│ ├── CMakeLists.txt # Root: three build modes (default / CGAL_TESTS / CGAL) +│ │ +│ ├── include/ # Header-only library — all algorithms here +│ │ ├── conformal_mesh.hpp # ConformalMesh = CGAL::Surface_mesh +│ │ ├── constants.hpp # conformallab::PI, TWO_PI +│ │ ├── clausen.hpp # Cl₂, Lobachevsky Л, ImLi₂ +│ │ ├── hyper_ideal_geometry.hpp # ζ₁₃/₁₄/₁₅, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ +│ │ ├── hyper_ideal_utility.hpp # Tetrahedron volumes (Meyerhoff / Kolpakov–Mednykh) +│ │ ├── hyper_ideal_visualization_utility.hpp # Poincaré disk projection, circumcircle helpers +│ │ ├── hyper_ideal_functional.hpp # HyperIdeal energy + gradient on ConformalMesh +│ │ ├── hyper_ideal_hessian.hpp # HyperIdeal Hessian (symmetric FD, Phase 9b: analytic) +│ │ ├── spherical_geometry.hpp # Spherical arc-length, half-angle formula +│ │ ├── spherical_functional.hpp # Spherical energy + gradient + gauge-fix +│ │ ├── spherical_hessian.hpp # Spherical Hessian (∂α/∂u via law of cosines) +│ │ ├── euclidean_geometry.hpp # Euclidean corner angle (t-value / atan2) +│ │ ├── euclidean_functional.hpp # Euclidean energy + gradient +│ │ ├── euclidean_hessian.hpp # Cotangent Laplacian Hessian (Pinkall–Polthier) +│ │ ├── newton_solver.hpp # newton_{euclidean,spherical,hyper_ideal} + solve_linear_system +│ │ ├── gauss_bonnet.hpp # euler_characteristic, genus, check/enforce_gauss_bonnet +│ │ ├── cut_graph.hpp # CutGraph + compute_cut_graph (tree-cotree) +│ │ ├── layout.hpp # Priority-BFS layout, MobiusMap, halfedge_uv, HolonomyData +│ │ ├── mesh_builder.hpp # make_triangle / make_tetrahedron / make_quad_strip / make_fan +│ │ ├── mesh_io.hpp # load_mesh / save_mesh (OFF/OBJ/PLY via CGAL::IO) +│ │ ├── mesh_utils.hpp # CGAL → Eigen conversion (cgal_to_eigen) +│ │ ├── serialization.hpp # save/load_result_json + save/load_result_xml +│ │ ├── period_matrix.hpp # PeriodData, compute_period_matrix, SL(2,ℤ) reduction +│ │ └── fundamental_domain.hpp # FundamentalDomain, tiling_copy, tiling_neighbourhood +│ │ +│ ├── src/ +│ │ ├── apps/v0/conformallab_cli.cpp # CLI app (Phase 5): load → solve → layout → export +│ │ └── viewer/simple_viewer.cpp # libigl/GLFW viewer wrapper +│ │ +│ ├── examples/ # Standalone example programs (require WITH_CGAL=ON) +│ │ ├── example_euclidean.cpp # Euclidean pipeline end-to-end +│ │ ├── example_hyper_ideal.cpp # HyperIdeal pipeline end-to-end +│ │ ├── example_layout.cpp # Full pipeline: solve → layout → OFF/JSON/XML + round-trip +│ │ └── example_viewer.cpp # Interactive libigl viewer +│ │ +│ ├── tests/ +│ │ ├── CMakeLists.txt +│ │ ├── test_clausen.cpp +│ │ ├── test_hyper_ideal_utility.cpp +│ │ ├── test_matrix_utility.cpp +│ │ ├── test_surface_curve_utility.cpp +│ │ ├── test_discrete_elliptic_utility.cpp +│ │ ├── test_p2_utility.cpp +│ │ ├── test_hyper_ideal_visualization_utility.cpp +│ │ └── cgal/ # CGAL test suite (WITH_CGAL_TESTS or WITH_CGAL) +│ │ ├── test_conformal_mesh.cpp +│ │ ├── test_hyper_ideal_functional.cpp +│ │ ├── test_spherical_functional.cpp +│ │ ├── test_euclidean_functional.cpp +│ │ ├── test_euclidean_hessian.cpp +│ │ ├── test_spherical_hessian.cpp +│ │ ├── test_newton_solver.cpp +│ │ ├── test_mesh_io.cpp +│ │ ├── test_pipeline.cpp +│ │ ├── test_layout.cpp +│ │ ├── test_phase6.cpp +│ │ ├── test_phase7.cpp +│ │ └── test_geometry_utils.cpp +│ │ +│ └── deps/ # All dependencies as bundled tarballs +│ ├── tarballs/ +│ │ ├── eigen-3.4.0.tar.gz +│ │ ├── CGAL-6.1.1.tar.xz +│ │ ├── libigl-2.6.0.tar.gz +│ │ ├── libigl-glad.tar.gz +│ │ └── glfw-3.4.tar.gz +│ └── single_includes/ # CLI11.hpp, json.hpp (header-only) +│ +├── doc/ +│ ├── getting-started.md +│ ├── contributing.md +│ ├── api/ +│ │ ├── pipeline.md # Full pipeline API with code examples +│ │ ├── extending.md # New functionals, geometry modes, Java porting +│ │ ├── contracts.md # Processing unit preconditions/provides table +│ │ └── cgal-package.md # Phase 8 CGAL package design (TODO) +│ ├── architecture/ +│ │ ├── overall_pipeline.md # Mermaid diagram + stage descriptions +│ │ ├── design-decisions.md # Key architectural choices + rationale +│ │ └── project-structure.md # This file +│ ├── math/ +│ │ ├── geometry-modes.md # Euclidean / Spherical / HyperIdeal comparison +│ │ └── references.md # All papers by module +│ └── roadmap/ +│ ├── phases.md # Phases 1–10 with porting/research boundary +│ └── java-parity.md # Java vs C++ feature parity table +│ +└── .gitea/ + ├── docker/Dockerfile.ci-cpp # Ubuntu 22.04 ARM64 CI image + └── workflows/cpp-tests.yml # Two-job CI pipeline +``` + +## Build targets + +| Target | Mode | Description | +|---|---|---| +| `conformallab_tests` | default | 36 non-CGAL pure-math tests | +| `conformallab_cgal_tests` | `WITH_CGAL_TESTS` or `WITH_CGAL` | 158 CGAL tests | +| `conformallab_core` | `WITH_CGAL` | CLI application | +| `example_euclidean` | `WITH_CGAL` | Euclidean example program | +| `example_hyper_ideal` | `WITH_CGAL` | HyperIdeal example program | +| `example_layout` | `WITH_CGAL` | Full pipeline example | +| `example_viewer` | `WITH_CGAL` | Interactive viewer |