Commit Graph

28 Commits

Author SHA1 Message Date
Tarik Moussa
b7593e3f6d feat(phase5): Layout, CLI, JSON/XML serialisation — 95 tests
Phase 5 complete:

layout.hpp
  - euclidean_layout(): BFS unfolding in ℝ² using trilaterate_2d
  - spherical_layout(): BFS on S² using trilaterate_sph (spherical law of cosines)
  - hyper_ideal_layout(): BFS in Poincaré disk (tanh(d/2) Euclidean approx)
  - save_layout_off(): convenience OFF writer for 2-D and 3-D layouts

serialization.hpp
  - save/load_result_json(): nlohmann/json; stores DOF vector + uv/pos layout
  - save/load_result_xml(): hand-written writer/parser; same schema

conformallab_cli.cpp (rewritten)
  - CLI11 interface: -i/-o/-g/-j/-x/-s/-v
  - Dispatches to euclidean / spherical / hyper_ideal pipeline
  - Runs Newton, computes layout, saves OFF + JSON + XML

examples/example_layout.cpp
  - Full round-trip demo: solve → layout → JSON/XML → reload → verify

tests/cgal/test_layout.cpp (8 tests)
  - Euclidean_PreservesEdgeLengths, CorrectVertexCount, TriangleIsNonDegenerate
  - Spherical_PreservesArcLengths, PositionsOnUnitSphere
  - HyperIdeal_SuccessAndFinitePositions
  - Serialization.JSON_RoundTrip, XML_RoundTrip

All 95 CGAL tests pass (2 skipped — Hessian stubs unchanged).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 00:53:47 +02:00
Tarik Moussa
3f124eb071 feat(phase4): HyperIdeal Newton solver, SparseQR fallback, examples, docs
Phase 4 complete — 87 CGAL tests pass, 2 skipped.

Newton solver (phase4a):
- hyper_ideal_hessian.hpp: symmetric FD Hessian (O(ε²), PSD by convexity)
- newton_hyper_ideal(): Newton + backtracking for the HyperIdeal functional
- detail::solve_with_fallback(): optional bool* fallback_used parameter
- solve_linear_system(): public API exposing LDLT→SparseQR fallback

SparseQR fallback tests (SparseQRFallback.*):
- FullRankSystem_CorrectSolution: LDLT path, fallback_used=false
- SingularMatrix_FallbackActivated: zero-pivot → QR activated, fallback_used=true
- Euclidean_ClosedMeshNoPinConverges: gauge-mode null space handled via QR

HyperIdeal Newton tests (NewtonSolver.HyperIdeal_*):
- ConvergesTriangleAllVariable, ResultFieldsConsistent,
  ConvergesTetrahedron, SparseQRFallbackNoCrash
- Natural-target base point (b=1.0, a=0.5) — x=0 is degenerate in log-space

Pipeline tests (test_pipeline.cpp):
- End-to-end: all three geometries, mesh I/O round-trip, solve+export

Example programs (code/examples/):
- example_euclidean.cpp:   headless Euclidean pipeline
- example_hyper_ideal.cpp: headless HyperIdeal pipeline
- example_viewer.cpp:      interactive libigl viewer with jet colour map

README:
- Mathematical scope table: C++ vs Java original (18 rows)
- "For mathematicians" section: mental model, step-by-step new-functional
  guide, half-edge traversal snippets, recommended reading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 00:11:25 +02:00
Tarik Moussa
e70689d29f feat(phase4a+4b): Newton solver + CGAL mesh I/O
Phase 4a — newton_solver.hpp:
  - newton_euclidean(): SimplicialLDLT on H (PSD); solves H·Δx = −G
  - newton_spherical(): SimplicialLDLT on −H (NSD→PSD); solves (−H)·Δx = G
  - Backtracking line search (halving α up to 20×) for global convergence
  - NewtonResult struct: x, iterations, grad_inf_norm, converged
  - 7 tests: 4 spherical (convergence, few iters, large perturbation,
    field consistency) + 3 Euclidean (triangle pinned, quad pinned,
    mixed pinned — all with natural-theta equilibrium at x=0)

Phase 4b — mesh_io.hpp:
  - read_mesh() / write_mesh(): CGAL::IO::read/write_polygon_mesh wrappers
  - load_mesh() / save_mesh(): throwing convenience versions
  - Supports OFF, OBJ, PLY (format detected by file extension)
  - 6 tests: OFF round-trip (tet + quad), OBJ round-trip, missing-file throw,
    vertex-position preservation, save/load convenience wrappers

