U4 (README.md:17) — status line: v0.9.0 → v0.10.0, test count 0 → 277
U5 (Discrete_conformal_map.h:6-16) — \file Doxygen block rewritten:
was: 'provides a single function … Spherical/hyperbolic scheduled for Phase 8b.2'
now: lists all three discrete_conformal_map_* functions already present,
plus pointers to the circle-packing companion headers
U7 (getting-started.md) — new 'Mode 4 — Low-memory build' section added
after Mode 3; shows CONFORMALLAB_LOW_MEMORY_BUILD=ON with -j1 and explains
the -O0 / no PCH / batch-1 tradeoffs for Raspberry Pi / ≤ 4 GB runners
U8 (README.md compile-time modes) — LOW_MEMORY_BUILD entry added to the
compile-time workflow code block with a one-line explanation and the
mandatory -j1 note
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.8 KiB
Getting Started
Prerequisites
| Tool | Minimum | Notes |
|---|---|---|
| C++ compiler (GCC or Clang) | C++17 | GCC 11+ or Clang 14+ recommended |
| CMake | 3.20 | |
| Boost headers | 1.70 | Only for -DWITH_CGAL_TESTS=ON or -DWITH_CGAL=ON |
| Wayland/X11 dev headers | — | Only for -DWITH_CGAL=ON (viewer) |
All other dependencies (Eigen 3.4, CGAL 6.1.1, libigl 2.6, GLFW 3.4, GTest 1.14)
are bundled as tarballs in code/deps/tarballs/ and extracted automatically at CMake
configure time. No internet access is required at build time (except GTest, fetched via
FetchContent from GitHub).
Install Boost on your system:
# Ubuntu / Debian
apt install libboost-dev
# macOS
brew install boost
Clone
git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
Build modes
Three modes with increasing dependencies:
Mode 1 — Fast tests (default, no system dependencies)
Pure-math tests: Clausen functions, hyper-ideal geometry, matrix utilities.
cmake -S code -B build
cmake --build build --target conformallab_tests -j$(nproc)
ctest --test-dir build --output-on-failure
Expected: all pure-math tests pass (count: doc/api/tests.md).
Mode 2 — CGAL tests, headless (recommended for CI and development)
Full CGAL test suite. Requires Boost headers only — no display, no Wayland, no GLFW.
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
Expected: all CGAL tests pass, 0 skipped (count: doc/api/tests.md).
Mode 3 — Full local build (CLI app + interactive viewer)
Requires Wayland or X11 development packages (wayland-scanner, libx11-dev, etc.).
Automatically enables the viewer library (GLFW + libigl).
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -j$(nproc)
Note:
-DWITH_CGAL=ONimplies-DWITH_VIEWER=ON. Do not use this in headless environments — it will fail withFailed to find wayland-scanner.
Mode 4 — Low-memory build (RAM-constrained CI / Raspberry Pi ≤ 4 GB)
For machines where the CGAL build OOMs (peak ~700 MB per compilation unit at -O3):
cmake -S code -B build -DWITH_CGAL_TESTS=ON \
-DCONFORMALLAB_LOW_MEMORY_BUILD=ON
cmake --build build --target conformallab_cgal_tests -j1
LOW_MEMORY_BUILD applies four measures: -O0 (no debug info), PCH off,
unity batch size 1, --no-keep-memory linker flag. Drops cc1plus peak from
~700 MB to ~150-200 MB per TU. Tests run ~15× slower at -O0 but all pass.
Always use -j1 — parallel compilation would defeat the memory savings.
Running a single test
# By GTest filter (fastest, full output)
./build/conformallab_cgal_tests --gtest_filter="NewtonSolver*"
./build/conformallab_tests --gtest_filter="Clausen*"
# By CTest regex
ctest --test-dir build -R "cgal.NewtonSolver" --output-on-failure
All CGAL tests have the prefix cgal. in CTest (set in tests/cgal/CMakeLists.txt
via TEST_PREFIX "cgal.").
First run — CLI app
After a full build (-DWITH_CGAL=ON):
# Euclidean conformal layout
./bin/conformallab_core -i input.off -g euclidean -o layout.off -j result.json
# Spherical layout
./bin/conformallab_core -i input.off -g spherical -o sphere.off
# Hyperbolic layout (HyperIdeal)
./bin/conformallab_core -i input.off -g hyper_ideal -o hyperbolic.off
# Show input mesh in interactive viewer
./bin/conformallab_core -i input.off -s
# All options
./bin/conformallab_core --help
Example programs
# PRIMARY USE CASE: conformally flatten a mesh to the plane
./build/examples/example_flatten code/data/obj/cathead.obj flat.off
# → non-trivial u_v (e.g. range ≈ 2.96), real conformal deformation
# CGAL public API: one-call interface (natural theta by default)
./build/examples/example_cgal_api [input.off]
# Full pipeline with JSON/XML serialisation and round-trip test
./build/examples/example_layout [input.off] [layout.off] [result.json]
# Solver test (natural theta — u_v ≈ 0, used for pipeline validation)
./build/examples/example_euclidean [input.off] [output.off]
# Hyper-ideal (hyperbolic) functional
./build/examples/example_hyper_ideal [input.off] [output.off]
# Interactive viewer (requires WITH_VIEWER)
./build/examples/example_viewer [input.off]
Start here: example_flatten.cpp shows the primary use case — real conformal
flattening with Θ_v = 2π. example_layout.cpp adds JSON/XML serialisation.
Note on "natural theta":
example_euclideanandexample_layoutuse the "natural theta" testing trick (Θ_v = actual angle sum at x=0), which makesx* = 0trivially the equilibrium. The outputu_v ≈ 0is expected and correct for a pipeline test, but means no conformal deformation was applied. For real UV parameterisation, useexample_flatten.cpp.
Expected output of example_euclidean on the built-in quad-strip mesh:
[example_euclidean] No input file given — using make_quad_strip().
[example_euclidean] Mesh: 6 vertices, 4 faces.
[example_euclidean] DOFs: 5 (1 vertex pinned).
[example_euclidean] Solving Newton system…
[example_euclidean] Converged in 1 iterations. ||G||_inf = 0
[example_euclidean] Per-vertex conformal factors u_i:
v0 u = 0 (pinned)
v1 u = -1.38778e-17 ← ≈ 0 (machine epsilon)
...
[example_euclidean] Mesh saved to: /tmp/conformallab_euclidean_out.off
Convergence in 1 iteration is expected: the "natural equilibrium" construction sets x* = 0, so a small perturbation (-0.05) needs only one Newton step.
Quick automated start (no interactive build needed):
bash scripts/try_it.sh
This clones nothing (run from inside the repo), builds the CGAL test suite, runs
the full test suite, and prints a summary. See scripts/try_it.sh for details.
Known issues
macOS Finder duplicates
macOS Finder sometimes creates duplicate files named foo 2.hpp when copying
the repository. These cause confusing compile errors ("redefinition of …").
Fix (run once from the repo root):
find code/include -name "* 2.*" -delete
find code/include -name "*\ 2.*" -delete
Files without a 2 suffix are always canonical — the duplicates are safe to delete.
First build is slow
The first CMake configure extracts four tarballs (Eigen 3.4, CGAL 6.1.1,
libigl 2.6, GLFW 3.4) and downloads GTest via FetchContent.
Allow 30–90 seconds for the first configure. Subsequent builds are fast
(< 10 s incremental).
Rebuilding the CI Docker image
The CI runner is a self-hosted Raspberry Pi (ARM64). After changes to
.gitea/docker/Dockerfile.ci-cpp:
docker buildx build \
--platform linux/arm64 \
-f .gitea/docker/Dockerfile.ci-cpp \
-t git.eulernest.eu/conformallab/ci-cpp:latest \
--push \
.gitea/docker/