All 75 cgal tests pass (3 skipped as before).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-05-12 17:35:00 +02:00
Tarik Moussa
194effba97 feat(phase3f+3g): analytical Hessians + PI consolidation
Phase 3g — constants.hpp:
  - Introduce conformallab::PI and TWO_PI in a single constants.hpp
  - Remove scattered local PI/pi definitions from hyper_ideal_geometry.hpp,
    hyper_ideal_utility.hpp, euclidean_functional.hpp, mesh_builder.hpp,
    spherical_geometry.hpp (backward-compatible PI_SPHER alias kept)

Phase 3f — Euclidean Hessian (euclidean_hessian.hpp):
  - Cotangent-Laplace operator (Pinkall–Polthier 1993)
  - euclidean_cot_weights() helper + euclidean_hessian() + hessian_check_euclidean()
  - Correct Pinkall–Polthier 1/2 normalization factor
  - 8 tests: cot weights, symmetry, null-space (H·1=0), PSD, FD × 4 meshes

Phase 3f — Spherical Hessian (spherical_hessian.hpp):
  - Derives ∂α_i/∂u_j directly from the spherical law of cosines:
      ∂α1/∂l_opp  = sin(l_opp) / [sin(l_a)·sin(l_b)·sin(α1)]
      ∂α1/∂l_adj  = [cot(l_adj)·cos(α1) − cot(l_other)] / sin(α1)
    then chains with ∂l/∂λ = tan(l/2)
  - spherical_cot_weights() kept as a standalone helper (tested separately)
  - 8 tests: cot weights, symmetry, correct null-space & sign-convention
    (H·1 ≠ 0; H is NSD at equilibrium), FD × 3 meshes

All 62 cgal tests pass (3 skipped as before).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-05-12 17:22:28 +02:00
Tarik Moussa
8c353bb884 feat(phase3d+3e): port EuclideanCyclicFunctional + add SphericalFunctional gauge-fix
Phase 3d — EuclideanCyclicFunctional:
  • euclidean_geometry.hpp: t-value / atan2 corner-angle formula with
    centering trick (μ = (Λ̃₁₂+Λ̃₂₃+Λ̃₃₁)/6) for numerical stability
  • euclidean_functional.hpp: EuclideanMaps bundle, gradient (G_v = Θ_v − Σα_v,
    G_e = α_opp⁺ + α_opp⁻ − φ_e), 10-point GL path-integral energy,
    gradient_check_euclidean — identical halfedge convention to SphericalFunctional
  • test_euclidean_functional.cpp: 11 tests (1 skip) covering angle formula,
    right-isosceles triangle, angle sum = π, degenerate detection, gradient
    checks on triangle/quad-strip/tetrahedron/fan-5/mixed-pinned, NaN check

Phase 3e — Spherical gauge-fix:
  • spherical_gauge_shift(): Newton + backtracking line search to find t*
    where ΣG_v(x + t·1) = 0 (maximises E along the global scale direction);
    bisection used when sign change is detectable, Newton+backtrack otherwise
  • apply_spherical_gauge(): in-place wrapper
  • 3 new tests: GaugeFix_SpherTetVertexZerosSumGv, GaugeFix_ApplyInPlace,
    GaugeFix_AlreadyAtGaugeReturnsTNearZero

Total: 45 cgal tests pass, 3 skipped (@Ignore Hessian stubs, one per functional)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 07:39:14 +02:00
Tarik Moussa
a4c2a89e7e 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>
2026-05-12 00:01:24 +02:00
Tarik Moussa
516ac89bd8 feat(phase3b): port HyperIdealFunctional energy + gradient onto ConformalMesh
Implements the hyper-ideal discrete conformal map functional on
CGAL::Surface_mesh. The energy and analytic gradient are ported directly
from HyperIdealFunctional.java; correctness is verified via a
finite-difference gradient check (same eps=1E-5 / tol=1E-4 as Java).

New files:
  include/hyper_ideal_geometry.hpp    — ζ, ζ₁₃, ζ₁₄, ζ₁₅, lij, αij, σi, σij
  include/hyper_ideal_functional.hpp  — HyperIdealMaps, evaluate_hyper_ideal,
                                        gradient_check
  tests/cgal/test_hyper_ideal_functional.cpp  — 6 tests (1 skipped @Ignore)

Test results (local, -DWITH_CGAL=ON):
  conformallab_cgal_tests: 21 registered | 20 passed | 1 skipped | 0 failed
    - GradientCheck_AllHyperIdealTriangle   ✓
    - GradientCheck_ExtendedDomain          ✓
    - GradientCheck_TetrahedronAllVariable  ✓
    - EnergyFiniteAtTestPoint               ✓
    - GradientCheck_MixedIdealHyperIdeal    ✓
    - GradientCheck_Fan6AllVariable         ✓

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 23:10:23 +02:00
Tarik Moussa
bf9c323d60 feat(phase3a): introduce CGAL Surface_mesh as ConformalMesh foundation
Replaces the Java CoHDS with CGAL::Surface_mesh<Point3> (Simple_cartesian
kernel). Adds domain-specific property maps for lambda/theta/idx/alpha and
face geometry type — the direct C++ equivalent of CoVertex/CoEdge adapters.

New files:
  include/conformal_mesh.hpp   — ConformalMesh type + property-map helpers
  include/mesh_builder.hpp     — mesh factories (triangle, tetrahedron,
                                 quad-strip, fan) for tests and examples
  tests/cgal/                  — second test executable (conformallab_cgal_tests)
                                 built only with -DWITH_CGAL=ON

Test results (local, -DWITH_CGAL=ON):
  conformallab_tests:      36 registered | 23 passed | 13 skipped | 0 failed
  conformallab_cgal_tests: 14 registered | 14 passed |  0 skipped | 0 failed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 18:36:21 +02:00
Tarik Moussa
ae5db7216e tests: port HyperIdealVisualizationPlugin circle-projection tests
All checks were successful
C++ Tests / test (push) Successful in 2m29s
Mirror to Codeberg / mirror (push) Successful in 26s
Implements getEuclideanCircleFromHyperbolic() in C++ (hyperboloid model
→ Poincaré disk via Lorentz boost + circumcircle). Ports the 2 Java tests
that were the only remaining candidates not requiring HDS or a solver.

All other unported tests (DataTypesTest, SchottkyIOTest,
UniformizationDataTest, BranchedCoverTorusTest) are blocked by XML
serialization or HDS – stubs remain for Phase 4.

Test totals: 36 registered | 23 passed | 13 skipped | 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 17:23:15 +02:00
Tarik Moussa
c5a86cb30a tests: port DiscreteEllipticUtility + P2 tests; stub HDS-blocked tests
All checks were successful
C++ Tests / test (push) Successful in 2m39s
Mirror to Codeberg / mirror (push) Successful in 24s
Fully ported (pure math, no HDS required):
  test_discrete_elliptic_utility.cpp  – 2 tests
    normalizeModulus: move tau into SL(2,Z) fundamental domain
  test_p2_utility.cpp                 – 3 tests
    P2 projective geometry (perpendicularBisector, pointFromLines,
    makeDirectIsometryFromFrames double vs long double precision)

New headers:
  include/discrete_elliptic_utility.hpp  – normalizeModulus
  include/p2_utility.hpp                 – P2 Euclidean geometry (templated
    on scalar type so double and long double share one implementation)

Stubs (GTEST_SKIP, blocked until HDS port – Phase 4):
  test_hyper_ideal_functional.cpp          – 5 tests (1 @Ignore in Java)
  test_hyper_ideal_hyperelliptic_utility.cpp – 3 tests
  test_spherical_functional.cpp            – 5 tests
  All use CoHDS + HalfEdgeUtils which are not yet ported to C++.

Result: 34 tests total | 21 passed | 13 skipped | 0 failed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 17:15:18 +02:00
Tarik Moussa
b66525039d fix: gitignore – update CMakeLists.txt exception + ignore macOS duplicates
All checks were successful
C++ Tests / test (push) Successful in 2m13s
Mirror to Codeberg / mirror (push) Successful in 25s
- Exception updated to match renamed CMakeLists.txt (capital M)
- Add "* 2.*" / "* 3.*" patterns to suppress iCloud Drive duplicate
  files (e.g. "clausen 2.hpp") from appearing in git status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 00:22:53 +02:00
Tarik Moussa
6a70309a30 fix: rename deps/Cmakelists.txt → CMakeLists.txt (case-sensitive Linux fix)
Some checks failed
C++ Tests / test (push) Has started running
Mirror to Codeberg / mirror (push) Has been cancelled
macOS filesystem is case-insensitive so both spellings worked locally,
but the Linux container (CI) could not find the file and failed with
"does not contain a CMakeLists.txt file".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 00:22:16 +02:00
Tarik Moussa
42dd815591 cmake: add find_package(Boost) for WITH_CGAL mode
Some checks failed
C++ Tests / test (push) Failing after 41s
Mirror to Codeberg / mirror (push) Successful in 35s
CGAL 6.x still unconditionally includes boost/config.hpp in its
config.h, so Boost headers are required even with CGAL_DISABLE_GMP/MPFR.

Use system Boost via find_package instead of the removed 211 MB tarball.
Tests-only mode remains completely dependency-free.

Install: brew install boost  (macOS)
         apt install libboost-dev  (Debian/Ubuntu)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 00:20:38 +02:00
Tarik Moussa
cd7b7a8fd8 cmake: add WITH_CGAL / WITH_VIEWER modes, remove unused Boost
Restructures the CMake build into three clearly separated modes:

  (default)        tests only – Eigen + GTest, no heavy deps
  -DWITH_VIEWER=ON builds viewer lib (libigl / GLFW / GLAD)
  -DWITH_CGAL=ON   builds conformallab_core CLI app;
                   implies WITH_VIEWER automatically

Changes:
- code/CMakeLists.txt: viewer and core targets are now guarded by
  option() flags; GTest / tests target is always built
- code/deps/Cmakelists.txt: CGAL, libigl, glfw, glad are only
  extracted when the corresponding mode is enabled; Eigen always
- Remove Boost (211 MB tarball, 0 usages in the codebase – CGAL 6.x
  does not require Boost for Simple_cartesian / Surface_mesh / basic IO)
- Remove code/src/main.cpp (dead file, not referenced in CMake)

All 16 C++ tests pass in tests-only mode (verified locally).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:42:43 +02:00
Tarik Moussa
a2876b9cbf port MatrixUtility and SurfaceCurveUtility tests to C++
- include/matrix_utility.hpp: 4x4 mapping matrix R·from=to (Eigen)
- include/projective_math.hpp: dehomogenize, hyperbolicDistance,
  isOnSegment (collinearity + betweenness via 3D cross/dot),
  getPointOnCorrespondingSegment (parameter by arc-length ratio)
- test_matrix_utility.cpp: port of MatrixUtilityTest (1 test)
- test_surface_curve_utility.cpp: port of SurfaceCurveUtilityTest
  testIsBetween and testGetPointOnSegment_SegmentEdge (2 tests)
- tolerance adjusted to 1e-12 for matrix inversion (2.7e-15 rounding
  from Eigen vs jReality's LU; both well within meaningful accuracy)

Total: 16/16 tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 01:15:35 +02:00
Tarik Moussa
c30d540521 add GTest infrastructure and port first mathematical tests from Java
- Add Google Test via CMake FetchContent (v1.14.0)
- Add clausen.hpp: Clausen integral, Lobachevsky function, Im(Li2)
- Add hyper_ideal_utility.hpp: generalized and ideal-vertex hyperbolic
  tetrahedron volume formulas using Eigen for the 4x4 Gram determinant
- Port ClausenTest (5 tests) and HyperIdealUtilityTest (8 tests) from
  Java/JUnit — all 13 pass with same tolerances as the Java originals
- Fix pre-existing VIEWER/viewer case mismatch in CMakeLists.txt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 01:07:19 +02:00
Tarik Moussa
94533514fc fix typo 2026-03-17 21:25:33 +02:00
Tarik Moussa
e150cf6ef3 add new compile target for viewer 2026-03-17 21:18:59 +02:00
Tarik Moussa
2479aedeee ad simple visualization 2026-03-16 17:47:48 +02:00
Tarik Moussa
1ce993f296 ad simple visualization 2026-03-16 17:20:15 +02:00
Tarik Moussa
e1a90dbd85 fix typo 2026-03-06 21:43:54 +02:00
Tarik Moussa
5be43c90bc add dep liblig 2026-03-04 13:42:26 +02:00
Tarik Moussa
f3b7453a45 add CMake dependency handling for portability 2026-02-16 18:18:39 +02:00
Tarik Moussa
1d20c3a195 add CMake dependency handling for portability 2026-02-16 08:13:46 +02:00
Tarik Moussa
b7875f3b88 add CMake dependency handling for portability 2026-02-14 22:23:21 +02:00
Tarik Moussa
fbd3b26acc CLI11.hpp 2026-02-09 21:43:21 +02:00
Tarik Moussa
6d283fd952 json.hpp 2026-02-09 21:35:54 +02:00
Tarik Moussa
119601d639 CMakeList.txt 2026-02-09 21:30:36 +02:00