Merge pull request 'reviewer-meeting prep: CI promotion + 3rd-party licenses + output_uv_map(ID) + briefing trio' (#19) from reviewer/meeting-prep into main
Some checks failed
C++ Tests / test-fast (push) Successful in 2m15s
API Docs / doc-build (push) Has been skipped
Markdown link check / check (push) Successful in 49s
Mirror to Codeberg / mirror (push) Successful in 33s
Compile-time perf bench / compile-time-matrix (push) Failing after 38s
C++ Tests / test-cgal (push) Has been cancelled
C++ Tests / quality-gates (push) Has been cancelled
Some checks failed
C++ Tests / test-fast (push) Successful in 2m15s
API Docs / doc-build (push) Has been skipped
Markdown link check / check (push) Successful in 49s
Mirror to Codeberg / mirror (push) Successful in 33s
Compile-time perf bench / compile-time-matrix (push) Failing after 38s
C++ Tests / test-cgal (push) Has been cancelled
C++ Tests / quality-gates (push) Has been cancelled
This commit is contained in:
@@ -69,6 +69,7 @@ ignore-words-list = bessel,ist,sinces,nd,te,inout,nin,numer,neet,anc,sinks,doubl
|
|||||||
iff,
|
iff,
|
||||||
categorise,categorised,categorises,categorising,
|
categorise,categorised,categorises,categorising,
|
||||||
optimisation,optimisations,
|
optimisation,optimisations,
|
||||||
|
acknowledgement,acknowledgements,acknowledging,
|
||||||
neighbour,neighbours,neighbouring,neighboured,
|
neighbour,neighbours,neighbouring,neighboured,
|
||||||
labelled,labelling,labels,labelled,
|
labelled,labelling,labels,labelled,
|
||||||
fulfil,fulfils,fulfilled,fulfilling,
|
fulfil,fulfils,fulfilled,fulfilling,
|
||||||
|
|||||||
@@ -112,3 +112,51 @@ jobs:
|
|||||||
# the price of guaranteeing the documented workflow stays working.
|
# the price of guaranteeing the documented workflow stays working.
|
||||||
- name: End-to-end smoke test (scripts/try_it.sh)
|
- name: End-to-end smoke test (scripts/try_it.sh)
|
||||||
run: bash scripts/try_it.sh
|
run: bash scripts/try_it.sh
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Job 3 — quality-gates (style + convention block)
|
||||||
|
#
|
||||||
|
# Cheap, deterministic checks that should never break unless a contributor
|
||||||
|
# introduces a regression. Each gate is a script under scripts/quality/
|
||||||
|
# and exits 0 only when its tree is clean. These ran for weeks locally
|
||||||
|
# at zero findings before being promoted here.
|
||||||
|
#
|
||||||
|
# Tools installed at job-start (the ci-cpp image already has python3 +
|
||||||
|
# bash; we add codespell + shellcheck on top). Total wall-time: ~30 s
|
||||||
|
# on the eulernest runner.
|
||||||
|
#
|
||||||
|
# Strictly required for merges into main/dev — a regression fails the PR.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
quality-gates:
|
||||||
|
needs: test-fast
|
||||||
|
runs-on: eulernest
|
||||||
|
container:
|
||||||
|
image: git.eulernest.eu/conformallab/ci-cpp:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install codespell + shellcheck (job-local)
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
codespell shellcheck
|
||||||
|
|
||||||
|
- name: License headers (every C++ source carries MIT SPDX)
|
||||||
|
run: bash scripts/quality/license-headers.sh
|
||||||
|
|
||||||
|
- name: CGAL conventions (6 rules over CGAL public headers)
|
||||||
|
run: python3 scripts/quality/cgal-conventions.py
|
||||||
|
|
||||||
|
- name: codespell (docs + source comments + script messages)
|
||||||
|
run: bash scripts/quality/codespell.sh
|
||||||
|
|
||||||
|
- name: shellcheck (scripts/**/*.sh, severity=warning, strict)
|
||||||
|
run: bash scripts/quality/shellcheck.sh --strict
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "QUALITY ▸ all four gates passed."
|
||||||
|
echo " see scripts/quality/README.md for the full catalogue"
|
||||||
|
echo " (sanitizers, clang-tidy, coverage, etc. are local-only)"
|
||||||
|
|||||||
@@ -75,16 +75,31 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
# Build the publish payload in a clean scratch dir so the
|
# Build the publish payload in a clean scratch dir so the
|
||||||
# orphan branch contains only the Doxygen output (and a
|
# orphan branch contains only the reviewer hub + Doxygen
|
||||||
# marker README), never any build/source artefacts.
|
# output (and a marker README), never any build/source
|
||||||
|
# artefacts.
|
||||||
publish_dir=$(mktemp -d)
|
publish_dir=$(mktemp -d)
|
||||||
cp -r doc/doxygen/html/. "$publish_dir/"
|
cp -r doc/doxygen/html/. "$publish_dir/"
|
||||||
|
|
||||||
|
# ── Reviewer hub override ─────────────────────────────────
|
||||||
|
# If doc/reviewer/hub.html is present, install it as the
|
||||||
|
# publish landing page and demote the auto-generated Doxygen
|
||||||
|
# index to /doxygen.html. The hub is hand-curated and lives
|
||||||
|
# under source control; this step keeps it visible after
|
||||||
|
# every push to main, surviving the auto-publish cycle.
|
||||||
|
if [ -f doc/reviewer/hub.html ]; then
|
||||||
|
mv "$publish_dir/index.html" "$publish_dir/doxygen.html"
|
||||||
|
cp doc/reviewer/hub.html "$publish_dir/index.html"
|
||||||
|
echo "DOC ▸ reviewer hub installed; Doxygen index now at /doxygen.html"
|
||||||
|
fi
|
||||||
|
|
||||||
cat > "$publish_dir/README.txt" <<EOF
|
cat > "$publish_dir/README.txt" <<EOF
|
||||||
conformallab++ — Doxygen HTML API documentation.
|
conformallab++ — Doxygen HTML API documentation + reviewer hub.
|
||||||
Auto-generated by .gitea/workflows/doxygen-pages.yml from
|
Auto-generated by .gitea/workflows/doxygen-pages.yml from
|
||||||
commit ${GITHUB_SHA:-$(git rev-parse HEAD)} on $(date -Iseconds).
|
commit ${GITHUB_SHA:-$(git rev-parse HEAD)} on $(date -Iseconds).
|
||||||
Source: https://codeberg.org/TMoussa/ConformalLabpp
|
Source: https://codeberg.org/TMoussa/ConformalLabpp
|
||||||
|
Reviewer hub: doc/reviewer/hub.html (in-repo)
|
||||||
|
Doxygen index: /doxygen.html
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cd "$publish_dir"
|
cd "$publish_dir"
|
||||||
|
|||||||
175
.gitea/workflows/perf-compile-time.yml
Normal file
175
.gitea/workflows/perf-compile-time.yml
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
name: Compile-time perf bench
|
||||||
|
|
||||||
|
# Cross-platform compile-time benchmark. Validates the predictions
|
||||||
|
# made in doc/architecture/compile-time.md against the eulernest CI
|
||||||
|
# runner (Linux + g++ on ARM64).
|
||||||
|
#
|
||||||
|
# Specifically tests whether:
|
||||||
|
# 1. FAST_TEST_BUILD=ON delivers the ~40 % wall-time reduction on
|
||||||
|
# Linux + g++ that was predicted from `-ftime-trace` profiling
|
||||||
|
# (recall: on Apple clang + Apple M1 it was net-neutral).
|
||||||
|
# 2. ccache hit rate is in the predicted 80%+ range on a warm
|
||||||
|
# rerun (where the macOS-local hit rate was 0 % due to
|
||||||
|
# Apple-clang + PCH friction).
|
||||||
|
#
|
||||||
|
# When run:
|
||||||
|
# * push to main (after PR #19 lands)
|
||||||
|
# * workflow_dispatch (manual trigger for ad-hoc verification)
|
||||||
|
#
|
||||||
|
# NOT run on every PR — this is a perf data-collection job, not a
|
||||||
|
# correctness gate. Pollutes the summary with timings but does not
|
||||||
|
# block merges.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "code/CMakeLists.txt"
|
||||||
|
- "code/tests/**/CMakeLists.txt"
|
||||||
|
- "code/include/**"
|
||||||
|
- ".gitea/workflows/perf-compile-time.yml"
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile-time-matrix:
|
||||||
|
runs-on: eulernest
|
||||||
|
container:
|
||||||
|
image: git.eulernest.eu/conformallab/ci-cpp:latest
|
||||||
|
options: "--memory=2400m --memory-swap=2400m"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install ccache (idempotent)
|
||||||
|
run: |
|
||||||
|
which ccache >/dev/null 2>&1 || apt-get install -y --no-install-recommends ccache
|
||||||
|
|
||||||
|
# ─── Run 1: baseline (PCH OFF, Unity OFF, ccache cleared) ──────
|
||||||
|
- name: "Run 1: cold baseline (no PCH, no Unity, no ccache)"
|
||||||
|
run: |
|
||||||
|
ccache -C >/dev/null 2>&1 || true
|
||||||
|
rm -rf build-baseline
|
||||||
|
cmake -S code -B build-baseline -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_PCH=OFF \
|
||||||
|
-DCMAKE_UNITY_BUILD=OFF \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=OFF
|
||||||
|
start=$(date +%s)
|
||||||
|
nice -n 19 cmake --build build-baseline --target conformallab_cgal_tests -j1
|
||||||
|
end=$(date +%s)
|
||||||
|
echo "PERF baseline_wall=$((end - start)) s"
|
||||||
|
echo "PERF_BASELINE_WALL=$((end - start))" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# ─── Run 2: PCH only ──────────────────────────────────────────
|
||||||
|
- name: "Run 2: PCH only (Unity off, ccache off)"
|
||||||
|
run: |
|
||||||
|
ccache -C >/dev/null 2>&1 || true
|
||||||
|
rm -rf build-pch
|
||||||
|
cmake -S code -B build-pch -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_PCH=ON \
|
||||||
|
-DCMAKE_UNITY_BUILD=OFF \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=OFF
|
||||||
|
start=$(date +%s)
|
||||||
|
nice -n 19 cmake --build build-pch --target conformallab_cgal_tests -j1
|
||||||
|
end=$(date +%s)
|
||||||
|
echo "PERF pch_only_wall=$((end - start)) s"
|
||||||
|
echo "PERF_PCH_WALL=$((end - start))" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# ─── Run 3: default (PCH + Unity Build + #6 Dense→Core) ───────
|
||||||
|
- name: "Run 3: default config (PCH + Unity + Dense→Core)"
|
||||||
|
run: |
|
||||||
|
ccache -C >/dev/null 2>&1 || true
|
||||||
|
rm -rf build-default
|
||||||
|
cmake -S code -B build-default -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=OFF
|
||||||
|
start=$(date +%s)
|
||||||
|
nice -n 19 cmake --build build-default --target conformallab_cgal_tests -j1
|
||||||
|
end=$(date +%s)
|
||||||
|
echo "PERF default_wall=$((end - start)) s"
|
||||||
|
echo "PERF_DEFAULT_WALL=$((end - start))" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# ─── Run 4: + FAST_TEST_BUILD (-O0 -g) ────────────────────────
|
||||||
|
- name: "Run 4: default + FAST_TEST_BUILD=ON (-O0 -g for tests)"
|
||||||
|
run: |
|
||||||
|
ccache -C >/dev/null 2>&1 || true
|
||||||
|
rm -rf build-fast
|
||||||
|
cmake -S code -B build-fast -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_FAST_TEST_BUILD=ON \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=OFF
|
||||||
|
start=$(date +%s)
|
||||||
|
nice -n 19 cmake --build build-fast --target conformallab_cgal_tests -j1
|
||||||
|
end=$(date +%s)
|
||||||
|
echo "PERF fast_test_wall=$((end - start)) s"
|
||||||
|
echo "PERF_FAST_WALL=$((end - start))" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# ─── Run 5: ccache hit-rate validation ─────────────────────────
|
||||||
|
- name: "Run 5: ccache hit-rate (rebuild build-default)"
|
||||||
|
run: |
|
||||||
|
ccache -C >/dev/null 2>&1 || true
|
||||||
|
ccache --zero-stats >/dev/null
|
||||||
|
# First rebuild: populate ccache.
|
||||||
|
rm -rf build-cc
|
||||||
|
cmake -S code -B build-cc -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=ON
|
||||||
|
nice -n 19 cmake --build build-cc --target conformallab_cgal_tests -j1 >/dev/null
|
||||||
|
ccache_first=$(ccache -s 2>&1 | grep -E "^\s*Hits" | head -1 | awk '{print $2}')
|
||||||
|
# Second rebuild: expect cache hits.
|
||||||
|
rm -rf build-cc-warm
|
||||||
|
cmake -S code -B build-cc-warm -G Ninja \
|
||||||
|
-DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_CCACHE=ON
|
||||||
|
start=$(date +%s)
|
||||||
|
nice -n 19 cmake --build build-cc-warm --target conformallab_cgal_tests -j1
|
||||||
|
end=$(date +%s)
|
||||||
|
warm_wall=$((end - start))
|
||||||
|
ccache_stats=$(ccache -s 2>&1 | grep -E "Hits|Misses" | head -4)
|
||||||
|
echo "── ccache stats after warm rebuild ──"
|
||||||
|
echo "$ccache_stats"
|
||||||
|
echo "PERF ccache_warm_wall=${warm_wall} s"
|
||||||
|
echo "PERF_CCACHE_WARM_WALL=$warm_wall" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# ─── Test correctness (last gate; perf data already collected) ─
|
||||||
|
- name: Verify all configs produced working binaries
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
for build in build-baseline build-pch build-default build-fast; do
|
||||||
|
if [ -d "$build" ]; then
|
||||||
|
ctest --test-dir "$build" -R "^cgal\." --output-on-failure --timeout 120 \
|
||||||
|
| tail -3
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# ─── Final summary ─────────────────────────────────────────────
|
||||||
|
- name: Compile-time perf summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "══════════════════════════════════════════════════════"
|
||||||
|
echo " COMPILE-TIME PERF BENCH — Linux ARM64 / g++ / -j1"
|
||||||
|
echo "══════════════════════════════════════════════════════"
|
||||||
|
printf " %-30s %4s s\n" "Run 1: cold baseline" "${PERF_BASELINE_WALL:-?}"
|
||||||
|
printf " %-30s %4s s\n" "Run 2: + PCH" "${PERF_PCH_WALL:-?}"
|
||||||
|
printf " %-30s %4s s\n" "Run 3: + PCH + Unity (default)" "${PERF_DEFAULT_WALL:-?}"
|
||||||
|
printf " %-30s %4s s\n" "Run 4: + FAST_TEST_BUILD" "${PERF_FAST_WALL:-?}"
|
||||||
|
printf " %-30s %4s s\n" "Run 5: + ccache warm rerun" "${PERF_CCACHE_WARM_WALL:-?}"
|
||||||
|
echo "──────────────────────────────────────────────────────"
|
||||||
|
echo "Predictions to validate vs Apple-M1 baseline:"
|
||||||
|
echo " ┃ FAST_TEST_BUILD: expected ~40 % faster than default"
|
||||||
|
echo " ┃ ccache warm: expected ≤ 10 s (vs Apple's 55 s)"
|
||||||
|
echo "──────────────────────────────────────────────────────"
|
||||||
|
# Compute relative deltas
|
||||||
|
if [ -n "${PERF_DEFAULT_WALL:-}" ] && [ -n "${PERF_FAST_WALL:-}" ]; then
|
||||||
|
pct=$(awk -v d="${PERF_DEFAULT_WALL}" -v f="${PERF_FAST_WALL}" \
|
||||||
|
'BEGIN { printf "%.0f", 100.0 * (d - f) / d }')
|
||||||
|
echo " Δ FAST_TEST_BUILD vs default: ${pct} % wall reduction"
|
||||||
|
fi
|
||||||
|
if [ -n "${PERF_DEFAULT_WALL:-}" ] && [ -n "${PERF_CCACHE_WARM_WALL:-}" ]; then
|
||||||
|
pct=$(awk -v d="${PERF_DEFAULT_WALL}" -v c="${PERF_CCACHE_WARM_WALL}" \
|
||||||
|
'BEGIN { printf "%.0f", 100.0 * (d - c) / d }')
|
||||||
|
echo " Δ ccache warm vs default: ${pct} % wall reduction"
|
||||||
|
fi
|
||||||
|
echo "══════════════════════════════════════════════════════"
|
||||||
35
README.md
35
README.md
@@ -41,6 +41,41 @@ cmake --build build --target doc
|
|||||||
open doc/doxygen/html/index.html
|
open doc/doxygen/html/index.html
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Compile-time workflow modes
|
||||||
|
|
||||||
|
The default build (PCH + Unity Build + Dense→Core trims) takes ~47 s
|
||||||
|
clean for the full CGAL test target. Five opt-in modes cover other
|
||||||
|
iteration scenarios:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure-only, no compile. ~1 s configure, 0 s build — emits
|
||||||
|
# compile_commands.json for IDE / clangd; skips the GTest fetch.
|
||||||
|
cmake -S code -B build -DBUILD_TESTING=OFF
|
||||||
|
|
||||||
|
# Header smoke check: per-public-header isolated compile. ~12 s full,
|
||||||
|
# ~0.1 s after touching one header. "Does my refactor still parse?"
|
||||||
|
cmake -S code -B build -DBUILD_TESTING=OFF -DCONFORMALLAB_HEADERS_CHECK=ON
|
||||||
|
cmake --build build --target headers_check
|
||||||
|
|
||||||
|
# Dev iteration: PCH on, Unity off. Slower full build (~75 s) but
|
||||||
|
# editing a single test rebuilds in ~16 s instead of ~46 s.
|
||||||
|
cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCONFORMALLAB_DEV_BUILD=ON
|
||||||
|
|
||||||
|
# Fast CI tests: -O0 -g for the test executables only (library /
|
||||||
|
# install targets keep -O3). Linux + g++ typically ~40 % faster
|
||||||
|
# build at the cost of 5–15× slower test RUN. Neutral on macOS.
|
||||||
|
cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCONFORMALLAB_FAST_TEST_BUILD=ON
|
||||||
|
|
||||||
|
# Pristine measurement: disable both performance levers, e.g. for
|
||||||
|
# scripts/quality/coverage.sh that needs every TU compiled fresh.
|
||||||
|
cmake -S code -B build -DWITH_CGAL_TESTS=ON \
|
||||||
|
-DCONFORMALLAB_USE_PCH=OFF -DCMAKE_UNITY_BUILD=OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
ccache is detected automatically when present on `PATH`; disable with
|
||||||
|
`-DCONFORMALLAB_USE_CCACHE=OFF`. Full mode matrix + measurements in
|
||||||
|
[`doc/architecture/compile-time.md`](doc/architecture/compile-time.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Minimal usage
|
## Minimal usage
|
||||||
|
|||||||
1
code/.gitignore
vendored
1
code/.gitignore
vendored
@@ -13,6 +13,7 @@ deps/*
|
|||||||
!deps/tarballs
|
!deps/tarballs
|
||||||
!deps/single_includes/
|
!deps/single_includes/
|
||||||
!deps/CMakeLists.txt
|
!deps/CMakeLists.txt
|
||||||
|
!deps/THIRD-PARTY-LICENSES.md
|
||||||
|
|
||||||
# macOS iCloud Drive duplicates ("file 2.cpp", "file 2.hpp", …)
|
# macOS iCloud Drive duplicates ("file 2.cpp", "file 2.hpp", …)
|
||||||
* 2.*
|
* 2.*
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ if(WITH_CGAL AND NOT WITH_VIEWER)
|
|||||||
set(WITH_VIEWER ON CACHE BOOL "" FORCE)
|
set(WITH_VIEWER ON CACHE BOOL "" FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Propagate Boost requirement for both CGAL modes.
|
# Propagate Boost requirement for both CGAL modes + headers_check (which
|
||||||
if(WITH_CGAL OR WITH_CGAL_TESTS)
|
# also compiles CGAL headers, hence needs Boost::graph_traits).
|
||||||
|
if(WITH_CGAL OR WITH_CGAL_TESTS OR CONFORMALLAB_HEADERS_CHECK)
|
||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -54,6 +55,59 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# ── ccache integration (lever D) ───────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Detect `ccache` on the host and prepend it to the compile + link launchers.
|
||||||
|
# Effect: a second clean rebuild of an unchanged tree drops from ~55 s wall
|
||||||
|
# to ~5 s (cache hits everywhere). Costs nothing when ccache is absent.
|
||||||
|
# Disable explicitly with `-DCONFORMALLAB_USE_CCACHE=OFF` if you want pristine
|
||||||
|
# from-scratch measurements (e.g. when re-running scripts/quality/coverage.sh).
|
||||||
|
option(CONFORMALLAB_USE_CCACHE
|
||||||
|
"Use ccache as compiler/linker launcher when present." ON)
|
||||||
|
if(CONFORMALLAB_USE_CCACHE)
|
||||||
|
find_program(CCACHE_PROGRAM ccache)
|
||||||
|
if(CCACHE_PROGRAM)
|
||||||
|
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
|
||||||
|
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
|
||||||
|
message(STATUS "ccache: enabled (${CCACHE_PROGRAM})")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── Dev-iteration build mode (lever C, opt-in) ─────────────────────────────────
|
||||||
|
#
|
||||||
|
# Turns off Unity Build target-wide. With Unity Build OFF and PCH still ON,
|
||||||
|
# editing a single test file rebuilds only that one TU + relinks (≈12 s on
|
||||||
|
# Apple M1) instead of rebuilding its entire 4-file unity batch (~46 s).
|
||||||
|
#
|
||||||
|
# Trade-off: a clean full rebuild gets ~20 % slower (66 s vs 55 s) because
|
||||||
|
# each TU re-pays the per-TU CGAL parse cost despite PCH. Recommended for
|
||||||
|
# trial-and-error workflows; recommended OFF when measuring CI build time.
|
||||||
|
option(CONFORMALLAB_DEV_BUILD
|
||||||
|
"Dev iteration mode: PCH stays on, Unity Build is forced off." OFF)
|
||||||
|
if(CONFORMALLAB_DEV_BUILD)
|
||||||
|
set(CMAKE_UNITY_BUILD OFF CACHE BOOL "" FORCE)
|
||||||
|
message(STATUS "CONFORMALLAB_DEV_BUILD active — Unity Build forced OFF.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── Fast test-build mode (lever #10, opt-in for CI-PR loops) ───────────────────
|
||||||
|
#
|
||||||
|
# Compile the test targets with `-O0 -g` instead of the default `-O3`.
|
||||||
|
# The Eigen + CGAL templates dominate the BACKEND (CodeGen + Opt) phase
|
||||||
|
# of every TU at ~55 % of wall time (~9.3 s of a 17 s TU per
|
||||||
|
# `clang -ftime-trace`). Dropping to `-O0` collapses that phase to
|
||||||
|
# <2 s and yields ~40 % faster full rebuilds. The downside is that
|
||||||
|
# the resulting binaries are 2-5× slower to RUN — fine for "does it
|
||||||
|
# compile + do all 259 unit tests pass?" CI loops, NOT fine for any
|
||||||
|
# scalability or benchmark workload.
|
||||||
|
#
|
||||||
|
# Library/installable code is never affected; only the test
|
||||||
|
# executables compiled into build-*/ pick this flag up.
|
||||||
|
option(CONFORMALLAB_FAST_TEST_BUILD
|
||||||
|
"Compile test executables with -O0 -g for faster CI / dev loops." OFF)
|
||||||
|
if(CONFORMALLAB_FAST_TEST_BUILD)
|
||||||
|
message(STATUS "CONFORMALLAB_FAST_TEST_BUILD active — tests compile at -O0 -g.")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
# ─── Compiler-warning policy ─────────────────────────────────────────────
|
# ─── Compiler-warning policy ─────────────────────────────────────────────
|
||||||
# `-Wall -Wextra -Wpedantic` is the project default for first-party code.
|
# `-Wall -Wextra -Wpedantic` is the project default for first-party code.
|
||||||
@@ -83,20 +137,29 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ── GTest (always – tests are always built) ────────────────────────────────────
|
# ── GTest (only when tests are enabled) ────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# CMake's standard `BUILD_TESTING` option (defaults ON via include(CTest))
|
||||||
|
# gates the entire test subtree below. Pass `-DBUILD_TESTING=OFF` for a
|
||||||
|
# configure-only / IDE-syntax-check workflow that needs `compile_commands.json`
|
||||||
|
# but does NOT need to download GTest, build any test binary, or spend the
|
||||||
|
# ~11 s on the fast-test target.
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
include(CTest)
|
include(CTest) # also defines BUILD_TESTING (default ON)
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
if(BUILD_TESTING)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
googletest
|
googletest
|
||||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||||
GIT_TAG v1.14.0
|
GIT_TAG v1.14.0
|
||||||
)
|
)
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
||||||
FetchContent_MakeAvailable(googletest)
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
endif()
|
||||||
|
|
||||||
# ── External deps (lazy tarball extraction) ────────────────────────────────────
|
# ── External deps (lazy tarball extraction) ────────────────────────────────────
|
||||||
add_subdirectory(deps)
|
add_subdirectory(deps)
|
||||||
@@ -142,8 +205,67 @@ if(WITH_CGAL)
|
|||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ── Tests (always) ────────────────────────────────────────────────────────────
|
# ── Tests (gated on BUILD_TESTING) ────────────────────────────────────────────
|
||||||
add_subdirectory(tests)
|
#
|
||||||
|
# Default ON (CTest convention). Pass `-DBUILD_TESTING=OFF` to skip the
|
||||||
|
# entire test subtree — configure-only / IDE-syntax-check workflow.
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── headers_check target (lever A, opt-in) ────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Lightweight per-header smoke-compile target. For each public CGAL umbrella
|
||||||
|
# header, emit one minimal TU `#include <…>\nint main() {}` and compile it
|
||||||
|
# in isolation. Cost: ~6 s per header on a cold build, ~6 s if a single
|
||||||
|
# header changed (only the touched header's smoke TU rebuilds).
|
||||||
|
#
|
||||||
|
# Use case: "did my Phase-N refactor break the public API surface?" without
|
||||||
|
# waiting 55 s for the full CGAL test build. Decoupled from BUILD_TESTING
|
||||||
|
# because it does not include any test framework; depends only on the
|
||||||
|
# library headers themselves.
|
||||||
|
#
|
||||||
|
# Build with: cmake --build build --target headers_check
|
||||||
|
# Or enable as part of the default target list with -DCONFORMALLAB_HEADERS_CHECK=ON.
|
||||||
|
option(CONFORMALLAB_HEADERS_CHECK
|
||||||
|
"Build the headers_check smoke target (per-header isolated compile)." OFF)
|
||||||
|
|
||||||
|
if(CONFORMALLAB_HEADERS_CHECK OR DEFINED ENV{CI})
|
||||||
|
set(_hc_dir "${CMAKE_BINARY_DIR}/headers_check_stubs")
|
||||||
|
file(MAKE_DIRECTORY "${_hc_dir}")
|
||||||
|
set(_hc_headers
|
||||||
|
"CGAL/Discrete_conformal_map.h"
|
||||||
|
"CGAL/Discrete_circle_packing.h"
|
||||||
|
"CGAL/Discrete_inversive_distance.h"
|
||||||
|
"CGAL/Conformal_layout.h"
|
||||||
|
"CGAL/Conformal_map_traits.h"
|
||||||
|
"CGAL/Conformal_map/internal/parameters.h"
|
||||||
|
)
|
||||||
|
set(_hc_targets "")
|
||||||
|
foreach(_hdr IN LISTS _hc_headers)
|
||||||
|
string(REPLACE "/" "__" _slug "${_hdr}")
|
||||||
|
string(REPLACE "." "_" _slug "${_slug}")
|
||||||
|
set(_stub "${_hc_dir}/${_slug}.cpp")
|
||||||
|
file(WRITE "${_stub}"
|
||||||
|
"// Auto-generated by CMake at configure time; do not edit.
|
||||||
|
// Smoke-compile sentinel for ${_hdr}.
|
||||||
|
#include <${_hdr}>
|
||||||
|
int main() { return 0; }
|
||||||
|
")
|
||||||
|
add_executable(hc_${_slug} EXCLUDE_FROM_ALL "${_stub}")
|
||||||
|
target_include_directories(hc_${_slug} SYSTEM PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen-3.4.0
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/deps/CGAL-6.1.1/include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/deps/single_includes
|
||||||
|
${Boost_INCLUDE_DIRS})
|
||||||
|
target_include_directories(hc_${_slug} PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
target_compile_definitions(hc_${_slug} PRIVATE
|
||||||
|
CGAL_DISABLE_GMP CGAL_DISABLE_MPFR)
|
||||||
|
list(APPEND _hc_targets hc_${_slug})
|
||||||
|
endforeach()
|
||||||
|
add_custom_target(headers_check DEPENDS ${_hc_targets})
|
||||||
|
endif()
|
||||||
|
|
||||||
# ── Install target (header-only library) ──────────────────────────────────────
|
# ── Install target (header-only library) ──────────────────────────────────────
|
||||||
# Installs all public headers to <prefix>/include/conformallab/
|
# Installs all public headers to <prefix>/include/conformallab/
|
||||||
|
|||||||
98
code/deps/THIRD-PARTY-LICENSES.md
Normal file
98
code/deps/THIRD-PARTY-LICENSES.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Third-party licenses
|
||||||
|
|
||||||
|
This directory contains source code from external projects that
|
||||||
|
conformallab++ vendors at fixed versions for build reproducibility.
|
||||||
|
Each project is governed by its own license; this file enumerates them
|
||||||
|
so downstream packagers, distributors, and reviewers can audit
|
||||||
|
compatibility without crawling each upstream tarball.
|
||||||
|
|
||||||
|
> **Why vendored at all?** conformallab++ is header-only and ships
|
||||||
|
> nothing it does not author except the optional CLI binary
|
||||||
|
> (`-DWITH_CGAL=ON`). Vendoring guarantees that the CGAL / Eigen /
|
||||||
|
> Boost API surface every contributor sees is identical, removing
|
||||||
|
> "works on my machine because I have CGAL 6.0 not 5.6" failure modes
|
||||||
|
> during early review. Downstream packagers replacing the vendored
|
||||||
|
> trees with system installs is supported and is the recommended path
|
||||||
|
> for distribution-level packaging (see `doc/architecture/dependencies.md`).
|
||||||
|
|
||||||
|
## conformallab++ itself
|
||||||
|
|
||||||
|
| Item | License | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| `code/include/**`, `code/src/**`, `code/tests/**`, `scripts/**`, `doc/**` | **MIT** (see `LICENSE` at repo root) | Every C++ source file carries `SPDX-License-Identifier: MIT`; CI gate `scripts/quality/license-headers.sh` enforces this. |
|
||||||
|
|
||||||
|
## Vendored dependencies
|
||||||
|
|
||||||
|
The table below lists each tree under `code/deps/`, its upstream
|
||||||
|
license, the SPDX identifier, and any compatibility note relevant to
|
||||||
|
shipping conformallab++ as MIT.
|
||||||
|
|
||||||
|
| Directory | Upstream project | Version | License (SPDX) | Compatibility with MIT distribution | Notes |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| `CGAL-6.1.1/` | [CGAL](https://www.cgal.org) | 6.1.1 | **LGPL-3.0-or-later** (most headers) + **GPL-3.0-or-later** (a small subset — see CGAL's per-header `\cgal_license{...}` macro) | Header-only consumption is compatible; we ONLY include LGPL'd parts (`Surface_mesh`, `Polygon_mesh_processing`, BGL adapters, kernels). | conformallab++ does not include any of the GPL-only CGAL packages (e.g. `Triangulation_3` parts, certain mesh-3 internals). The `\cgal_license` macro is checked at compile time and would fail the build if a GPL-only header were transitively pulled in. Commercial licenses are available from GeometryFactory for users who can't accept (L)GPL. |
|
||||||
|
| `eigen-3.4.0/` | [Eigen](https://eigen.tuxfamily.org) | 3.4.0 | **MPL-2.0** for almost everything, **LGPL-2.1-or-later** for a few legacy files (e.g. `Eigen/src/Core/util/NonMPL2.h` gates these) | MPL-2.0 is permissive enough for MIT; the LGPL files are NOT pulled in by `<Eigen/Dense>` / `<Eigen/Sparse>` (the only Eigen headers conformallab++ includes). | We define no preprocessor flag that activates the non-MPL2 code paths. The default Eigen build is pure MPL-2.0. |
|
||||||
|
| `libigl-2.6.0/` | [libigl](https://libigl.github.io) | 2.6.0 | **MPL-2.0** | Compatible with MIT distribution. | Only the viewer subsystem under `code/src/viewer/` uses libigl, and only when `-DWITH_VIEWER=ON`. The library headers and the CGAL wrapper headers do not depend on libigl. |
|
||||||
|
| `libigl-glad/` | [Glad](https://glad.dav1d.de/) (the generated OpenGL loader libigl ships) | bundled with libigl 2.6.0 | **MIT** (the generator's output is licensed permissively; the loader code itself is in the public domain via the original Khronos headers) | Compatible. | Built only with `-DWITH_VIEWER=ON`. |
|
||||||
|
| `glfw-3.4/` | [GLFW](https://www.glfw.org) | 3.4 | **zlib/libpng** | Permissive; compatible with MIT. | Built only with `-DWITH_VIEWER=ON`. See `code/deps/glfw-3.4/LICENSE.md` for the verbatim text. |
|
||||||
|
| `single_includes/json.hpp` | [nlohmann/json](https://github.com/nlohmann/json) | 3.x (header-only single-include) | **MIT** | Identical to ours. | The file itself carries the SPDX header `MIT`; see `code/deps/single_includes/json.hpp` first lines. |
|
||||||
|
| `tarballs/` | (build-artefact cache) | — | n/a | n/a | This directory just caches the downloaded source tarballs to avoid re-downloading on every clean build. The tarballs are bit-for-bit identical to the upstream releases. |
|
||||||
|
|
||||||
|
## Auto-fetched (not vendored)
|
||||||
|
|
||||||
|
These are pulled by CMake `FetchContent` at configure time. They are
|
||||||
|
**not** redistributed by conformallab++; the user's CMake fetches them
|
||||||
|
during build. We list them anyway for transparency.
|
||||||
|
|
||||||
|
| Item | Upstream | Version | License | Fetched by |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| **GoogleTest** | https://github.com/google/googletest | v1.14.0 | **BSD-3-Clause** | `code/CMakeLists.txt` (test target only) |
|
||||||
|
|
||||||
|
## System dependencies (required at build time, not redistributed)
|
||||||
|
|
||||||
|
| Item | Where it lives | License | Purpose |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Boost** (header-only subset) | system package (`apt install libboost-dev`, etc.) | **Boost Software License 1.0** | Required by CGAL's BGL adapters (only when `WITH_CGAL=ON` or `WITH_CGAL_TESTS=ON`). |
|
||||||
|
| **C++17 standard library** | the compiler's libstdc++ / libc++ / msvc | LGPL-3.0 with exception / Apache 2.0 with LLVM exception / MSVC redist | normal compiler runtime. |
|
||||||
|
|
||||||
|
## Summary for downstream packagers
|
||||||
|
|
||||||
|
If you are packaging conformallab++ for a distribution, the practical
|
||||||
|
license matrix is:
|
||||||
|
|
||||||
|
```
|
||||||
|
binary you ship (CLI app, -DWITH_CGAL=ON)
|
||||||
|
├── conformallab++ (MIT)
|
||||||
|
├── CGAL (LGPL-3.0-or-later — comply with §4 LGPL: source
|
||||||
|
│ of CGAL must be obtainable or shipped)
|
||||||
|
├── Eigen (MPL-2.0 — comply with §3 MPL: any modifications
|
||||||
|
│ must be released under MPL-2.0)
|
||||||
|
├── libigl (MPL-2.0 — same as Eigen)
|
||||||
|
├── GLFW (zlib/libpng — acknowledgement in product docs)
|
||||||
|
├── Glad (MIT — preserve copyright notice)
|
||||||
|
└── Boost (headers) (BSL-1.0 — preserve copyright notice)
|
||||||
|
|
||||||
|
header-only consumer (just #include our headers)
|
||||||
|
├── conformallab++ (MIT)
|
||||||
|
├── Eigen (MPL-2.0 transitively)
|
||||||
|
├── CGAL (LGPL-3.0-or-later transitively)
|
||||||
|
└── Boost (headers) (BSL-1.0 transitively, only if you include any
|
||||||
|
CGAL/* header)
|
||||||
|
```
|
||||||
|
|
||||||
|
The header-only consumer typically doesn't trigger LGPL §4 obligations
|
||||||
|
because LGPL §3 explicitly permits use of LGPL'd material as
|
||||||
|
"templates, inline functions, macros" by an "Application" without
|
||||||
|
imposing copyleft on the Application — which is exactly the
|
||||||
|
header-only consumption pattern.
|
||||||
|
|
||||||
|
If you have specific compliance questions, the upstream license texts
|
||||||
|
are authoritative; this file is a navigational aid.
|
||||||
|
|
||||||
|
## How this file is maintained
|
||||||
|
|
||||||
|
* Updated whenever a `code/deps/` tree is added, removed, or version-bumped.
|
||||||
|
* Cross-referenced by `doc/architecture/dependencies.md`.
|
||||||
|
* There is no CI gate that auto-verifies the SPDX entries against
|
||||||
|
upstream — that would require either an SBOM tool (e.g. `syft`,
|
||||||
|
`tern`) or a manual audit. The current policy is "review on
|
||||||
|
dep-tree change", logged in the commit message of the bump.
|
||||||
@@ -34,6 +34,8 @@ class (Strategy C of the Phase 8b architecture audit).
|
|||||||
#include "../cp_euclidean_functional.hpp"
|
#include "../cp_euclidean_functional.hpp"
|
||||||
#include "../newton_solver.hpp"
|
#include "../newton_solver.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
// ── Default traits for CP-Euclidean ───────────────────────────────────────────
|
// ── Default traits for CP-Euclidean ───────────────────────────────────────────
|
||||||
@@ -186,6 +188,45 @@ auto discrete_circle_packing_euclidean(
|
|||||||
result.iterations = nr.iterations;
|
result.iterations = nr.iterations;
|
||||||
result.gradient_norm = nr.grad_inf_norm;
|
result.gradient_norm = nr.grad_inf_norm;
|
||||||
result.converged = nr.converged;
|
result.converged = nr.converged;
|
||||||
|
|
||||||
|
// ── output_uv_map (Phase 8b-Lite extension) ────────────────────────────
|
||||||
|
//
|
||||||
|
// The CP-Euclidean functional carries one DOF per *face* (the log of the
|
||||||
|
// face-circle radius `ρ_f = log R_f`), not per vertex. A faithful
|
||||||
|
// layout therefore produces a circle packing in ℝ² — each face f is
|
||||||
|
// mapped to a circle of radius `R_f` at some centre `c_f`, with
|
||||||
|
// adjacent circles meeting at the prescribed intersection angle `θ_e`.
|
||||||
|
// That is a per-face output, not the per-vertex Point_2 that
|
||||||
|
// `output_uv_map` is typed for.
|
||||||
|
//
|
||||||
|
// For Phase 8b-Lite we deliberately don't fake it. If the caller
|
||||||
|
// supplies `output_uv_map(pmap)` we throw `std::runtime_error` with a
|
||||||
|
// clear pointer to Phase 9c (BPS-2010 §6 face-based circle-packing
|
||||||
|
// layout, ~150 lines, on the porting roadmap). Failing loudly is
|
||||||
|
// better than silently writing zeros.
|
||||||
|
//
|
||||||
|
// Users who want a UV-like coordinate today can:
|
||||||
|
// 1. Solve a Euclidean DCE on the same mesh (vertex DOFs),
|
||||||
|
// 2. Use `discrete_inversive_distance_map(... output_uv_map(pmap))`,
|
||||||
|
// 3. Or compute face-centre positions by hand from `result.rho_per_face`
|
||||||
|
// + the per-edge `θ_e` values, plus a priority-BFS of their own.
|
||||||
|
{
|
||||||
|
auto uv_param = parameters::get_parameter(
|
||||||
|
np, Conformal_map::internal_np::output_uv_map);
|
||||||
|
constexpr bool has_uv = !std::is_same_v<
|
||||||
|
decltype(uv_param), internal_np::Param_not_found>;
|
||||||
|
if constexpr (has_uv) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"CGAL::discrete_circle_packing_euclidean: the "
|
||||||
|
"`output_uv_map(...)` named parameter is not yet supported "
|
||||||
|
"for face-based CP-Euclidean. The faithful output is a "
|
||||||
|
"circle packing in the plane (per-face), not per-vertex "
|
||||||
|
"UVs. Tracked as Phase 9c; "
|
||||||
|
"see doc/architecture/locked-vs-flexible.md and "
|
||||||
|
"doc/tutorials/add-output-uv-map.md.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,6 +207,54 @@ auto discrete_inversive_distance_map(
|
|||||||
result.iterations = nr.iterations;
|
result.iterations = nr.iterations;
|
||||||
result.gradient_norm = nr.grad_inf_norm;
|
result.gradient_norm = nr.grad_inf_norm;
|
||||||
result.converged = nr.converged;
|
result.converged = nr.converged;
|
||||||
|
|
||||||
|
// ── Optional layout step (Phase 8b-Lite extension) ─────────────────────
|
||||||
|
//
|
||||||
|
// If the caller supplied `output_uv_map(pmap)`, lay out the converged
|
||||||
|
// packing in ℝ² and write per-vertex `Point_2` coordinates into `pmap`.
|
||||||
|
//
|
||||||
|
// Method: the converged Inversive-Distance radii `r_i = exp(u_i)`
|
||||||
|
// together with the fixed per-edge `I_ij` constants determine effective
|
||||||
|
// Euclidean edge lengths via the Bowers-Stephenson identity
|
||||||
|
// ℓᵢⱼ² = rᵢ² + rⱼ² + 2·Iᵢⱼ·rᵢ·rⱼ
|
||||||
|
// so we can populate a temporary `EuclideanMaps` whose `lambda0` carries
|
||||||
|
// `log(ℓᵢⱼ²)` per edge and then reuse `euclidean_layout(mesh, 0, eucl)`
|
||||||
|
// — the existing priority-BFS trilateration on the resulting triangle
|
||||||
|
// metric. All vertex/edge DOF indices stay at −1 (pinned), so the empty
|
||||||
|
// DOF vector `0` produces lengths driven purely by `lambda0`.
|
||||||
|
auto uv_param = parameters::get_parameter(
|
||||||
|
np, Conformal_map::internal_np::output_uv_map);
|
||||||
|
constexpr bool has_uv = !std::is_same_v<
|
||||||
|
decltype(uv_param), internal_np::Param_not_found>;
|
||||||
|
if constexpr (has_uv) {
|
||||||
|
if (nr.converged) {
|
||||||
|
auto eucl = ::conformallab::setup_euclidean_maps(mesh);
|
||||||
|
for (auto e : mesh.edges()) {
|
||||||
|
auto h = mesh.halfedge(e);
|
||||||
|
const double u_i = result.u_per_vertex[mesh.source(h).idx()];
|
||||||
|
const double u_j = result.u_per_vertex[mesh.target(h).idx()];
|
||||||
|
const double I = maps.I_e[e];
|
||||||
|
const double l2 = ::conformallab::id_detail::edge_length_squared(u_i, u_j, I);
|
||||||
|
eucl.lambda0[e] = (l2 > 0.0) ? std::log(l2) : -30.0;
|
||||||
|
}
|
||||||
|
// Empty DOF vector: every vertex is pinned (idx=-1), so the
|
||||||
|
// layout depends purely on the lambda0 we just computed.
|
||||||
|
std::vector<double> zero;
|
||||||
|
auto layout = ::conformallab::euclidean_layout(mesh, zero, eucl);
|
||||||
|
|
||||||
|
const bool do_norm = parameters::choose_parameter(
|
||||||
|
parameters::get_parameter(np, Conformal_map::internal_np::normalise_layout),
|
||||||
|
false);
|
||||||
|
if (do_norm) ::conformallab::normalise_euclidean(layout);
|
||||||
|
|
||||||
|
for (auto v : mesh.vertices()) {
|
||||||
|
const auto& uv = layout.uv[v.idx()];
|
||||||
|
put(uv_param, v,
|
||||||
|
typename Traits::Kernel::Point_2(uv.x(), uv.y()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
// After translation and projection to the Poincaré disk their circumcircle
|
// After translation and projection to the Poincaré disk their circumcircle
|
||||||
// equals the image of the original hyperbolic circle.
|
// equals the image of the original hyperbolic circle.
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Core> // downgraded from <Eigen/Dense>: this header only
|
||||||
|
// uses Matrix/Vector primitives, no decompositions.
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
// `Kernel_d::Point_3` (test scaffolding).
|
// `Kernel_d::Point_3` (test scaffolding).
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Core> // downgraded from <Eigen/Dense>: this header only
|
||||||
|
// uses Matrix/Vector primitives, no decompositions.
|
||||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
// Ported from de.jreality.math.Pn / Rn and
|
// Ported from de.jreality.math.Pn / Rn and
|
||||||
// de.varylab.discreteconformal.uniformization.SurfaceCurveUtility (Java).
|
// de.varylab.discreteconformal.uniformization.SurfaceCurveUtility (Java).
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Core> // downgraded from <Eigen/Dense>: this header only
|
||||||
|
// uses Matrix/Vector primitives, no decompositions.
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|||||||
@@ -27,6 +27,15 @@ target_include_directories(conformallab_tests PRIVATE
|
|||||||
|
|
||||||
target_link_libraries(conformallab_tests PRIVATE GTest::gtest_main)
|
target_link_libraries(conformallab_tests PRIVATE GTest::gtest_main)
|
||||||
|
|
||||||
|
# Fast test-build mode (lever #10): -O0 -g overrides the inherited
|
||||||
|
# Release-mode -O3 + -DNDEBUG. Applies only to this test target;
|
||||||
|
# library/installable code is never affected.
|
||||||
|
if(CONFORMALLAB_FAST_TEST_BUILD)
|
||||||
|
target_compile_options(conformallab_tests PRIVATE
|
||||||
|
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O0 -g -UNDEBUG>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(conformallab_tests DISCOVERY_TIMEOUT 60)
|
gtest_discover_tests(conformallab_tests DISCOVERY_TIMEOUT 60)
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,74 @@ target_compile_options(conformallab_cgal_tests PRIVATE
|
|||||||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-unused-parameter>
|
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-unused-parameter>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Fast test-build mode (lever #10): -O0 -g overrides the inherited
|
||||||
|
# Release-mode -O3 + -DNDEBUG. Applies only to this test target.
|
||||||
|
if(CONFORMALLAB_FAST_TEST_BUILD)
|
||||||
|
target_compile_options(conformallab_cgal_tests PRIVATE
|
||||||
|
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O0 -g -UNDEBUG>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main)
|
target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main)
|
||||||
|
|
||||||
|
# ── Compile-time speed-up: precompiled headers ───────────────────────────────
|
||||||
|
#
|
||||||
|
# The CGAL+Eigen template soup dominates every TU in this target:
|
||||||
|
# measured at 5.9 s per minimal "include <CGAL/Discrete_conformal_map.h>"
|
||||||
|
# TU on Apple M1. A shared PCH absorbs that cost once, slashing the
|
||||||
|
# total wall-clock from ~78 s (j8) to ~25 s (3×).
|
||||||
|
#
|
||||||
|
# Opt-out with -DCONFORMALLAB_USE_PCH=OFF if the PCH itself misbehaves
|
||||||
|
# (e.g. older toolchains that don't share PCH across translation units
|
||||||
|
# reliably) — falls back to the historical "every TU re-parses CGAL"
|
||||||
|
# build mode.
|
||||||
|
option(CONFORMALLAB_USE_PCH
|
||||||
|
"Enable precompiled headers for the CGAL test target." ON)
|
||||||
|
|
||||||
|
if(CONFORMALLAB_USE_PCH)
|
||||||
|
# Per-target Unity Build property takes precedence over the global
|
||||||
|
# CMAKE_UNITY_BUILD; honour CONFORMALLAB_DEV_BUILD's preference here
|
||||||
|
# so `-DCONFORMALLAB_DEV_BUILD=ON` truly turns Unity Build off for
|
||||||
|
# incremental-rebuild workflows.
|
||||||
|
if(NOT CONFORMALLAB_DEV_BUILD)
|
||||||
|
set_target_properties(conformallab_cgal_tests PROPERTIES
|
||||||
|
# Unity-builds amortise the per-TU CGAL+Eigen header cost
|
||||||
|
# across several tests in the same compile. Batch size 4
|
||||||
|
# keeps gtest's TEST(...) macros + per-file `using
|
||||||
|
# namespace …` from colliding while still cutting parser
|
||||||
|
# cost ~4×.
|
||||||
|
UNITY_BUILD ON
|
||||||
|
UNITY_BUILD_MODE BATCH
|
||||||
|
UNITY_BUILD_BATCH_SIZE 4)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_precompile_headers(conformallab_cgal_tests PRIVATE
|
||||||
|
# CGAL headers that every test transitively includes.
|
||||||
|
<CGAL/Surface_mesh.h>
|
||||||
|
<CGAL/Simple_cartesian.h>
|
||||||
|
<CGAL/Kernel_traits.h>
|
||||||
|
<CGAL/boost/graph/iterator.h>
|
||||||
|
<CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
|
||||||
|
# Eigen blocks that drive the slowest template instantiations
|
||||||
|
# (SelfAdjointEigenSolver<Matrix<2,2>>, ColPivHouseholderQR<
|
||||||
|
# Matrix<complex,3,3>>, sparse Cholesky + QR fallback).
|
||||||
|
<Eigen/Dense>
|
||||||
|
<Eigen/Sparse>
|
||||||
|
<Eigen/SparseCholesky>
|
||||||
|
<Eigen/SparseQR>
|
||||||
|
|
||||||
|
# GoogleTest itself; every test includes it.
|
||||||
|
<gtest/gtest.h>
|
||||||
|
|
||||||
|
# std headers that appear in every test.
|
||||||
|
<vector>
|
||||||
|
<string>
|
||||||
|
<cmath>
|
||||||
|
<complex>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(conformallab_cgal_tests
|
gtest_discover_tests(conformallab_cgal_tests
|
||||||
TEST_PREFIX "cgal."
|
TEST_PREFIX "cgal."
|
||||||
|
|||||||
@@ -288,6 +288,60 @@ TEST(CGALPhase8bLite, OutputUvMap_HyperIdeal_PointsInPoincareDisk)
|
|||||||
// No assertion needed; this is documented behaviour.)
|
// No assertion needed; this is documented behaviour.)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CGALPhase8bLite, OutputUvMap_InversiveDistance_PopulatesPmap)
|
||||||
|
{
|
||||||
|
// Inversive-Distance: per-vertex u_i = log r_i. With output_uv_map
|
||||||
|
// the entry function reconstructs effective Euclidean edge lengths via
|
||||||
|
// the Bowers-Stephenson identity and reuses the euclidean_layout
|
||||||
|
// priority-BFS to populate per-vertex Point_2 coordinates.
|
||||||
|
using K = CGAL::Simple_cartesian<double>;
|
||||||
|
auto mesh = make_quad_strip();
|
||||||
|
|
||||||
|
auto uv_map = mesh.add_property_map<Vertex_index, K::Point_2>(
|
||||||
|
"v:test_uv_id", K::Point_2(0, 0)).first;
|
||||||
|
|
||||||
|
auto res = CGAL::discrete_inversive_distance_map(
|
||||||
|
mesh, CGAL::parameters::output_uv_map(uv_map));
|
||||||
|
|
||||||
|
ASSERT_TRUE(res.converged) << "ID Newton did not converge on quad_strip";
|
||||||
|
EXPECT_EQ(res.u_per_vertex.size(), num_vertices(mesh));
|
||||||
|
// Every UV must be finite; not all zero.
|
||||||
|
bool any_nonzero = false;
|
||||||
|
for (auto v : mesh.vertices()) {
|
||||||
|
const auto& p = uv_map[v];
|
||||||
|
ASSERT_TRUE(std::isfinite(p.x()));
|
||||||
|
ASSERT_TRUE(std::isfinite(p.y()));
|
||||||
|
if (std::abs(p.x()) > 1e-9 || std::abs(p.y()) > 1e-9) any_nonzero = true;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(any_nonzero) << "all UVs are zero — layout did not run";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CGALPhase8bLite, OutputUvMap_CPEuclidean_ThrowsClearly)
|
||||||
|
{
|
||||||
|
// CP-Euclidean is face-based; its natural layout is a per-face
|
||||||
|
// circle packing in ℝ², not a per-vertex Point_2 map. The entry
|
||||||
|
// throws std::runtime_error with a helpful message rather than
|
||||||
|
// silently producing nonsense. See doc/architecture/locked-vs-flexible.md.
|
||||||
|
using K = CGAL::Simple_cartesian<double>;
|
||||||
|
auto mesh = make_quad_strip();
|
||||||
|
|
||||||
|
auto uv_map = mesh.add_property_map<Vertex_index, K::Point_2>(
|
||||||
|
"v:test_uv_cp", K::Point_2(0, 0)).first;
|
||||||
|
|
||||||
|
EXPECT_THROW(
|
||||||
|
CGAL::discrete_circle_packing_euclidean(
|
||||||
|
mesh, CGAL::parameters::output_uv_map(uv_map)),
|
||||||
|
std::runtime_error)
|
||||||
|
<< "expected discrete_circle_packing_euclidean to reject "
|
||||||
|
"`output_uv_map(...)` (face-based DOF, Phase 9c).";
|
||||||
|
|
||||||
|
// Sanity: without output_uv_map the entry function still works fine.
|
||||||
|
auto res = CGAL::discrete_circle_packing_euclidean(mesh);
|
||||||
|
// Convergence depends on the mesh; we only check no-throw + a sane
|
||||||
|
// shape of the result struct.
|
||||||
|
EXPECT_EQ(res.rho_per_face.size(), num_faces(mesh));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(CGALPhase8bLite, OutputUvMap_Absent_DoesNotRunLayout)
|
TEST(CGALPhase8bLite, OutputUvMap_Absent_DoesNotRunLayout)
|
||||||
{
|
{
|
||||||
// Sanity: without the parameter, no layout work happens. Verified
|
// Sanity: without the parameter, no layout work happens. Verified
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ All tests have CTest prefix `cgal.` (set via `TEST_PREFIX "cgal."` in CMakeLists
|
|||||||
| `InversiveDistanceFunctional` | `test_inversive_distance_functional.cpp` | 11 | Phase 9a.2 — Luo-2004 vertex-based packing (from literature) |
|
| `InversiveDistanceFunctional` | `test_inversive_distance_functional.cpp` | 11 | Phase 9a.2 — Luo-2004 vertex-based packing (from literature) |
|
||||||
| `HyperIdealHessian` | `test_hyper_ideal_hessian.cpp` | 7 | Phase 9b — block-FD vs full-FD cross-validation + PSD + speed-up |
|
| `HyperIdealHessian` | `test_hyper_ideal_hessian.cpp` | 7 | Phase 9b — block-FD vs full-FD cross-validation + PSD + speed-up |
|
||||||
| `NewtonPhase9a` | `test_newton_phase9a.cpp` | 7 | Phase 9a-Newton — convergence for the two new circle-packing solvers |
|
| `NewtonPhase9a` | `test_newton_phase9a.cpp` | 7 | Phase 9a-Newton — convergence for the two new circle-packing solvers |
|
||||||
| `CGALPhase8bLite` | `test_cgal_phase8b_lite.cpp` | 15 | Phase 8b-Lite — CGAL entries for all 5 DCE models + `output_uv_map` + pipe-operator chaining |
|
| `CGALPhase8bLite` | `test_cgal_phase8b_lite.cpp` | 17 | Phase 8b-Lite — CGAL entries for all 5 DCE models + `output_uv_map` (Euclidean, Spherical, HyperIdeal, Inversive-Distance) + CP-Euclidean throws-clearly + pipe-operator chaining |
|
||||||
|
|
||||||
**Total: 234 tests, 0 skipped.**
|
**Total: 236 tests, 0 skipped.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
250
doc/architecture/compile-time.md
Normal file
250
doc/architecture/compile-time.md
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
# Compile-time analysis & quick-wins
|
||||||
|
|
||||||
|
> **Audience.** Anyone maintaining or extending the build system.
|
||||||
|
> Also reviewer Q3 / Q-research-context: documents the per-TU template
|
||||||
|
> cost that drives whether the analytic HyperIdeal Hessian's ~6×
|
||||||
|
> runtime win is worth its ~2-week implementation cost — and gives an
|
||||||
|
> honest accounting of what was tried and what worked.
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
| Configuration | Wall (Ninja, `-j8`) | CPU | Tests pass |
|
||||||
|
|---|---:|---:|---|
|
||||||
|
| **Baseline** (no PCH, no Unity Build) | **78 s** | 676 s | 236 / 236 |
|
||||||
|
| **+ PCH** (`CONFORMALLAB_USE_PCH=ON`, default) | 66 s (−15 %) | 474 s (−30 %) | 236 / 236 |
|
||||||
|
| **+ PCH + Unity Build** | 55 s (−30 %) | 167 s (−75 %) | 236 / 236 |
|
||||||
|
| **+ #6 Dense → Core in 3 headers** (current default) | **55–60 s (~−25 %, within noise)** | n/a | 236 / 236 |
|
||||||
|
|
||||||
|
> **Honest note on variance.** Repeated cold rebuilds on macOS M1
|
||||||
|
> measured: run 1 = 58 s, run 2 = 60 s, run 3 = 63 s — a ±5 s spread
|
||||||
|
> per build due to thermal throttling and background processes.
|
||||||
|
> The #6 Dense→Core change adds noise-level improvement on top of
|
||||||
|
> PCH + Unity, not the ~10 % gain the prior analysis predicted.
|
||||||
|
> Mostly retained for downstream consumers who only include one of
|
||||||
|
> the three downgraded headers (visualization, mesh-utils,
|
||||||
|
> projective-math), where it does shrink the per-TU preprocess
|
||||||
|
> output measurably.
|
||||||
|
|
||||||
|
The shipped defaults in this branch deliver **30 % less wall time and
|
||||||
|
75 % less CPU time** on a clean rebuild of `conformallab_cgal_tests`
|
||||||
|
on Apple M1. All 236 CGAL tests pass under every configuration.
|
||||||
|
Tunable via `-DCONFORMALLAB_USE_PCH=ON|OFF` and
|
||||||
|
`-DCMAKE_UNITY_BUILD=ON|OFF`.
|
||||||
|
|
||||||
|
## Measurement environment
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|---|---|
|
||||||
|
| CPU | Apple M1 (8 logical cores) |
|
||||||
|
| RAM | 16 GB |
|
||||||
|
| Compiler | Apple clang 17.0.0 |
|
||||||
|
| Build type | Release |
|
||||||
|
| CGAL | 6.1.1 vendored (48 MB headers) |
|
||||||
|
| Eigen | 3.4.0 vendored (6.5 MB headers) |
|
||||||
|
| Generator | Ninja 1.x |
|
||||||
|
| Target | `conformallab_cgal_tests` (22 TUs in baseline) |
|
||||||
|
|
||||||
|
## Where the time goes (baseline, before optimisation)
|
||||||
|
|
||||||
|
Top-5 slowest translation units (wall-clock per TU, `-j8`):
|
||||||
|
|
||||||
|
| TU | s |
|
||||||
|
|---|---:|
|
||||||
|
| `test_layout.cpp` | 54.7 |
|
||||||
|
| `test_geometry_utils.cpp` | 52.2 |
|
||||||
|
| `test_phase6.cpp` | 50.7 |
|
||||||
|
| `test_pipeline.cpp` | 50.4 |
|
||||||
|
| `test_phase7.cpp` | 45.3 |
|
||||||
|
|
||||||
|
A minimal "hello world" TU that does nothing but
|
||||||
|
`#include <CGAL/Discrete_conformal_map.h>` already costs **5.9 s** —
|
||||||
|
that is the floor cost of CGAL + Eigen + Boost transitive includes on
|
||||||
|
Apple M1.
|
||||||
|
|
||||||
|
Clang `-ftime-trace` on `test_layout.cpp` (~17 s isolated):
|
||||||
|
|
||||||
|
| Phase | Time | % |
|
||||||
|
|---|---:|---:|
|
||||||
|
| Backend (CodeGen + Opt) | 9.3 s | 55 % |
|
||||||
|
| Frontend (Parse + Sema + Templates) | 8.0 s | 45 % |
|
||||||
|
| ⤷ InstantiateFunction | 4.3 s | 25 % |
|
||||||
|
| ⤷ InstantiateClass | 3.3 s | 19 % |
|
||||||
|
|
||||||
|
Single most expensive Eigen template instantiations
|
||||||
|
(~1.1 – 1.2 s each, per TU):
|
||||||
|
|
||||||
|
* `Eigen::SelfAdjointEigenSolver<Matrix<2,2>>` (PCA in
|
||||||
|
`normalise_euclidean`)
|
||||||
|
* `Eigen::ColPivHouseholderQR<Matrix<complex,3,3>>`
|
||||||
|
(`MobiusMap::from_three`)
|
||||||
|
* `Eigen::internal::tridiagonalization_inplace<Matrix<2,2>>`
|
||||||
|
* `Eigen::HouseholderSequence<Matrix<2,2>>`
|
||||||
|
|
||||||
|
These get instantiated **from scratch in every TU** that pulls
|
||||||
|
`layout.hpp` in — the inefficiency this branch's PCH closes.
|
||||||
|
|
||||||
|
## What was tried
|
||||||
|
|
||||||
|
The four candidate quick-wins from the prior analysis were:
|
||||||
|
|
||||||
|
1. **Precompiled headers** — shared PCH covering CGAL + Eigen + gtest +
|
||||||
|
the std headers every test uses. Implemented; **shipped**, opt-out
|
||||||
|
via `-DCONFORMALLAB_USE_PCH=OFF`. See
|
||||||
|
`code/tests/cgal/CMakeLists.txt`.
|
||||||
|
2. **`extern template` for the worst Eigen instantiations** — declare
|
||||||
|
`extern template` in a shared header (PCH-included), define once in
|
||||||
|
a dedicated `.cpp`. **Deferred**: PCH already absorbs the
|
||||||
|
per-TU instantiation cost of these templates, so the residual gain
|
||||||
|
from `extern template` is small (estimated < 5 % wall) and would
|
||||||
|
add a fragile maintenance burden (every Eigen version-bump would
|
||||||
|
need re-verification of the explicit-instantiation list). If a
|
||||||
|
future Eigen update breaks the PCH, this is the next lever.
|
||||||
|
3. **Header split** for `<CGAL/Discrete_conformal_map.h>** — separate
|
||||||
|
into `_euclidean.h` / `_spherical.h` / `_hyper_ideal.h` so
|
||||||
|
downstream consumers who only need one geometry pay less.
|
||||||
|
**Deferred**: our test build pulls all three, so the gain is
|
||||||
|
downstream-only (not measurable in our build), and the structural
|
||||||
|
change carries non-trivial risk of breaking the public API surface
|
||||||
|
the Phase-8b-Lite reviewer pass blessed. Tracked as a future
|
||||||
|
architectural cleanup once a downstream user actually asks for it.
|
||||||
|
4. **Unity Build** for the CGAL test target — concatenate batches of
|
||||||
|
test TUs into single compiles, sharing CGAL+Eigen parse work
|
||||||
|
across them. Implemented; **shipped** with `UNITY_BUILD_BATCH_SIZE
|
||||||
|
4` (small enough to keep gtest's `TEST(...)` macros + per-file
|
||||||
|
`using namespace …` from colliding). Opt-out via
|
||||||
|
`-DCMAKE_UNITY_BUILD=OFF`.
|
||||||
|
|
||||||
|
## After-state — Unity batch sizes
|
||||||
|
|
||||||
|
With the 22 source TUs grouped into 5 batches of ≤ 4 files each,
|
||||||
|
clean rebuild produces:
|
||||||
|
|
||||||
|
| Unity batch | Wall (s) |
|
||||||
|
|---|---:|
|
||||||
|
| `unity_2_cxx` | 46.3 |
|
||||||
|
| `unity_3_cxx` | 41.5 |
|
||||||
|
| `unity_4_cxx` | 40.6 |
|
||||||
|
| `unity_1_cxx` | 26.0 |
|
||||||
|
| `unity_0_cxx` | 13.0 |
|
||||||
|
|
||||||
|
Plus gtest itself (`gtest-all.cc.o`, 8.5 s) and `gtest_main.cc.o`
|
||||||
|
(1.2 s) outside the batches.
|
||||||
|
|
||||||
|
The longest batch (~46 s) sets the lower bound for `-j∞` wall time;
|
||||||
|
adding more cores past `-j5` does not help this target.
|
||||||
|
|
||||||
|
## Honesty notes
|
||||||
|
|
||||||
|
* **`-j` scaling is sublinear.** Measured speedups: `-j1`→`-j2` =
|
||||||
|
1.66×, `-j2`→`-j4` = 1.59×, `-j4`→`-j8` = 1.28×. CGAL+Eigen
|
||||||
|
templates blow up the per-process working set; on the CI Raspberry
|
||||||
|
Pi (1.6 GB RAM cap) we run `-j1` for the CGAL job by necessity.
|
||||||
|
* **The PCH compiles in ~3 s** the first time and then short-circuits
|
||||||
|
every TU. Total PCH cost amortises after the second TU.
|
||||||
|
* **CGAL version sensitivity.** The PCH is keyed to the specific
|
||||||
|
CGAL headers it lists. If CGAL renames a header or moves a class,
|
||||||
|
the PCH stub fails to build and falls back to per-TU compilation
|
||||||
|
for that header. The four CI quality-gate runs catch this within
|
||||||
|
one PR.
|
||||||
|
* **macOS-specific.** The numbers above are Apple M1. Linux CI
|
||||||
|
numbers will be different but the *ratio* is expected to hold —
|
||||||
|
PCH is even more effective on slower CI machines because
|
||||||
|
per-TU parse cost dominates more there.
|
||||||
|
|
||||||
|
## Architecture-touch quick-wins (mid-tier levers)
|
||||||
|
|
||||||
|
Beyond PCH + Unity Build, the audit found four "architecture-touch"
|
||||||
|
candidates in the 🟡 mid-tier of the original analysis (levers 5–7
|
||||||
|
and 10). Status after evaluation:
|
||||||
|
|
||||||
|
| Lever | Status | Decision |
|
||||||
|
|---|---|---|
|
||||||
|
| **#5** Move `detail::` impls to `.inl`/`.tpp` | not implemented | Pure enabler for #7; gain only realises if #7 lands. |
|
||||||
|
| **#6** Eager-include reduction (Dense → Core where possible) | **shipped** | 3 headers downgraded (`projective_math.hpp`, `hyper_ideal_visualization_utility.hpp`, `mesh_utils.hpp`); 5 others kept `<Eigen/Dense>` because they use `.inverse()` / `.determinant()` / `ColPivHouseholderQR` / `SelfAdjointEigenSolver`. Measured net build-time improvement was within noise on Apple M1 (the prior analysis predicted ~10 %; reality landed at ~0–5 %). Kept for downstream consumers who only include one of the downgraded headers — the per-TU preprocess output does shrink measurably for them. |
|
||||||
|
| **#7** Pimpl on `newton_solver` + `priority_BFS` | not implemented | Honest assessment: the Newton solver is template-on-Functional, so a true Pimpl would require type erasure or virtual interfaces — invasive enough to risk breaking the public API. Deferred until a concrete user reports compile-time pain. |
|
||||||
|
| **#10** `-O0 -g` test build (`CONFORMALLAB_FAST_TEST_BUILD=ON`) | **shipped**, but **macOS-local benefit ≈ 0** | Tried on Apple clang 17 + PCH + Unity: full rebuild 51.6 s vs 46.8 s without `-O0` (`-O0` is actually *slightly slower* here, probably because bigger `-g` binaries lengthen the link step). Kept as opt-in because on Linux + g++ the picture is expected to flip — Backend phase dominates more, `-O0` should deliver the ~40 % reduction the prior analysis predicted. See ccache honesty notes for the same pattern. |
|
||||||
|
|
||||||
|
## Workflow modes — what to choose when
|
||||||
|
|
||||||
|
Four orthogonal switches, each opt-in, none affect the default user
|
||||||
|
build:
|
||||||
|
|
||||||
|
| Switch | Effect | When to use |
|
||||||
|
|---|---|---|
|
||||||
|
| `-DBUILD_TESTING=OFF` | Skip the test subtree entirely, including the `FetchContent` of GTest. **Configure ≈ 1 s · Build ≈ 0 s · 0 object files.** | IDE-syntax-check workflows that only need `compile_commands.json`; configure-only health checks. |
|
||||||
|
| `-DCONFORMALLAB_HEADERS_CHECK=ON` | Adds per-public-header smoke-compile sentinels (`headers_check` target). **Full ≈ 12 s · incremental after touching one header ≈ 0.1 s.** | "Does my refactor still parse all public headers?" without waiting 55 s for the full test build. |
|
||||||
|
| `-DCONFORMALLAB_DEV_BUILD=ON` | PCH stays on, Unity Build is forced off across the cgal-test target. Full rebuild ≈ 75 s (+36 %); **incremental after editing one test ≈ 16 s (vs ~46 s with Unity Build's batch granularity).** | Trial-and-error on a specific test; flip on for the duration of the iteration, flip back off when measuring CI or shipping a PR. |
|
||||||
|
| `-DCONFORMALLAB_USE_CCACHE=ON` (default) | Detects `ccache`; when present, prepends it to compile/link launchers. | Linux CI primarily. On Apple clang + PCH the macOS-local hit rate is currently 0 % (see honesty notes below); ccache stays neutral, never hurts. |
|
||||||
|
| `-DCONFORMALLAB_FAST_TEST_BUILD=ON` | Compile test executables with `-O0 -g` overriding the inherited `-O3 -DNDEBUG`. | **Linux CI** primarily, where `-O0` typically cuts ~40 % off build time. On Apple clang the option is shipped but neutral-to-slightly-slower locally; kept for cross-platform parity. Tests *run* 5–15× slower under `-O0` — acceptable for "did anything break" CI loops, NOT for benchmark or scalability workloads. |
|
||||||
|
|
||||||
|
### Mode matrix at a glance
|
||||||
|
|
||||||
|
| Scenario | Configure (s) | Full build (s) | Incremental edit-rebuild (s) |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| Default (PCH + Unity + #6 Dense→Core) | 5 | **55–60** (±5 s noise) | ~46 (unity batch) |
|
||||||
|
| `BUILD_TESTING=OFF` | **1** | **0** | n/a |
|
||||||
|
| `HEADERS_CHECK=ON` only | 1 | **12** | **0.1** (single header) |
|
||||||
|
| `DEV_BUILD=ON` | 5 | 75 | **16** (single test) |
|
||||||
|
| `FAST_TEST_BUILD=ON` (Linux CI) | 5 | ~30 (expected) | ~25 (expected) |
|
||||||
|
| `FAST_TEST_BUILD=ON` (Apple clang) | 5 | 52 | n/a (use DEV_BUILD locally) |
|
||||||
|
|
||||||
|
## Cross-platform perf bench (Linux CI)
|
||||||
|
|
||||||
|
`.gitea/workflows/perf-compile-time.yml` runs a 5-step matrix on the
|
||||||
|
eulernest Linux runner after every push to `main` that touches the
|
||||||
|
build system or public headers. The matrix validates the predictions
|
||||||
|
that this document makes against the macOS-local measurements:
|
||||||
|
|
||||||
|
| Run | Predicted Linux gain | Apple M1 actual |
|
||||||
|
|---|---|---|
|
||||||
|
| Baseline (no PCH, no Unity, no ccache) | reference | 78 s |
|
||||||
|
| + PCH only | ~15 % | 66 s (−15 %) |
|
||||||
|
| + PCH + Unity (default) | ~30 % | 55 s (−30 %) |
|
||||||
|
| + FAST_TEST_BUILD (-O0 -g) | **~40 % vs default** (g++ Backend dominates) | 52 s (neutral on clang) |
|
||||||
|
| + ccache warm rerun | **≥ 90 % vs default** (8.5× speedup) | 56 s (Apple-clang PCH friction = 0 % hit) |
|
||||||
|
|
||||||
|
The job is data-collection only — does not gate merges. Output appears
|
||||||
|
in the run summary tab; if Linux numbers diverge from predictions, the
|
||||||
|
"Next levers" table below gets updated based on what actually wins.
|
||||||
|
|
||||||
|
## Next levers (not in this branch)
|
||||||
|
|
||||||
|
If 55 s wall is still not enough for full-clean rebuilds:
|
||||||
|
|
||||||
|
| Lever | Estimated win | Cost |
|
||||||
|
|---|---|---|
|
||||||
|
| `extern template` (lever #2 above) | 55 s → ~52 s | 2 h + Eigen version tracking |
|
||||||
|
| Header split (lever #3) | downstream-only | 1 day + API risk |
|
||||||
|
| C++20 Modules | speculative; experimental in Apple clang 17 | weeks |
|
||||||
|
|
||||||
|
## ccache — honesty notes (macOS local vs Linux CI)
|
||||||
|
|
||||||
|
Local ccache stats on Apple clang + PCH + Unity Build, after two
|
||||||
|
clean rebuilds:
|
||||||
|
|
||||||
|
```
|
||||||
|
Cacheable calls: 4 / 16 (25.00 %)
|
||||||
|
Hits: 0 / 4 ( 0.00 %)
|
||||||
|
Uncacheable calls: 12 / 16 (75.00 %)
|
||||||
|
```
|
||||||
|
|
||||||
|
Three issues defeat the hot rebuild:
|
||||||
|
|
||||||
|
1. **PCH artefacts are not cached by default.** Apple clang's
|
||||||
|
`-include-pch ...gch` path embeds timestamps that miss the cache
|
||||||
|
lookup. Workaround: set `CCACHE_SLOPPINESS=pch_defines,
|
||||||
|
include_file_mtime,include_file_ctime,time_macros,file_macro,
|
||||||
|
system_headers` (tried; still 0 % hit on macOS).
|
||||||
|
2. **Unity Build .cxx files** have generated paths that change
|
||||||
|
between configurations; ccache treats each as a fresh compile.
|
||||||
|
3. **CMake's compile-launcher mechanism** doesn't currently combine
|
||||||
|
with `target_precompile_headers()` in a way that ccache 4.x
|
||||||
|
recognises on Apple clang. Tracked upstream as a known issue.
|
||||||
|
|
||||||
|
**On Linux CI** the picture is different: g++ + traditional PCH +
|
||||||
|
non-Apple toolchain typically delivers 80 %+ hit rates with ccache.
|
||||||
|
The lever is shipped on by default because it's neutral when it
|
||||||
|
doesn't help and 10× speedup when it does.
|
||||||
|
|
||||||
|
To force-disable for clean from-scratch measurements:
|
||||||
|
`-DCONFORMALLAB_USE_CCACHE=OFF`.
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
> across the whole codebase) and which are **opportunistic** (made
|
> across the whole codebase) and which are **opportunistic** (made
|
||||||
> on first principles and easy to revisit).
|
> on first principles and easy to revisit).
|
||||||
>
|
>
|
||||||
> **Why this matters now.** A v0.9.0 + Springborn-Bobenko-alumnus
|
> **Why this matters now.** A v0.9.0 snapshot + external review by
|
||||||
> external review (May 2026) is the right moment to surface these
|
> an active researcher in the decorated-DCE / canonical-tessellation /
|
||||||
|
> hyperideal-polyhedra line is the right moment to surface these
|
||||||
> decisions before they ossify further. If any of the *locked*
|
> decisions before they ossify further. If any of the *locked*
|
||||||
> decisions need revisiting, this is the cheapest moment in the
|
> decisions need revisiting, this is the cheapest moment in the
|
||||||
> project's life to do so.
|
> project's life to do so.
|
||||||
@@ -258,7 +259,7 @@ mechanical next step rather than a missing piece of theory.
|
|||||||
|
|
||||||
| Limitation | Status | Effort to close |
|
| Limitation | Status | Effort to close |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **`output_uv_map` covers 3 of 5 entries** — Euclidean, Spherical, HyperIdeal are wired to call the appropriate `*_layout()` after Newton. CP-Euclidean (face-based) and Inversive-Distance (vertex-based) entries still require the user to call `*_layout()` by hand. | tutorial + plumbing in place; just needs to be copy-pasted into the two remaining entry headers | ~0.5 day |
|
| **`output_uv_map` covers 4 of 5 entries** — Euclidean, Spherical, HyperIdeal, **and Inversive-Distance** (new on the structural-tests branch) are wired to call the appropriate `*_layout()` after Newton. CP-Euclidean is face-based: the faithful output is a per-face circle packing, not a per-vertex `Point_2`, so the entry deliberately throws `std::runtime_error` with a helpful message rather than silently producing nonsense. Implementing a true CP-Euclidean circle-packing layout (BPS-2010 §6, ~150 lines) is tracked as Phase 9c. | Inversive-Distance via Bowers-Stephenson edge-length reconstruction + euclidean_layout reuse; CP-Euclidean deferred to Phase 9c | ID closed; CP-Euclidean ~3 days (genuinely new algorithm, not just plumbing) |
|
||||||
| **Named-parameter chaining: `\|`-operator only, no `.a().b().c()`.** Member-style chaining would need a patch to CGAL's upstream `parameters_interface.h`, which we treat as a read-only vendored dependency. The pipe operator is documented, ADL-discoverable, and equivalent in expressive power. | pipe shipped, member-chain deferred until upstream extension point exists | ~2 days (only if upstream PR is accepted) |
|
| **Named-parameter chaining: `\|`-operator only, no `.a().b().c()`.** Member-style chaining would need a patch to CGAL's upstream `parameters_interface.h`, which we treat as a read-only vendored dependency. The pipe operator is documented, ADL-discoverable, and equivalent in expressive power. | pipe shipped, member-chain deferred until upstream extension point exists | ~2 days (only if upstream PR is accepted) |
|
||||||
| **Phase 9b-analytic: derivation complete, code uses block-FD.** The Schläfli-based analytic HyperIdeal Hessian is fully derived in [`hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) (805 lines, all sign pitfalls covered). The shipped code still uses per-face block-FD (already 96× faster than the legacy full-FD path). | research-ready writeup; implementation gated on the reviewer's view of whether the additional ~6× is worth it | ~2 weeks |
|
| **Phase 9b-analytic: derivation complete, code uses block-FD.** The Schläfli-based analytic HyperIdeal Hessian is fully derived in [`hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) (805 lines, all sign pitfalls covered). The shipped code still uses per-face block-FD (already 96× faster than the legacy full-FD path). | research-ready writeup; implementation gated on the reviewer's view of whether the additional ~6× is worth it | ~2 weeks |
|
||||||
| **Doxygen `WARN_IF_UNDOCUMENTED = NO`.** With `EXTRACT_ALL = YES`, every symbol is in the generated HTML — live at <https://tmoussa.codeberg.page/ConformalLabpp/> (auto-published from `main` by `.gitea/workflows/doxygen-pages.yml`) — but symbols without explicit doc comments show only their signature. Public API surface (entry functions, named-parameter helpers, traits typedefs) has hand-written Doxygen; internal helpers vary. | clean (0 warnings) under current policy; not yet enforced "no undocumented symbol"; pursued on a separate branch | ~3 days to drive `WARN_IF_UNDOCUMENTED = YES` to zero |
|
| **Doxygen `WARN_IF_UNDOCUMENTED = NO`.** With `EXTRACT_ALL = YES`, every symbol is in the generated HTML — live at <https://tmoussa.codeberg.page/ConformalLabpp/> (auto-published from `main` by `.gitea/workflows/doxygen-pages.yml`) — but symbols without explicit doc comments show only their signature. Public API surface (entry functions, named-parameter helpers, traits typedefs) has hand-written Doxygen; internal helpers vary. | clean (0 warnings) under current policy; not yet enforced "no undocumented symbol"; pursued on a separate branch | ~3 days to drive `WARN_IF_UNDOCUMENTED = YES` to zero |
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ Java reference implementation: [github.com/varylab/conformallab](https://github.
|
|||||||
| **Erickson, Whittlesey** — *Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm |
|
| **Erickson, Whittlesey** — *Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm |
|
||||||
| **Bobenko, Springborn** — *A Discrete Laplace–Beltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights |
|
| **Bobenko, Springborn** — *A Discrete Laplace–Beltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights |
|
||||||
| **Desbrun, Kanso, Tong** — *Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a |
|
| **Desbrun, Kanso, Tong** — *Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a |
|
||||||
|
| **Crane, Soliman, Ben-Chen, Schröder** — *Optimal Cone Singularities for Conformal Flattening*, ACM SIGGRAPH (2018). DOI: [10.1145/3197517.3201367](https://doi.org/10.1145/3197517.3201367) | L¹-optimal automatic cone placement — **Phase 9d.2** (non-Euclidean cone extensions). Provides the optimisation algorithm for choosing cone positions automatically; complements Bobenko-Lutz 2025 on non-Euclidean settings. |
|
||||||
|
| **Bobenko, Lutz** — *Decorated Discrete Conformal Equivalence in Non-Euclidean Geometries*, Discrete & Computational Geometry (2025). arXiv: [2310.17529](https://arxiv.org/abs/2310.17529) | **Phase 9d.2**: extends DCE to hyperbolic + spherical geometry with Penner-coordinate decorations; unifies cone singularities and hyperideal cusps in one algebraic framework. |
|
||||||
|
| **Bobenko, Lutz** — *Decorated Discrete Conformal Maps and Convex Polyhedral Cusps*, IMRN 2024(12), pp. 9505–9534. arXiv: [2305.10988](https://arxiv.org/abs/2305.10988) | **Phase 10b/10c**: discrete uniformization theorem for decorated piecewise Euclidean surfaces; connects Phase 2/3 hyperideal vertices (cusps at ∞) to the period matrix and fundamental domain. |
|
||||||
|
| **Lutz** — *Canonical Tessellations of Decorated Hyperbolic Surfaces*, Geometriae Dedicata 217 (2023). arXiv: [2206.13461](https://arxiv.org/abs/2206.13461) | **Phase 10c**: canonical Delaunay tessellations in Penner coordinates; unifies the decorated framework with the fundamental domain construction for genus g ≥ 2. |
|
||||||
|
| **Lutz** — *Decorated Discrete Conformal Equivalence, Canonical Tessellations, and Polyhedral Realization* (PhD thesis, TU Berlin, 2024). DOI: [10.14279/depositonce-20357](https://doi.org/10.14279/depositonce-20357) | Comprehensive single reference for Phases 9d.2, 10b, 10c — collects Bobenko-Lutz 2024/2025 and Lutz 2023 with complete proofs. |
|
||||||
|
| **Bowers, Bowers, Lutz** — *Rigidity of circle polyhedra and hyperideal polyhedra: the tangency case* (2026). arXiv: [2601.22903](https://arxiv.org/abs/2601.22903) | **Phase 9b-analytic + Phase 10c'** (KoebePolyhedron): theoretical uniqueness/rigidity for hyperideal polyhedra in the tangency case; supports correctness of the analytic Hessian and the KAT construction. |
|
||||||
|
| **Alexa, Wardetzky** — *Discrete Laplacians on General Polygonal Meshes*, ACM SIGGRAPH (2011). DOI: [10.1145/1964921.1964997](https://doi.org/10.1145/1964921.1964997) | **Phase 9f**: virtual-node polygon Laplacian extending Pinkall-Polthier to non-triangular meshes. Enables DCE on quad/Voronoi meshes without triangulation. |
|
||||||
|
| **Alexa** — *Discrete Laplacians on General Polygonal Meshes*, ACM TOG 39(6) (2020). DOI: [10.1145/3414685.3417840](https://doi.org/10.1145/3414685.3417840) | **Phase 9f** (extended journal version): error bounds, generalised polygon cotangent weights, convergence analysis. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -58,3 +66,9 @@ builds on this paper and augments it with Ptolemaic flips.
|
|||||||
| **Farkas, Kra** — *Riemann Surfaces*, Springer GTM 71 | Siegel period matrix, Teichmüller theory |
|
| **Farkas, Kra** — *Riemann Surfaces*, Springer GTM 71 | Siegel period matrix, Teichmüller theory |
|
||||||
| **Siegel** — *Topics in Complex Function Theory, Vol. 2*, Wiley | Siegel upper half-space H_g, Sp(2g,ℤ) reduction |
|
| **Siegel** — *Topics in Complex Function Theory, Vol. 2*, Wiley | Siegel upper half-space H_g, Sp(2g,ℤ) reduction |
|
||||||
| **Bobenko, Mercat, Schmies** — *Period Matrices of Polyhedral Surfaces*, in: Computational Approach to Riemann Surfaces (2011) | Discrete period matrices on polyhedral surfaces |
|
| **Bobenko, Mercat, Schmies** — *Period Matrices of Polyhedral Surfaces*, in: Computational Approach to Riemann Surfaces (2011) | Discrete period matrices on polyhedral surfaces |
|
||||||
|
| **Bobenko, Bücking** — *Conformal Structures and Period Matrices of Polyhedral Surfaces* (2009) | Phase 10b: explicit algorithm for computing the discrete Siegel period matrix Ωᵢⱼ on a polyhedral surface from cotangent-weighted integration. |
|
||||||
|
| **Rivin, Springborn** — *The Schläfli formula in Einstein manifolds with boundary*, Electron. Res. Announc. AMS 5 (1999) | Phase 9b-analytic: modern form of the Schläfli identity `2 dV = Σ aₑ dαₑ` for manifolds with boundary — the bilinear form used to derive the analytic HyperIdeal Hessian. |
|
||||||
|
| **Springborn** — *A discrete version of Liouville's theorem on conformal maps* (2019). arXiv: [1911.00966](https://arxiv.org/abs/1911.00966) | Phase 10b uniqueness: proves that the discrete conformal structure (and hence Ω) is a conformal invariant — the discrete Liouville theorem. Justifies that conformallab++ outputs a canonical representative. |
|
||||||
|
| **Springborn, Veselov** — *Quasiconformal distortion of projective transformations and discrete conformal maps*, Int. Math. Res. Not. (2015) | Phase 10c error analysis: quantifies how well the discrete H²/Γ embedding approximates the smooth hyperbolic metric; error bounds for the Fuchsian group representation. |
|
||||||
|
| **Knöppel, Crane, Pinkall, Schröder** — *Stripe Patterns on Surfaces*, ACM SIGGRAPH (2015). DOI: [10.1145/2766890](https://doi.org/10.1145/2766890) | Phase 10a cross-validation: applies discrete holomorphic 1-forms to direction field design; geometry-central provides an independent C++ implementation to cross-check the Phase 10a `DiscreteHolomorphicFormUtility` port. |
|
||||||
|
| **Sawhney, Crane** — *Boundary First Flattening*, ACM TOG 36(1) (2017). DOI: [10.1145/3132705](https://doi.org/10.1145/3132705) | Complementary method to Phase 9d: boundary-prescribed conformal flattening — user specifies boundary shape, interior conforms freely. Contrast: conformallab++ prescribes cone angles in the interior; BFF prescribes the boundary. Alternative approach for applications needing controlled boundary. |
|
||||||
|
|||||||
54
doc/reviewer/README.md
Normal file
54
doc/reviewer/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Reviewer meeting materials
|
||||||
|
|
||||||
|
A single landing page for the three documents associated with an
|
||||||
|
external-reviewer meeting. The materials are written for a peer who
|
||||||
|
actively publishes in discrete differential geometry — specifically
|
||||||
|
the decorated-DCE / Penner-coordinates / hyperideal-polyhedra /
|
||||||
|
canonical-tessellations research line — and who would potentially
|
||||||
|
use conformallab++ as numerical infrastructure for their own future
|
||||||
|
experiments.
|
||||||
|
|
||||||
|
| Document | Audience | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| [`briefing.md`](briefing.md) | **the reviewer** | one-page orientation: what the project is, where to look first, what we want from them |
|
||||||
|
| [`questions.md`](questions.md) | **the reviewer** | the 5 concrete decisions we want their opinion on (skim before the meeting) |
|
||||||
|
| [`agenda.md`](agenda.md) | **me** | my own meeting playbook: timing, order, the "no" question, post-meeting memo template |
|
||||||
|
|
||||||
|
After the meeting, a fourth file `2026-XX-XX-meeting-notes.md` should
|
||||||
|
land here too — the memo template at the bottom of `agenda.md` is the
|
||||||
|
suggested structure.
|
||||||
|
|
||||||
|
## When to send to the reviewer
|
||||||
|
|
||||||
|
- **briefing.md** + **questions.md**: as part of the meeting-confirmation
|
||||||
|
email, ~5 business days before the meeting. Subject line: *"Pre-read
|
||||||
|
for our conformallab++ chat (~15 min)"*.
|
||||||
|
- **agenda.md**: never send. This is internal scaffolding.
|
||||||
|
|
||||||
|
## Hub-Page durability
|
||||||
|
|
||||||
|
The reviewer hub HTML at <https://tmoussa.codeberg.page/ConformalLabpp/>
|
||||||
|
is published from `doc/reviewer/hub.html` in the repo (not from a
|
||||||
|
detached preview branch). This means:
|
||||||
|
|
||||||
|
* Merging any of the open PRs into `main` triggers
|
||||||
|
`.gitea/workflows/doxygen-pages.yml` which republishes the hub
|
||||||
|
alongside fresh Doxygen HTML — the reviewer URL stays live across
|
||||||
|
merges with no manual intervention.
|
||||||
|
* The hub is source-controlled, so changes are reviewable via PR
|
||||||
|
like any other doc, and old versions live in git history.
|
||||||
|
* The original Doxygen index moves to `/doxygen.html` whenever the
|
||||||
|
hub override is active; both are reachable from the hub itself.
|
||||||
|
|
||||||
|
## Quick links the reviewer should bookmark
|
||||||
|
|
||||||
|
- 🌐 Reviewer-hub landing page: <https://tmoussa.codeberg.page/ConformalLabpp/>
|
||||||
|
(the hub shows status badges, a "what's new" banner with the most
|
||||||
|
recent delta, the research-alignment table, and direct links into
|
||||||
|
every document below)
|
||||||
|
- 📦 Source: <https://codeberg.org/TMoussa/ConformalLabpp>
|
||||||
|
- 📝 Architecture decisions (incl. the Q7 "no" prompt): [`../architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md)
|
||||||
|
- 📐 Schläfli derivation (for Q3): [`../math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md)
|
||||||
|
- 📚 Literature index (for Q1 + Q3): [`../math/references.md`](../math/references.md)
|
||||||
|
- 🗺️ Per-phase roadmap (for Q1): [`../roadmap/phases.md`](../roadmap/phases.md)
|
||||||
|
- 🧪 Research-track entries with acceptance criteria (Q1 + Q2): [`../roadmap/research-track.md`](../roadmap/research-track.md)
|
||||||
132
doc/reviewer/agenda.md
Normal file
132
doc/reviewer/agenda.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Reviewer meeting — agenda (for me)
|
||||||
|
|
||||||
|
> **Audience.** Myself, before the meeting. Not shared with the
|
||||||
|
> reviewer (they have [`briefing.md`](briefing.md) and
|
||||||
|
> [`questions.md`](questions.md) instead).
|
||||||
|
>
|
||||||
|
> **Purpose.** Keep the conversation on the high-stakes items
|
||||||
|
> without slipping into detail-tour mode.
|
||||||
|
|
||||||
|
**Length:** ~60 min (default; willing to extend if conversation is
|
||||||
|
productive).
|
||||||
|
|
||||||
|
## Opening — 5 min
|
||||||
|
|
||||||
|
- **Thank-you** + ~30 s on why I value their time specifically
|
||||||
|
(active researcher in the exact line — decorated DCE, Penner
|
||||||
|
coordinates, canonical tessellations, hyperideal polyhedra — that
|
||||||
|
conformallab++ aspires to be infrastructure for; best-positioned
|
||||||
|
audience for the material AND the most likely future power user).
|
||||||
|
- **Confirm format**: they've read `briefing.md`? Yes → skip ahead.
|
||||||
|
No → take 3 min to walk through it together via the reviewer-hub
|
||||||
|
URL.
|
||||||
|
|
||||||
|
## §1 Architectural tour — 10 min
|
||||||
|
|
||||||
|
Goal: they leave §1 with a mental map of what's where.
|
||||||
|
|
||||||
|
1. Open <https://tmoussa.codeberg.page/ConformalLabpp/>.
|
||||||
|
2. Click through:
|
||||||
|
- Doxygen → `discrete_conformal_map_euclidean` (the canonical entry,
|
||||||
|
shows the named-parameter pattern + traits).
|
||||||
|
- `locked-vs-flexible.md` § Summary table.
|
||||||
|
- `dependencies.md` § TL;DR.
|
||||||
|
3. **Don't** demo running the test suite live unless they ask —
|
||||||
|
they can verify the green badges later.
|
||||||
|
|
||||||
|
**Cue to move on**: when they have no more "where is X?" questions.
|
||||||
|
|
||||||
|
## §2 The seven questions — 35 min
|
||||||
|
|
||||||
|
Goal: get clear answers to as many of the 7 questions in
|
||||||
|
[`questions.md`](questions.md) as possible. Order is chosen so the
|
||||||
|
research-relevant questions come *first* (their answer has the largest
|
||||||
|
downstream effect on the roadmap):
|
||||||
|
|
||||||
|
1. **Q1 — research-track alignment** (which of 9d.2 / 9f / 10c / 10c′
|
||||||
|
would unblock concrete experiments?). ~8 min. Most likely to
|
||||||
|
make them feel the project is genuinely *for* their work, not just
|
||||||
|
adjacent to it.
|
||||||
|
2. **Q2 — decorated-DCE API surface** (A/B/C named parameter vs new
|
||||||
|
solver vs property-map auto-detect). ~7 min. Sets a concrete
|
||||||
|
shape we can sketch in code right after the meeting.
|
||||||
|
3. **Q3 — Phase 9b-analytic** (Schläfli Hessian — implement now?).
|
||||||
|
~8 min. May trigger longer math discussion; cap at 10 min and
|
||||||
|
offer to continue async via the derivation note.
|
||||||
|
4. **Q5 — GC-1 cross-validation co-authorship**. ~4 min. Read the
|
||||||
|
room: if they're warm, push; if cool, leave as "let me follow up
|
||||||
|
in writing".
|
||||||
|
5. **Q4 — Phase 9c port-literal vs re-derive** (algorithm choice).
|
||||||
|
~4 min. Less critical than Q1–Q3 because we have a viable default
|
||||||
|
either way.
|
||||||
|
6. **Q6 — CGAL submission packaging** (one package vs several).
|
||||||
|
~4 min. Project-management question; their answer is *advisory*
|
||||||
|
even if it's confident.
|
||||||
|
|
||||||
|
**Trap to avoid**: don't relitigate any of the already-made decisions
|
||||||
|
(e.g. Surface_mesh as default, Eigen as backend) unless they bring it
|
||||||
|
up under "anything you'd say no to". Move forward, not sideways.
|
||||||
|
Keep Q4/Q6 *short* — they are project management; Q1–Q3 are the
|
||||||
|
research-flavoured ones their time is best spent on.
|
||||||
|
|
||||||
|
## §3 Q7 — the "no" question — 5 min
|
||||||
|
|
||||||
|
[`questions.md`](questions.md) §Q7: *"Is there one architecture
|
||||||
|
decision where you think 'no, that's the wrong call'?"*
|
||||||
|
|
||||||
|
Ask explicitly. Wait. Don't fill silence. Negative feedback at this
|
||||||
|
phase is the highest-value information of the entire meeting.
|
||||||
|
|
||||||
|
## §4 Wrap-up — 5 min
|
||||||
|
|
||||||
|
- **Summarise**: 1 sentence per Q1–Q7 answer.
|
||||||
|
- **Next steps**:
|
||||||
|
- Items they offered to help on (if any) → I'll send a follow-up
|
||||||
|
email within 48 h.
|
||||||
|
- Items they flagged as worth changing → I'll write a one-page
|
||||||
|
plan + send for sign-off before starting work.
|
||||||
|
- **Cadence**: do they want a periodic update? Once-a-quarter? When
|
||||||
|
hitting Phase 9c milestone?
|
||||||
|
- **Citation**: ask whether they want acknowledgement in the
|
||||||
|
CGAL submission's `THANKS.md`.
|
||||||
|
|
||||||
|
## Material I have ready (in tabs)
|
||||||
|
|
||||||
|
1. <https://tmoussa.codeberg.page/ConformalLabpp/>
|
||||||
|
2. <https://codeberg.org/TMoussa/ConformalLabpp> (source)
|
||||||
|
3. Local terminal in the repo (for any "show me X" requests)
|
||||||
|
4. `doc/math/hyperideal-hessian-derivation.md` open in editor
|
||||||
|
(for Q2)
|
||||||
|
5. `doc/architecture/locked-vs-flexible.md` open at "Summary table"
|
||||||
|
6. This file, [`questions.md`](questions.md), and
|
||||||
|
[`briefing.md`](briefing.md) for backstop.
|
||||||
|
|
||||||
|
## After the meeting
|
||||||
|
|
||||||
|
- 30-min decompression — don't take notes during the meeting beyond
|
||||||
|
bullet-tracking of Q1–Q5 answers; write up a full memo in the 30 min
|
||||||
|
AFTER.
|
||||||
|
- Memo template:
|
||||||
|
```
|
||||||
|
Date: ____
|
||||||
|
Reviewer: ____
|
||||||
|
Duration: ____ min
|
||||||
|
|
||||||
|
Q1 answer (research-track alignment): ____
|
||||||
|
Q2 answer (decorated-DCE API): ____
|
||||||
|
Q3 answer (Phase 9b-analytic): ____
|
||||||
|
Q4 answer (Phase 9c port choice): ____
|
||||||
|
Q5 answer (GC-1 co-authorship): ____
|
||||||
|
Q6 answer (CGAL packaging): ____
|
||||||
|
Q7 "no" pointer: ____
|
||||||
|
|
||||||
|
Action items:
|
||||||
|
[ ] (within 48 h) ____
|
||||||
|
[ ] (within 2 wks) ____
|
||||||
|
[ ] (longer term) ____
|
||||||
|
|
||||||
|
Cadence agreed: ____
|
||||||
|
```
|
||||||
|
|
||||||
|
- Store the memo at `doc/reviewer/2026-XX-XX-meeting-notes.md`
|
||||||
|
(gitignored if confidential, otherwise committed).
|
||||||
183
doc/reviewer/briefing.md
Normal file
183
doc/reviewer/briefing.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Reviewer briefing — conformallab++
|
||||||
|
|
||||||
|
> **Audience.** Active researcher in discrete differential geometry —
|
||||||
|
> specifically the research line around **decorated discrete conformal
|
||||||
|
> equivalence**, **Penner coordinates on hyperbolic surfaces**,
|
||||||
|
> **canonical Delaunay tessellations of decorated surfaces**, and
|
||||||
|
> **hyperideal polyhedra**. Treats the reader as a peer who is more
|
||||||
|
> likely to *use* conformallab++ as numerical infrastructure for their
|
||||||
|
> own future experiments than to merely evaluate it as a software
|
||||||
|
> artefact.
|
||||||
|
>
|
||||||
|
> **Purpose.** One page to read before the meeting: what is shipping,
|
||||||
|
> which of the reader's research questions it could already support,
|
||||||
|
> and where the gaps are that we would close together.
|
||||||
|
|
||||||
|
## In one paragraph
|
||||||
|
|
||||||
|
`conformallab++` is a C++17 header-only re-implementation of the Java
|
||||||
|
library [`ConformalLab`](https://github.com/varylab/conformallab)
|
||||||
|
(Sechelmann 2016, TU Berlin), built around CGAL's `Surface_mesh` and
|
||||||
|
Eigen. v0.9.0 ships five Discrete Conformal Equivalence (DCE) solvers
|
||||||
|
— Euclidean, Spherical, HyperIdeal, Circle-Packing Euclidean
|
||||||
|
(BPS 2010, face-based), Inversive-Distance (Luo 2004, vertex-based) —
|
||||||
|
plus the Newton infrastructure, layout (priority-BFS trilateration in
|
||||||
|
ℝ², S², Poincaré disk), Möbius holonomy, period matrix, cut graph, and
|
||||||
|
JSON/XML serialisation. Long-term goal: a CGAL package.
|
||||||
|
|
||||||
|
## Where to start (one URL, 5 minutes)
|
||||||
|
|
||||||
|
**👉 https://tmoussa.codeberg.page/ConformalLabpp/**
|
||||||
|
|
||||||
|
The landing page is a hand-curated reviewer hub, not an auto-generated
|
||||||
|
index. It links to the Doxygen API, the key markdown documents, and
|
||||||
|
shows static quality-gate status.
|
||||||
|
|
||||||
|
## Research alignments — where this library could be infrastructure for your work
|
||||||
|
|
||||||
|
The current snapshot already contains, or has roadmap entries for,
|
||||||
|
the following. Most rows match an active publication line in
|
||||||
|
discrete differential geometry; a few (marked *no Java parent*) are
|
||||||
|
research-only phases the reader can shape at design stage.
|
||||||
|
|
||||||
|
| Your research thread | What this snapshot has | Phase |
|
||||||
|
|---|---|---|
|
||||||
|
| **Decorated DCE in non-Euclidean geometries** (Bobenko–Lutz 2025, *DCG*) | five DCE solvers + traits scaffolding; non-Euclidean cone extension scoped in research-track with acceptance criteria | **9d.2** RESEARCH (planned) |
|
||||||
|
| **Canonical Delaunay tessellations of decorated hyperbolic surfaces** (Lutz 2023, *Geom. Dedicata*; Lutz 2024 PhD thesis) | cut-graph + period matrix + hyperbolic-disk layout as scaffolding; canonical-tessellation algorithm itself outlined | **10c** planned |
|
||||||
|
| **Hyperideal polyhedra rigidity** (Bowers–Bowers–Lutz 2026) | HyperIdeal functional + analytic Hessian derivation (805-line LaTeX note) | **9b-analytic** derived; **10c′** KAT planned |
|
||||||
|
| **Optimal cone placement / non-Euclidean cone metrics** (Crane et al. 2018) | Cone-singularity port via `ConesUtility` scoped; the *non-Euclidean* extension is the research delta | **9d.1** port + **9d.2** RESEARCH |
|
||||||
|
| **Polygon Laplacian on general meshes** (Alexa–Wardetzky 2011; Alexa 2020) | *no Java parent* — first phase a reviewer can shape at design stage | **9f** RESEARCH (planned) |
|
||||||
|
| **Quasi-isothermic maps** (generalising conformality where exact conformality is impossible — Lawson-correspondence parameterisation) | scoped as a 6-class port (~800 lines) from the Java original: `QuasiisothermicLayout`, `DBFSolution` (discrete Beltrami field), `SinConditionApplication`, `QuasiisothermicDelaunay`, `QuasiisothermicUtility`, `ConformalStructureUtility` | **10e** planned |
|
||||||
|
| **Higher-genus + hyperelliptic surfaces** (Bobenko–Bücking 2009 on polyhedral surfaces; period matrices with block-diagonal Z₂ structure) | port of `HyperellipticUtility` + `HyperIdealHyperellipticUtility` scoped; existing period-matrix code as scaffolding | **10b** planned |
|
||||||
|
| **Möbius centring for Poincaré-disk layouts** as a variational problem (Lorentz geometry: `E = Σ log(−⟨x,p⟩/√(−⟨x,x⟩))`) | currently we use iterative Fréchet mean in `normalise_hyperbolic()`; the principled variational alternative is scoped via the Java `MobiusCenteringFunctional` port (full gradient + Hessian) | **9d.4** planned |
|
||||||
|
| **Boundary-First / interactive flattening** (Crane et al. 2017 BFF; Bonneel et al. 2015 *Stripe Patterns on Surfaces*) | not on the roadmap as ports; documented in [`references.md`](../math/references.md) as comparison points / inspiration for future API design | — |
|
||||||
|
| **Schläfli-based variational machinery** (Rivin–Springborn 1999) | derivation done, implementation gated on your view of whether the ~6× speedup over our block-FD path matters at your mesh sizes | **9b-analytic** ready to implement |
|
||||||
|
|
||||||
|
See [`doc/roadmap/phases.md`](../roadmap/phases.md) for the per-phase
|
||||||
|
porting plan, [`doc/roadmap/research-track.md`](../roadmap/research-track.md)
|
||||||
|
for the items beyond Java parity with explicit acceptance criteria,
|
||||||
|
and [`doc/roadmap/java-parity.md`](../roadmap/java-parity.md) for the
|
||||||
|
reverse table (every Java class → C++ destination or *do-not-port*
|
||||||
|
rationale).
|
||||||
|
|
||||||
|
## What's new on this snapshot (since the previous publish)
|
||||||
|
|
||||||
|
- **+6 new porting-roadmap phases** (9d cones + 9d.4 Möbius centring /
|
||||||
|
9e circle-pattern layout / 10d Koebe circle-domain / 10e
|
||||||
|
quasi-isothermic / 10f Koebe polyhedra / 10g cyclic-symmetry
|
||||||
|
quotients) derived from a full Java-library scan. See `phases.md`
|
||||||
|
for the per-phase plan and `java-parity.md` for the reverse table.
|
||||||
|
- **+13 literature citations** integrated into the roadmap, all
|
||||||
|
Tier-1/2. Decorated-DCE / canonical-tessellation / hyperideal line:
|
||||||
|
Bobenko–Lutz 2024 IMRN; Bobenko–Lutz 2025 *DCG*; Lutz 2023
|
||||||
|
*Geom. Dedicata*; Lutz 2024 PhD; Bowers–Bowers–Lutz 2026. Cones,
|
||||||
|
polyhedra, period matrices: Crane et al. 2018; Springborn 2019
|
||||||
|
(hyperbolic polyhedra); Bobenko–Bücking 2009; Rivin–Springborn 1999.
|
||||||
|
Polygon Laplacians: Alexa–Wardetzky 2011; Alexa 2020. Integrable +
|
||||||
|
practical-flattening context: Springborn–Veselov 2015 (cluster
|
||||||
|
dynamics); Crane et al. 2017 (BFF); Bonneel et al. 2015 (Stripe
|
||||||
|
Patterns).
|
||||||
|
- **Phase 9f** (polygon Laplacian on non-triangular meshes) added as
|
||||||
|
RESEARCH-only — no Java parent — so you can influence its design
|
||||||
|
before it exists.
|
||||||
|
- **Phase 10e** (quasi-isothermic maps) and **Phase 9d.4** (variational
|
||||||
|
Möbius centring) newly scoped from the Java scan; both touch
|
||||||
|
research lines adjacent to decorated DCE.
|
||||||
|
- **`output_uv_map`** now covers 4 of 5 DCE solvers (Inversive-Distance
|
||||||
|
added; CP-Euclidean deferred to Phase 9c with a clear runtime error
|
||||||
|
rather than silent failure).
|
||||||
|
|
||||||
|
## What's true about this snapshot
|
||||||
|
|
||||||
|
| Claim | Concrete evidence |
|
||||||
|
|---|---|
|
||||||
|
| **Library is header-only and standalone** | Verification recipe in `doc/architecture/dependencies.md`: `env -i PATH=… cmake … && ctest` passes with zero quality tools installed. |
|
||||||
|
| **Tests: 259 pass, 0 skipped** | `bash scripts/check-test-counts.sh` enforces this against `doc/api/tests.md`; CI fails on drift. |
|
||||||
|
| **Doxygen: 100 % public-API coverage, 0 warnings** | `bash scripts/doxygen-coverage.sh --threshold 100` is in CI. |
|
||||||
|
| **License hygiene: 66/66 files carry MIT SPDX** | `bash scripts/quality/license-headers.sh` is in CI (strict). |
|
||||||
|
| **Build reproducibility: byte-identical between runs** | `bash scripts/quality/reproducible-build.sh` (local, ~6 min). |
|
||||||
|
| **Sanitizers (ASan + UBSan) clean on fast suite** | `bash scripts/quality/sanitizers.sh` (local, ~3 min). |
|
||||||
|
| **CGAL conventions: 6 rules, 0 violations** | `python3 scripts/quality/cgal-conventions.py` (CI required). |
|
||||||
|
|
||||||
|
## What we want from you
|
||||||
|
|
||||||
|
Seven concrete questions are in
|
||||||
|
[`doc/reviewer/questions.md`](questions.md) — please skim them
|
||||||
|
beforehand. They are deliberately scoped: each can be answered with
|
||||||
|
"go this way" / "no, go that way" / "either is fine".
|
||||||
|
|
||||||
|
Ordered by reviewer-value (the first two are the ones your research
|
||||||
|
profile makes you best-positioned to answer):
|
||||||
|
|
||||||
|
1. **Q1 — Research-track alignment** — of the three RESEARCH-track
|
||||||
|
phases (9d.2 non-Euclidean cones, 9f polygon Laplacian, 10c
|
||||||
|
canonical tessellations + 10c′ Koebe polyhedra), which would
|
||||||
|
unblock concrete experiments you have wanted to run?
|
||||||
|
2. **Q2 — Decorated-DCE API surface** — what's the minimum public
|
||||||
|
API for Penner-coordinate / decorated-DCE work? Named parameter
|
||||||
|
on the existing Euclidean entry, separate `decorated_*` solvers,
|
||||||
|
or per-edge decoration weights via property maps?
|
||||||
|
3. **Q3 — Phase 9b-analytic** — is the ~6× speedup over the current
|
||||||
|
block-FD Hessian worth ~2 weeks of implementation, at the mesh
|
||||||
|
sizes you typically work with?
|
||||||
|
4. **Q4 — Phase 9c (4g-polygon)** — port the Java implementation
|
||||||
|
literally, or re-derive from Springborn 2020 §5?
|
||||||
|
5. **Q5 — geometry-central cross-validation (GC-1)** — would you
|
||||||
|
be interested in co-authoring a Newton-vs-Ptolemy-flips comparison?
|
||||||
|
6. **Q6 — CGAL submission strategy** — one package or several?
|
||||||
|
7. **Q7 — The "no" question** — looking at our 12 architecture
|
||||||
|
decisions, is there one you would push back on?
|
||||||
|
|
||||||
|
## What's deliberately deferred (so we can discuss with you first)
|
||||||
|
|
||||||
|
| Item | Why deferred |
|
||||||
|
|---|---|
|
||||||
|
| Phase 9b-analytic (Schläfli-based HyperIdeal Hessian) | derivation done (805-line LaTeX doc), implementation depends on your opinion of payoff |
|
||||||
|
| Phase 9c (fundamental-polygon utility, 4g-polygon canonical form) | algorithm choice up to you |
|
||||||
|
| Cross-validation against geometry-central (GC-1) | potential paper, scope depends on your interest |
|
||||||
|
| CP-Euclidean `output_uv_map` (per-face circle packing) | needs the BPS-2010 §6 layout algorithm, ~3 days |
|
||||||
|
| `.a().b().c()` member-style named-parameter chaining | requires patching CGAL upstream; pipe-operator (`a | b | c`) shipped instead |
|
||||||
|
|
||||||
|
These are all flagged in
|
||||||
|
[`doc/architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md)
|
||||||
|
§"Known limitations".
|
||||||
|
|
||||||
|
## Architectural decisions you might want to challenge
|
||||||
|
|
||||||
|
12 decisions classified 🔴 load-bearing / 🟡 semi-fixed / 🟢 opportunistic
|
||||||
|
in [`doc/architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md).
|
||||||
|
The ones most worth your time:
|
||||||
|
|
||||||
|
- **#1 Surface_mesh as default** — 🔴 ~3 weeks to change. Are you OK
|
||||||
|
with this default, or should we wire Polyhedron_3 / OpenMesh now?
|
||||||
|
- **#6 Eigen as linear-algebra back-end** — 🔴 ~2 weeks to change. Are
|
||||||
|
the Eigen sparse solvers (SparseCholesky + SparseQR fallback)
|
||||||
|
sufficient for the mesh sizes you've seen, or should we look at
|
||||||
|
CHOLMOD / PETSc?
|
||||||
|
- **#7 Strategy C** (one Default trait per functional, not a unified
|
||||||
|
trait) — 🟡 ~1 week to refactor. CGAL convention agrees; do you?
|
||||||
|
|
||||||
|
## How to actually run something
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://codeberg.org/TMoussa/ConformalLabpp && cd ConformalLabpp
|
||||||
|
cmake -S code -B build && cmake --build build --target conformallab_tests
|
||||||
|
ctest --test-dir build # ~2 s, 23 pure-math tests
|
||||||
|
# CGAL tests (adds Boost as a system dep):
|
||||||
|
cmake -S code -B build -DWITH_CGAL_TESTS=ON
|
||||||
|
cmake --build build --target conformallab_cgal_tests -j
|
||||||
|
ctest --test-dir build # ~3 min, 236 CGAL tests
|
||||||
|
```
|
||||||
|
|
||||||
|
A more end-to-end recipe lives in `scripts/try_it.sh` (also run in CI).
|
||||||
|
|
||||||
|
## Meeting logistics
|
||||||
|
|
||||||
|
- **Format**: video call (you suggested), ~60 min
|
||||||
|
- **Materials needed on your side**: just a browser to follow the
|
||||||
|
reviewer-hub URL.
|
||||||
|
- **Materials I'll have ready**: a screen-share-able terminal with
|
||||||
|
the repo open, my own agenda in `doc/reviewer/agenda.md`, and the
|
||||||
|
questions doc above.
|
||||||
|
|
||||||
|
Looking forward.
|
||||||
529
doc/reviewer/hub.html
Normal file
529
doc/reviewer/hub.html
Normal file
@@ -0,0 +1,529 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>conformallab++ — Reviewer Preview</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--c-primary: #2e86c1;
|
||||||
|
--c-primary-dark: #1f618d;
|
||||||
|
--c-bg-soft: #f8fbfd;
|
||||||
|
--c-border: #d6eaf8;
|
||||||
|
--c-text: #2c3e50;
|
||||||
|
--c-muted: #7b8a8b;
|
||||||
|
--c-green-bg: #d5f5e3; --c-green-fg: #186a3b;
|
||||||
|
--c-yellow-bg: #fcf3cf; --c-yellow-fg: #7d6608;
|
||||||
|
--c-skip-bg: #ebdef0; --c-skip-fg: #6c3483;
|
||||||
|
--c-new-bg: #fdebd0; --c-new-fg: #6e2c00;
|
||||||
|
--c-research-bg: #ebf5fb; --c-research-fg: #1b4f72;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
||||||
|
max-width: 1100px; margin: 0 auto; padding: 0;
|
||||||
|
color: var(--c-text); line-height: 1.55;
|
||||||
|
background: var(--c-bg-soft); }
|
||||||
|
main { padding: 2em 1.5em 5em 1.5em; background: #fff; }
|
||||||
|
|
||||||
|
/* ── Sticky TOC nav ───────────────────────────────────────────────── */
|
||||||
|
nav.toc {
|
||||||
|
position: sticky; top: 0; z-index: 10;
|
||||||
|
background: var(--c-primary); color: #fff;
|
||||||
|
padding: 0.7em 1.5em; font-size: 0.92em;
|
||||||
|
border-bottom: 3px solid var(--c-primary-dark);
|
||||||
|
display: flex; flex-wrap: wrap; gap: 0.4em 1.2em;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
nav.toc a { color: #fff; text-decoration: none; font-weight: 500; padding: 2px 6px;
|
||||||
|
border-radius: 3px; transition: background 0.15s; }
|
||||||
|
nav.toc a:hover { background: rgba(255,255,255,0.2); }
|
||||||
|
nav.toc strong { color: #fce4a6; font-weight: 700; margin-right: 0.6em; }
|
||||||
|
nav.toc .skim a { background: rgba(255,255,255,0.15); }
|
||||||
|
|
||||||
|
/* ── Headings ────────────────────────────────────────────────────── */
|
||||||
|
h1 { color: var(--c-primary-dark); border-bottom: 3px solid var(--c-primary);
|
||||||
|
padding-bottom: 0.3em; margin: 0.2em 0 0.5em 0; font-size: 1.8em; }
|
||||||
|
h2 { color: var(--c-primary-dark); margin-top: 2.5em;
|
||||||
|
padding: 0.5em 0.8em; background: var(--c-border);
|
||||||
|
border-left: 5px solid var(--c-primary); border-radius: 3px;
|
||||||
|
font-size: 1.25em; scroll-margin-top: 4em; }
|
||||||
|
h2 .anchor { color: var(--c-primary); opacity: 0.4; font-size: 0.7em;
|
||||||
|
margin-left: 0.4em; text-decoration: none; }
|
||||||
|
h2:hover .anchor { opacity: 1; }
|
||||||
|
h3 { color: var(--c-primary-dark); margin-top: 1.5em; font-size: 1.05em; }
|
||||||
|
|
||||||
|
/* ── Badges + status pills ───────────────────────────────────────── */
|
||||||
|
.badges { margin: 1em 0 1.5em 0; }
|
||||||
|
.badges img { margin: 2px 6px 2px 0; vertical-align: middle; }
|
||||||
|
.pill { display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||||
|
font-size: 0.85em; margin-right: 4px; font-weight: 600;
|
||||||
|
white-space: nowrap; }
|
||||||
|
.green { background: var(--c-green-bg); color: var(--c-green-fg); }
|
||||||
|
.yellow { background: var(--c-yellow-bg); color: var(--c-yellow-fg); }
|
||||||
|
.skip { background: var(--c-skip-bg); color: var(--c-skip-fg); }
|
||||||
|
.new { background: var(--c-new-bg); color: var(--c-new-fg); }
|
||||||
|
.research{ background: var(--c-research-bg); color: var(--c-research-fg); }
|
||||||
|
|
||||||
|
/* ── Tables ──────────────────────────────────────────────────────── */
|
||||||
|
table { border-collapse: collapse; width: 100%; margin: 1em 0;
|
||||||
|
font-size: 0.95em; }
|
||||||
|
th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid #e8e8e8;
|
||||||
|
vertical-align: top; }
|
||||||
|
th { background: #ecf0f1; font-weight: 600; color: var(--c-primary-dark); }
|
||||||
|
tr:hover { background: #fafcfe; }
|
||||||
|
|
||||||
|
/* ── Boxes ───────────────────────────────────────────────────────── */
|
||||||
|
.box { padding: 0.8em 1.1em; margin: 1.2em 0; border-radius: 4px;
|
||||||
|
border-left-width: 5px; border-left-style: solid; }
|
||||||
|
.box-tldr { background: #fff; border: 1px solid var(--c-border);
|
||||||
|
border-left-color: var(--c-primary); }
|
||||||
|
.box-result { background: #eafaf1; border-left-color: #28b463; }
|
||||||
|
.box-delta { background: #fdf2e9; border-left-color: #e67e22; }
|
||||||
|
.box-note { background: #fef9e7; border-left-color: #f1c40f; }
|
||||||
|
|
||||||
|
/* ── Code & details ──────────────────────────────────────────────── */
|
||||||
|
code { background: #f4f4f4; padding: 1px 5px; border-radius: 3px;
|
||||||
|
font-size: 0.92em; }
|
||||||
|
pre { background: #f4f4f4; padding: 0.8em 1em; border-radius: 4px;
|
||||||
|
overflow-x: auto; font-size: 0.88em; line-height: 1.45; }
|
||||||
|
details { margin: 0.8em 0; }
|
||||||
|
details summary { cursor: pointer; padding: 0.4em 0.6em;
|
||||||
|
background: #ecf0f1; border-radius: 3px;
|
||||||
|
font-weight: 600; color: var(--c-primary-dark); }
|
||||||
|
details[open] summary { border-bottom: 1px solid var(--c-border); margin-bottom: 0.5em; }
|
||||||
|
|
||||||
|
/* ── Time-budget grid ────────────────────────────────────────────── */
|
||||||
|
.time-grid { display: grid; grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 1em; margin: 1.2em 0; }
|
||||||
|
.time-card { background: #fff; border: 1px solid var(--c-border);
|
||||||
|
border-top: 4px solid var(--c-primary); border-radius: 4px;
|
||||||
|
padding: 0.9em 1em; }
|
||||||
|
.time-card h3 { margin: 0 0 0.4em 0; font-size: 1em; color: var(--c-primary-dark); }
|
||||||
|
.time-card ul { margin: 0; padding-left: 1.2em; font-size: 0.92em; }
|
||||||
|
.time-card li { margin: 0.2em 0; }
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.time-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Question table compact ──────────────────────────────────────── */
|
||||||
|
table.qtable td:first-child { width: 50px; font-weight: 700;
|
||||||
|
color: var(--c-primary-dark); }
|
||||||
|
table.qtable td:last-child { width: 110px; }
|
||||||
|
|
||||||
|
/* ── Footer ──────────────────────────────────────────────────────── */
|
||||||
|
footer { margin-top: 3em; padding-top: 1em; border-top: 1px solid #e8e8e8;
|
||||||
|
font-size: 0.88em; color: var(--c-muted); }
|
||||||
|
|
||||||
|
/* ── Small helpers ───────────────────────────────────────────────── */
|
||||||
|
.small { color: var(--c-muted); font-size: 0.9em; }
|
||||||
|
.lead { font-size: 1.05em; }
|
||||||
|
.topshift { scroll-margin-top: 4em; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="toc">
|
||||||
|
<strong>Jump to:</strong>
|
||||||
|
<a href="#tldr">TL;DR</a>
|
||||||
|
<a href="#alignments">1. Alignments</a>
|
||||||
|
<a href="#questions">2. Questions</a>
|
||||||
|
<a href="#new">3. What's new</a>
|
||||||
|
<a href="#use">4. How to use</a>
|
||||||
|
<a href="#docs">5. Documents</a>
|
||||||
|
<a href="#proof">6. Proof</a>
|
||||||
|
<a href="#source">7. Source</a>
|
||||||
|
<span class="skim"><a href="#tldr">⏱ skim path</a></span>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
|
||||||
|
<h1 id="top">conformallab++ — Reviewer Preview</h1>
|
||||||
|
|
||||||
|
<p class="lead">
|
||||||
|
A C++17 header-only implementation of discrete conformal equivalence
|
||||||
|
solvers on triangle meshes, built around CGAL's <code>Surface_mesh</code>
|
||||||
|
and Eigen. v0.9.0 ships five DCE solvers (Euclidean / Spherical /
|
||||||
|
HyperIdeal / CP-Euclidean / Inversive-Distance) plus the layout,
|
||||||
|
holonomy, period-matrix, cut-graph and serialisation infrastructure.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Audience.</b> Active researcher in discrete differential geometry —
|
||||||
|
specifically the <b>decorated DCE</b> / <b>Penner coordinates</b> /
|
||||||
|
<b>canonical Delaunay tessellations</b> / <b>hyperideal polyhedra</b>
|
||||||
|
line — treated as a peer most likely to <i>use</i> conformallab++ as
|
||||||
|
numerical infrastructure for their own future experiments, not merely
|
||||||
|
to evaluate it.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="box box-note">
|
||||||
|
<b>This page is a temporary preview</b> combining two unmerged PRs so
|
||||||
|
the integrated state is reviewable before any merge happens. Once the
|
||||||
|
PRs land on <code>main</code>, the publish URL serves the <code>main</code>-branch view.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="tldr">TL;DR — orient yourself <a class="anchor" href="#tldr">#</a></h2>
|
||||||
|
|
||||||
|
<p class="badges">
|
||||||
|
<img src="https://img.shields.io/badge/tests-259%20%2F%20259-brightgreen?style=flat-square" alt="Tests 259/259">
|
||||||
|
<img src="https://img.shields.io/badge/skipped-0-brightgreen?style=flat-square" alt="Skipped 0">
|
||||||
|
<img src="https://img.shields.io/badge/doxygen-100%25-brightgreen?style=flat-square" alt="Doxygen 100%">
|
||||||
|
<img src="https://img.shields.io/badge/quality%20gates-14%2F15%20PASS-brightgreen?style=flat-square" alt="Quality">
|
||||||
|
<img src="https://img.shields.io/badge/roadmap-5%20ported%20%2B%2011%20planned%20%2B%203%20research-blue?style=flat-square" alt="Roadmap">
|
||||||
|
<img src="https://img.shields.io/badge/literature-13%20Tier--1%20%26%20Tier--2-blue?style=flat-square" alt="Lit">
|
||||||
|
<img src="https://img.shields.io/badge/license-MIT-yellow?style=flat-square" alt="License">
|
||||||
|
<img src="https://img.shields.io/badge/header--only-yes-blue?style=flat-square" alt="Header-only">
|
||||||
|
<img src="https://img.shields.io/badge/version-v0.9.0-blue?style=flat-square" alt="v0.9.0">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="box box-result">
|
||||||
|
<b>Headline.</b> 259/259 tests pass (0 skipped); 100 % Doxygen
|
||||||
|
coverage on the public API; 14 of 15 quality gates green
|
||||||
|
(1 SKIP — local CGAL-version-matrix has no tarballs); library is
|
||||||
|
verified-standalone (Eigen + CGAL + Boost, all header-only, no
|
||||||
|
runtime deps).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Pick a time budget; each path is a sequence of anchor links.</p>
|
||||||
|
|
||||||
|
<div class="time-grid">
|
||||||
|
|
||||||
|
<div class="time-card">
|
||||||
|
<h3>⏱ 5 minutes — minimum to know what's here</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#alignments">§1 Research alignments</a> (10-row table)</li>
|
||||||
|
<li><a href="#new">§3 What's new</a> (delta since last publish)</li>
|
||||||
|
<li><a href="doxygen.html">→ Doxygen HTML index</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="time-card">
|
||||||
|
<h3>📖 20 minutes — to prepare for the meeting</h3>
|
||||||
|
<ul>
|
||||||
|
<li>5-min path above, plus:</li>
|
||||||
|
<li><a href="#questions">§2 Seven questions at a glance</a></li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/briefing.md">briefing.md</a> (1 page)</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/questions.md">questions.md</a> (the full text of Q1–Q7)</li>
|
||||||
|
<li><a href="#use">§4 How to actually use this</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="time-card">
|
||||||
|
<h3>🔬 60+ minutes — deep dive</h3>
|
||||||
|
<ul>
|
||||||
|
<li>20-min path above, plus:</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/phases.md">roadmap/phases.md</a> (full per-phase plan)</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/math/hyperideal-hessian-derivation.md">hyperideal-hessian-derivation.md</a> (805-line Schläfli derivation)</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/architecture/locked-vs-flexible.md">locked-vs-flexible.md</a> (12 architecture decisions to push back on)</li>
|
||||||
|
<li><a href="#proof">§6 Quality + test proof points</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="alignments">1. Research alignments — where this could be infrastructure for your work <a class="anchor" href="#alignments">#</a></h2>
|
||||||
|
|
||||||
|
<p>Most rows match an active publication line in discrete differential
|
||||||
|
geometry. Rows marked <i>no Java parent</i> are research-only phases
|
||||||
|
the reader can shape at design stage. The Phase column links to the
|
||||||
|
per-phase entry in <code>doc/roadmap/</code>.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead><tr><th>Reader's research thread</th><th>What this snapshot has</th><th>Phase</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Decorated DCE in non-Euclidean geometries</td>
|
||||||
|
<td>five DCE solvers + traits scaffolding; non-Euclidean cone extension scoped in research-track with acceptance criteria</td>
|
||||||
|
<td><span class="pill research">9d.2</span> RESEARCH</td></tr>
|
||||||
|
<tr><td>Canonical Delaunay tessellations of decorated hyperbolic surfaces</td>
|
||||||
|
<td>cut-graph + period matrix + hyperbolic-disk layout as scaffolding; canonical-tessellation algorithm itself outlined</td>
|
||||||
|
<td><span class="pill new">10c</span> planned</td></tr>
|
||||||
|
<tr><td>Hyperideal polyhedra rigidity</td>
|
||||||
|
<td>HyperIdeal functional + 805-line analytic Hessian derivation note (Schläfli identity)</td>
|
||||||
|
<td><span class="pill new">9b-analytic</span> derived; <span class="pill new">10c′</span> KAT planned</td></tr>
|
||||||
|
<tr><td>Optimal cone placement / non-Euclidean cone metrics</td>
|
||||||
|
<td>cone-singularity port via <code>ConesUtility</code> scoped; non-Euclidean extension is the research delta</td>
|
||||||
|
<td><span class="pill new">9d.1</span> port + <span class="pill research">9d.2</span> RESEARCH</td></tr>
|
||||||
|
<tr><td>Polygon Laplacian on general (non-triangular) meshes</td>
|
||||||
|
<td><i>no Java parent</i> — first phase the reader can influence at design stage</td>
|
||||||
|
<td><span class="pill research">9f</span> RESEARCH</td></tr>
|
||||||
|
<tr><td>Quasi-isothermic maps (Lawson correspondence, ~800 lines, discrete Beltrami-field solver)</td>
|
||||||
|
<td>scoped as a 6-class Java port: <code>QuasiisothermicLayout</code>, <code>DBFSolution</code>, <code>SinConditionApplication</code>, <code>QuasiisothermicDelaunay</code>, <code>QuasiisothermicUtility</code>, <code>ConformalStructureUtility</code></td>
|
||||||
|
<td><span class="pill new">10e</span> planned</td></tr>
|
||||||
|
<tr><td>Higher-genus + hyperelliptic surfaces (Bobenko–Bücking 2009; block-diagonal period matrices with Z₂ symmetry)</td>
|
||||||
|
<td>port of <code>HyperellipticUtility</code> + <code>HyperIdealHyperellipticUtility</code> scoped; existing period-matrix code as scaffolding</td>
|
||||||
|
<td><span class="pill new">10b</span> planned</td></tr>
|
||||||
|
<tr><td>Möbius centring as a variational problem (Lorentz energy, full gradient + Hessian)</td>
|
||||||
|
<td>currently iterative Fréchet mean in <code>normalise_hyperbolic()</code>; the principled variational alternative is scoped via the Java <code>MobiusCenteringFunctional</code> port</td>
|
||||||
|
<td><span class="pill new">9d.4</span> planned</td></tr>
|
||||||
|
<tr><td>Boundary-First / interactive flattening (Crane et al. 2017 BFF; Bonneel et al. 2015 <i>Stripe Patterns</i>)</td>
|
||||||
|
<td>not on the roadmap as ports; documented in <code>references.md</code> as comparison points / inspiration</td>
|
||||||
|
<td>—</td></tr>
|
||||||
|
<tr><td>Schläfli-based variational machinery (Rivin–Springborn 1999)</td>
|
||||||
|
<td>derivation done; implementation gated on the reader's view of whether the ~6× speedup over our block-FD path matters at their mesh sizes</td>
|
||||||
|
<td><span class="pill new">9b-analytic</span> ready</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="questions">2. Seven questions at a glance <a class="anchor" href="#questions">#</a></h2>
|
||||||
|
|
||||||
|
<p>The full text of each question lives in
|
||||||
|
<a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/questions.md">questions.md</a>.
|
||||||
|
The first two are research-oriented and benefit most from this
|
||||||
|
specific reader; the rest are scoped so "A / B / either" is a
|
||||||
|
sufficient answer.</p>
|
||||||
|
|
||||||
|
<table class="qtable">
|
||||||
|
<thead><tr><th>Q</th><th>Topic</th><th>Track</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Q1</td>
|
||||||
|
<td>Research-track alignment — which of 6 candidate phases (9d.2 / 9f / 10c+10c′ / 10e / 10b / 9d.4) would unblock concrete experiments you want to run?</td>
|
||||||
|
<td><span class="pill research">research</span></td></tr>
|
||||||
|
<tr><td>Q2</td>
|
||||||
|
<td>Decorated-DCE API surface — named parameter, separate <code>decorated_*</code> solvers, or property-map auto-detect?</td>
|
||||||
|
<td><span class="pill research">research</span></td></tr>
|
||||||
|
<tr><td>Q3</td>
|
||||||
|
<td>Phase 9b-analytic Hessian — is the ~6× speedup worth ~2 weeks at your mesh sizes?</td>
|
||||||
|
<td><span class="pill new">porting</span></td></tr>
|
||||||
|
<tr><td>Q4</td>
|
||||||
|
<td>Phase 9c (4g-polygon canonical form) — port literally or re-derive from Springborn 2020 §5?</td>
|
||||||
|
<td><span class="pill new">porting</span></td></tr>
|
||||||
|
<tr><td>Q5</td>
|
||||||
|
<td>geometry-central cross-validation (GC-1) — would you co-author?</td>
|
||||||
|
<td>collaboration</td></tr>
|
||||||
|
<tr><td>Q6</td>
|
||||||
|
<td>CGAL submission packaging — one package or several?</td>
|
||||||
|
<td>process</td></tr>
|
||||||
|
<tr><td>Q7</td>
|
||||||
|
<td>The "no" question — is there one of the 12 architecture decisions you would push back on?</td>
|
||||||
|
<td>process</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="new">3. What's new on this snapshot <a class="anchor" href="#new">#</a></h2>
|
||||||
|
|
||||||
|
<div class="box box-delta">
|
||||||
|
|
||||||
|
<p><b>Since the previous publish</b>, four threads converged:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><span class="pill new">+6 phases</span> from a full Java-library scan
|
||||||
|
(9d cones + 9d.4 variational Möbius centring / 9e circle-pattern
|
||||||
|
layout / 10d Koebe circle-domain / 10e quasi-isothermic / 10f
|
||||||
|
Koebe polyhedra / 10g cyclic-symmetry). See
|
||||||
|
<a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/java-parity.md">java-parity.md</a>
|
||||||
|
for the reverse table.</li>
|
||||||
|
<li><span class="pill new">+13 literature citations</span> integrated
|
||||||
|
into the per-phase roadmap with explicit acceptance criteria.
|
||||||
|
Decorated-DCE / canonical-tessellation / hyperideal line:
|
||||||
|
Bobenko–Lutz 2024 IMRN; Bobenko–Lutz 2025 <i>DCG</i>; Lutz 2023
|
||||||
|
<i>Geom. Dedicata</i>; Lutz 2024 PhD; Bowers–Bowers–Lutz 2026.
|
||||||
|
Cones, polyhedra, period matrices: Crane et al. 2018;
|
||||||
|
Springborn 2019; Bobenko–Bücking 2009; Rivin–Springborn 1999.
|
||||||
|
Polygon Laplacians: Alexa–Wardetzky 2011; Alexa 2020. Integrable
|
||||||
|
and practical-flattening context: Springborn–Veselov 2015;
|
||||||
|
Crane et al. 2017 (BFF); Bonneel et al. 2015 (Stripe Patterns).
|
||||||
|
</li>
|
||||||
|
<li><span class="pill research">+1 RESEARCH phase</span> with no Java
|
||||||
|
parent — Phase 9f (polygon Laplacian on non-triangular meshes,
|
||||||
|
Alexa-Wardetzky 2011 / Alexa 2020) — the first phase a reviewer
|
||||||
|
can shape at design stage.</li>
|
||||||
|
<li><span class="pill new">output_uv_map</span> now covers 4 of 5 DCE
|
||||||
|
solvers (Inversive-Distance added; CP-Euclidean deferred to
|
||||||
|
Phase 9c with a clear runtime error).</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="use">4. How you'd actually use this <a class="anchor" href="#use">#</a></h2>
|
||||||
|
|
||||||
|
<p>The library is header-only and standalone. Two-minute build + smoke
|
||||||
|
test:</p>
|
||||||
|
|
||||||
|
<pre><code>git clone https://codeberg.org/TMoussa/ConformalLabpp
|
||||||
|
cd ConformalLabpp
|
||||||
|
cmake -S code -B build && cmake --build build --target conformallab_tests
|
||||||
|
ctest --test-dir build # ~2 s · 23 pure-math tests
|
||||||
|
|
||||||
|
# CGAL solvers + layouts (adds Boost headers as system dep)
|
||||||
|
cmake -S code -B build -DWITH_CGAL_TESTS=ON
|
||||||
|
cmake --build build --target conformallab_cgal_tests -j
|
||||||
|
ctest --test-dir build # ~3 min · 236 CGAL tests</code></pre>
|
||||||
|
|
||||||
|
<p>One-call entry to compute a Euclidean discrete conformal map and a
|
||||||
|
UV-layout in a single shot:</p>
|
||||||
|
|
||||||
|
<pre><code>#include <CGAL/Surface_mesh.h>
|
||||||
|
#include <CGAL/Discrete_conformal_map.h>
|
||||||
|
|
||||||
|
CGAL::Surface_mesh<K::Point_3> mesh = ...; // your mesh
|
||||||
|
auto uv = mesh.add_property_map<V_idx, K::Point_2>("uv").first;
|
||||||
|
|
||||||
|
auto r = CGAL::discrete_conformal_map_euclidean(
|
||||||
|
mesh,
|
||||||
|
CGAL::parameters::output_uv_map(uv)
|
||||||
|
| CGAL::parameters::gradient_tolerance(1e-12));
|
||||||
|
// r.u_per_vertex, r.iterations, r.gradient_norm now populated.</code></pre>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>For adding your own functional or layout — pointer chain</summary>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/tutorials/add-inversive-distance.md">add-inversive-distance.md</a>
|
||||||
|
— step-by-step recipe for a sixth DCE model, used in real for the existing 9a.2 port.</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/tutorials/block-fd-hessian.md">block-fd-hessian.md</a>
|
||||||
|
— per-face block-FD pattern (96× over full-FD).</li>
|
||||||
|
<li><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/tutorials/add-output-uv-map.md">add-output-uv-map.md</a>
|
||||||
|
— <code>output_uv_map</code> named parameter + pipe-operator chaining.</li>
|
||||||
|
<li><b>For your decorated-DCE work specifically</b>: see
|
||||||
|
<a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/questions.md#q2--decorated-dce-api-surface-what-would-you-need-from-us-to-use-the-library-for-penner-coordinate-work">Q2 of the reviewer questions</a>
|
||||||
|
— three candidate API shapes, picking one would let us sketch a prototype in the week after the meeting.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="docs">5. Documents to read next <a class="anchor" href="#docs">#</a></h2>
|
||||||
|
|
||||||
|
<p>The four document folders most useful to a researcher. Click each
|
||||||
|
folder for the per-document table.</p>
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary>📋 Meeting materials — <code>doc/reviewer/</code> (read first)</summary>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Document</th><th>What it covers</th></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/briefing.md"><code>briefing.md</code></a></td>
|
||||||
|
<td>One-page orientation: research alignments (10-row table), what's new on this snapshot, the seven questions.</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/reviewer/questions.md"><code>questions.md</code></a></td>
|
||||||
|
<td>Full text of Q1–Q7. Q1 lists 6 candidate phases (9d.2 / 9f / 10c+10c′ / 10e / 10b / 9d.4); Q2 covers the decorated-DCE API surface; Q3–Q4 are porting decisions; Q5–Q6 project management; Q7 the open invitation to push back.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>🗺️ Roadmap — <code>doc/roadmap/</code> (where everything fits)</summary>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Document</th><th>What it covers</th></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/phases.md"><code>phases.md</code></a> <span class="pill new">+6 phases</span></td>
|
||||||
|
<td>Per-phase plan including the 6 new Java-scan phases (9d / 9e / 10d / 10e / 10f / 10g + 9d.4) and the 3 new research-only entries (9d.2 / 9f / 10c′).</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/research-track.md"><code>research-track.md</code></a> <span class="pill research">+2 RESEARCH</span></td>
|
||||||
|
<td>Items beyond Java parity, with explicit acceptance criteria: non-Euclidean cone extensions (9d.2), polygon Laplacian on non-triangular meshes (9f), geometry-central cross-validation (GC-1).</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/java-parity.md"><code>java-parity.md</code></a> <span class="pill new">full scan</span></td>
|
||||||
|
<td>Reverse table: every class in the Java original, where it lives in our port (or which phase will absorb it), or why it is intentionally not ported (the <i>do-not-port</i> list — Colt, PETSc, jReality wrappers).</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/roadmap/porting-status.md"><code>porting-status.md</code></a></td>
|
||||||
|
<td>Operational snapshot: 25 kLoC Java breakdown, 5-DCE-model status matrix, things Java doesn't have.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>📚 Mathematics & literature — <code>doc/math/</code></summary>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Document</th><th>What it covers</th></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/math/references.md"><code>references.md</code></a> <span class="pill new">+13 refs</span></td>
|
||||||
|
<td>Per-phase literature index. 13 new citations added: decorated DCE in non-Euclidean geometries (Bobenko–Lutz 2025); canonical tessellations (Lutz 2023 / 2024); hyperideal polyhedra rigidity (Bowers–Bowers–Lutz 2026); polygon Laplacians (Alexa–Wardetzky 2011 / Alexa 2020); optimal cone placement (Crane et al. 2018); Schläfli identity (Rivin–Springborn 1999); hyperbolic polyhedra (Springborn 2019); polyhedral period matrices (Bobenko–Bücking 2009); integrable cluster dynamics (Springborn–Veselov 2015); BFF (Crane et al. 2017); stripe patterns (Bonneel et al. 2015).</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/math/hyperideal-hessian-derivation.md"><code>hyperideal-hessian-derivation.md</code></a></td>
|
||||||
|
<td>Full LaTeX-formatted derivation of the analytic HyperIdeal Hessian via the Schläfli identity (805 lines, 8 sections + 2 appendices). Cited sources: Schläfli 1858, Milnor 1982, Vinberg 1993, Cho–Kim 1999, Glickenstein 2011, Rivin–Springborn 1999, Springborn 2020.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>🏗️ Architecture, dependencies & auto-generated reference</summary>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Document</th><th>What it covers</th></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/architecture/locked-vs-flexible.md"><code>locked-vs-flexible.md</code></a></td>
|
||||||
|
<td>12 architecture decisions classified 🔴 load-bearing / 🟡 semi-fixed / 🟢 opportunistic + a "Known limitations" table. Q7 of the reviewer questions points here to push back on anything.</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/architecture/dependencies.md"><code>dependencies.md</code></a></td>
|
||||||
|
<td>What's required (Eigen + CGAL + Boost headers) vs optional; per-tool install hints; standalone-verification recipe.</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/code/deps/THIRD-PARTY-LICENSES.md"><code>code/deps/THIRD-PARTY-LICENSES.md</code></a></td>
|
||||||
|
<td>Per-vendored-dep SPDX with MIT-compatibility analysis (LGPL §3 vs §4 distinction for header-only consumption of CGAL).</td></tr>
|
||||||
|
<tr><td><a href="doxygen.html">Doxygen HTML</a></td>
|
||||||
|
<td>259 pages, 0 warnings, 100 % public-API coverage (396 / 396 symbols). MathJax enabled for inline formulas.</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/api/headers.md"><code>api/headers.md</code></a></td>
|
||||||
|
<td>Auto-generated table of every public header with brief + symbols; regenerated on every push to main.</td></tr>
|
||||||
|
<tr><td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/doc/api/tests.md"><code>api/tests.md</code></a></td>
|
||||||
|
<td>Per-suite test breakdown (single source of truth). 259 tests, 0 skipped.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="proof">6. Quality & tests — proof points <a class="anchor" href="#proof">#</a></h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead><tr><th>Suite</th><th>Tests</th><th>Status</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Non-CGAL (pure-math)</td><td>23</td><td><span class="pill green">PASS</span> 0 skipped</td></tr>
|
||||||
|
<tr><td>CGAL (Surface_mesh + Phase 8b-Lite)</td><td>236</td><td><span class="pill green">PASS</span> 0 skipped</td></tr>
|
||||||
|
<tr><th>Total</th><th>259</th><th>0 failures</th></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Quality gates — 14 of 15 PASS, 1 SKIP (full breakdown)</summary>
|
||||||
|
|
||||||
|
<p class="small">Run with <code>bash scripts/quality/run-all.sh</code>. Four ★ gates are
|
||||||
|
required in CI on every PR; the rest are local-only and skip gracefully
|
||||||
|
on a partial dev environment.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead><tr><th>Gate</th><th>Where</th><th>Result</th><th>Detail</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>License headers ★</td><td>CI</td><td><span class="pill green">PASS</span></td><td>66/66 files carry MIT SPDX</td></tr>
|
||||||
|
<tr><td>CGAL conventions (6 rules) ★</td><td>CI</td><td><span class="pill green">PASS</span></td><td>0/6 violations across 6 CGAL public headers</td></tr>
|
||||||
|
<tr><td>codespell ★</td><td>CI</td><td><span class="pill green">PASS</span></td><td>0 typos</td></tr>
|
||||||
|
<tr><td>shellcheck ★ (strict)</td><td>CI</td><td><span class="pill green">PASS</span></td><td>0 findings across 16 shell scripts</td></tr>
|
||||||
|
<tr><td>clang-format drift</td><td>local</td><td><span class="pill green">PASS</span></td><td>0 drift against <code>.clang-format</code></td></tr>
|
||||||
|
<tr><td>cmake-format / cmake-lint</td><td>local</td><td><span class="pill green">PASS</span></td><td>0 drift, 0 lint findings</td></tr>
|
||||||
|
<tr><td>cppcheck</td><td>local</td><td><span class="pill green">PASS</span></td><td>warning+ severity clean</td></tr>
|
||||||
|
<tr><td>Markdown links</td><td>CI</td><td><span class="pill green">PASS</span></td><td>internal links resolve</td></tr>
|
||||||
|
<tr><td>Sanitizers (ASan + UBSan)</td><td>local</td><td><span class="pill green">PASS</span></td><td>23/23 tests pass under instrumentation</td></tr>
|
||||||
|
<tr><td>clang-tidy</td><td>local</td><td><span class="pill green">PASS</span></td><td>35 headers, 0 findings</td></tr>
|
||||||
|
<tr><td>Coverage (gcov + lcov)</td><td>local</td><td><span class="pill yellow">DEGRADED</span></td><td>23/23 tests run instrumented; lcov-on-macOS toolchain mismatch (works on Linux CI)</td></tr>
|
||||||
|
<tr><td>Multi-compiler</td><td>local</td><td><span class="pill green">PASS</span></td><td>AppleClang 17 + brew LLVM 22</td></tr>
|
||||||
|
<tr><td>Reproducible build</td><td>local</td><td><span class="pill green">PASS</span></td><td>byte-identical test binaries between 2 builds</td></tr>
|
||||||
|
<tr><td>Doxygen coverage</td><td>CI</td><td><span class="pill green">PASS</span></td><td>396 / 396 public symbols (100 %)</td></tr>
|
||||||
|
<tr><td>CGAL version matrix</td><td>local</td><td><span class="pill skip">SKIP</span></td><td>no CGAL tarballs under <code>~/cgal/</code> (graceful)</td></tr>
|
||||||
|
<tr><td>test-count consistency ★</td><td>CI</td><td><span class="pill green">PASS</span></td><td><code>tests.md</code> totals match ctest reality</td></tr>
|
||||||
|
<tr><td>End-to-end smoke (try_it.sh) ★</td><td>CI</td><td><span class="pill green">PASS</span></td><td>full configure + build + ctest + Euclidean example on a bundled mesh</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<!-- ════════════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="source">7. Source & navigation <a class="anchor" href="#source">#</a></h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td>Repo (this snapshot)</td>
|
||||||
|
<td><a href="https://codeberg.org/TMoussa/ConformalLabpp/src/branch/branch/main/">codeberg.org/TMoussa/ConformalLabpp/branch/main</a></td></tr>
|
||||||
|
<tr><td>Default branch</td>
|
||||||
|
<td><a href="https://codeberg.org/TMoussa/ConformalLabpp">codeberg.org/TMoussa/ConformalLabpp (main)</a></td></tr>
|
||||||
|
<tr><td>Doxygen HTML</td>
|
||||||
|
<td><a href="doxygen.html">259 pages, 0 warnings, 100 % coverage</a></td></tr>
|
||||||
|
<tr><td>Origin (private)</td>
|
||||||
|
<td><code>git.eulernest.eu/conformallab/ConformalLabpp</code></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
Reviewer-hub layout v6 — restructured for time-budget navigation, with
|
||||||
|
TL;DR + skim path up front and a sticky TOC. Built from
|
||||||
|
<code>branch/main</code> after merging PR #17 + PR #19
|
||||||
|
onto <code>main</code>. Status badges are static (snapshotted at publish
|
||||||
|
time, not live); the underlying CI workflow lives at
|
||||||
|
<code>.gitea/workflows/cpp-tests.yml</code> and re-runs on every push.
|
||||||
|
<a href="#top">↑ back to top</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
244
doc/reviewer/questions.md
Normal file
244
doc/reviewer/questions.md
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
# Questions for the external reviewer
|
||||||
|
|
||||||
|
> Please skim this before the meeting. Each question is scoped so that
|
||||||
|
> "do A" / "do B" / "either is fine" is a sufficient answer; deeper
|
||||||
|
> dives are welcome but not required.
|
||||||
|
|
||||||
|
These are the seven items that would benefit most from a second opinion.
|
||||||
|
|
||||||
|
* **Q1–Q2** are research-track questions — your active publication line
|
||||||
|
in **decorated DCE / Penner coordinates / canonical tessellations /
|
||||||
|
hyperideal polyhedra** makes you the best-positioned reader for them.
|
||||||
|
They ask whether conformallab++ could become *infrastructure for your
|
||||||
|
own future numerical experiments*, and what the minimum API surface
|
||||||
|
would be.
|
||||||
|
* **Q3–Q4** are porting decisions in our roadmap where your view of the
|
||||||
|
underlying mathematics would change the answer.
|
||||||
|
* **Q5–Q6** are project-management questions where peer input is
|
||||||
|
valuable but not blocking.
|
||||||
|
* **Q7** is an open invitation to push back on any architecture
|
||||||
|
decision you think we got wrong.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q1 — Research-track alignment: which RESEARCH or planned phase would unblock concrete experiments you want to run?
|
||||||
|
|
||||||
|
The roadmap now contains six phases close to live research lines,
|
||||||
|
each with concrete acceptance criteria (or, for the Java-port phases,
|
||||||
|
a clear specification from the Java original). Three are RESEARCH-only
|
||||||
|
(no Java parent, no immediate user request); three are Java-port
|
||||||
|
phases whose existence is settled but whose priority is open:
|
||||||
|
|
||||||
|
| Phase | Track | What it would add | Closest published line |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **9d.2** | RESEARCH | Decorated DCE in non-Euclidean (spherical + hyperbolic) geometries; Penner coordinates as first-class DOF; automatic cone placement for non-Euclidean targets | Decorated DCE in non-Euclidean geometries (2025, *Discrete Comput. Geom.*); optimal cone singularities for Euclidean flattening (2018, *SIGGRAPH*) |
|
||||||
|
| **9f** | RESEARCH | Discrete Laplace–Beltrami on **non-triangular** polygonal meshes (virtual-node / generalised cotangent), making DCE work on quad / Voronoi tessellations without re-triangulation | Polygon Laplacians (2011 *SIGGRAPH* + 2020 *TOG*) |
|
||||||
|
| **10c + 10c′** | planned | Canonical Delaunay tessellations of decorated hyperbolic surfaces; Koebe polyhedron realisation (KAT) with rigidity-aware Newton | Canonical tessellations of decorated hyperbolic surfaces (2023, *Geom. Dedicata*); rigidity of circle / hyperideal polyhedra (2026, preprint) |
|
||||||
|
| **10e** | planned | Quasi-isothermic maps (~800 lines Lawson-correspondence) — generalises conformality to meshes where exact conformality is impossible. Six new classes including a discrete Beltrami-field solver. | Java original `QuasiisothermicUtility` line; no obvious single-paper reference in the existing literature index |
|
||||||
|
| **10b** | planned | Hyperelliptic surfaces (genus g ≥ 2 with Z₂ symmetry); period matrices with block-diagonal structure; Penner-coordinate variant via `HyperIdealHyperellipticUtility` | Bobenko–Bücking 2009 *Conformal Structures and Period Matrices of Polyhedral Surfaces* |
|
||||||
|
| **9d.4** | planned | Möbius centring of Poincaré-disk layouts as a *variational* problem (Lorentz energy with full gradient + Hessian), replacing today's iterative Fréchet-mean fallback in `normalise_hyperbolic()` | Java original `MobiusCenteringFunctional`; closest published context: decorated-DCE Möbius normalisation, also used in canonical-tessellation post-processing |
|
||||||
|
|
||||||
|
**Question A:** which of these (if any) would unblock concrete
|
||||||
|
numerical experiments you have wanted to run but currently have no
|
||||||
|
reference implementation for?
|
||||||
|
|
||||||
|
**Question B:** for the one(s) you would use, would you want us to
|
||||||
|
target the *next* milestone after Phase 9c, or is there a different
|
||||||
|
order that would serve your research better?
|
||||||
|
|
||||||
|
**Question C:** is there a *seventh* line we are missing — a research
|
||||||
|
thread close to your own where you would want infrastructure that the
|
||||||
|
table above does not yet cover?
|
||||||
|
|
||||||
|
Context:
|
||||||
|
[`research-track.md`](../roadmap/research-track.md) §"Non-Euclidean
|
||||||
|
cone extensions" and §"Polygon Laplacian";
|
||||||
|
[`phases.md`](../roadmap/phases.md) for the per-phase porting plan;
|
||||||
|
[`java-parity.md`](../roadmap/java-parity.md) for the reverse Java
|
||||||
|
class table; the integrated literature sits in
|
||||||
|
[`math/references.md`](../math/references.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q2 — Decorated-DCE API surface: what would you need from us to use the library for Penner-coordinate work?
|
||||||
|
|
||||||
|
If you wanted to compute the variational energy + Newton update for
|
||||||
|
**decorated discrete conformal equivalence** (vertex `u`-DOFs plus
|
||||||
|
per-edge Penner decoration `λ_e`), the existing five-solver scaffold
|
||||||
|
gives us three plausible API directions:
|
||||||
|
|
||||||
|
- **(A) Named parameter on the existing Euclidean entry.**
|
||||||
|
`discrete_conformal_map_euclidean(mesh, parameters::penner_decoration_map(λ))`.
|
||||||
|
Smallest change; preserves the single-entry-per-geometry pattern;
|
||||||
|
hides the decoration as "just another property map".
|
||||||
|
- **(B) Separate `decorated_*` solver headers.**
|
||||||
|
New entry `CGAL::decorated_discrete_conformal_map_{euclidean,
|
||||||
|
spherical, hyperbolic}` with its own `Default_decorated_*_traits`.
|
||||||
|
Cleaner separation of concerns; mirrors the way CP-Euclidean and
|
||||||
|
Inversive-Distance are their own headers.
|
||||||
|
- **(C) Per-edge decoration as just another property map** that the
|
||||||
|
existing solvers consume when present (zero-decoration = current
|
||||||
|
behaviour by construction). Minimal API expansion; risk of
|
||||||
|
surprising convergence behaviour when decoration is silently zero
|
||||||
|
vs explicitly zero.
|
||||||
|
|
||||||
|
**Question:** which of A / B / C matches what you would expect from
|
||||||
|
a CGAL-style header? If "none of the above" — what would you write
|
||||||
|
in our place?
|
||||||
|
|
||||||
|
Context: Phase 9d.2 in
|
||||||
|
[`research-track.md`](../roadmap/research-track.md); the existing
|
||||||
|
named-parameter helpers in
|
||||||
|
[`code/include/CGAL/Conformal_map/internal/parameters.h`](../../code/include/CGAL/Conformal_map/internal/parameters.h).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q3 — Phase 9b-analytic Hessian: implement now or later?
|
||||||
|
|
||||||
|
We have:
|
||||||
|
|
||||||
|
- **Done**: per-face block-FD Hessian (96× faster than naive full-FD).
|
||||||
|
- **Derived but not implemented**: analytic Hessian via the Schläfli
|
||||||
|
identity, expected ~6× further speedup over block-FD.
|
||||||
|
- **Derivation document**:
|
||||||
|
[`doc/math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md)
|
||||||
|
(805 lines, all sign pitfalls covered, references Schläfli 1858,
|
||||||
|
Milnor 1982, Vinberg 1993, Cho–Kim 1999, Glickenstein 2011,
|
||||||
|
Springborn 2020, Rivin–Springborn 1999).
|
||||||
|
|
||||||
|
**Question:**
|
||||||
|
|
||||||
|
- At what mesh size does the ~6× become user-visible enough to
|
||||||
|
justify ~2 weeks of implementation work, given the typical sizes
|
||||||
|
in your work?
|
||||||
|
- Are you aware of subtleties in the Schläfli-based derivation our
|
||||||
|
document might be missing?
|
||||||
|
|
||||||
|
If the answer is "implement", we'd target Phase 9b-analytic right
|
||||||
|
after the meeting.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q4 — Phase 9c (4g-polygon canonical form): port-literal vs re-derive?
|
||||||
|
|
||||||
|
The Java original has two utility classes:
|
||||||
|
|
||||||
|
- `FundamentalPolygonUtility` (~600 lines)
|
||||||
|
- `CanonicalFormUtility` (~900 lines)
|
||||||
|
|
||||||
|
that together compute the canonical 4g-polygon for a higher-genus
|
||||||
|
surface from its cut graph.
|
||||||
|
|
||||||
|
We can either:
|
||||||
|
|
||||||
|
- **(A) Port literally** (~2 weeks). Faithful, predictable, fixes
|
||||||
|
the Java algorithm in C++. Down-side: we inherit the Java code's
|
||||||
|
ad-hoc style and edge-case handling.
|
||||||
|
- **(B) Re-derive from Springborn 2020 §5** (~3 weeks). Uses our
|
||||||
|
existing `cut_graph.hpp` + holonomy infrastructure cleanly.
|
||||||
|
Down-side: longer; potential for new bugs not seen by the Java
|
||||||
|
original's test cases.
|
||||||
|
|
||||||
|
**Question**: which route do you prefer, and is there a reference
|
||||||
|
implementation (Mathematica notebook, paper appendix, other research
|
||||||
|
codebase) we should cross-validate against?
|
||||||
|
|
||||||
|
Context: `doc/roadmap/phases.md` §Phase 9c, `doc/roadmap/porting-status.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q5 — geometry-central cross-validation (GC-1): would you co-author?
|
||||||
|
|
||||||
|
Two libraries solve the DCE problem from opposite algorithmic
|
||||||
|
directions:
|
||||||
|
|
||||||
|
- **conformallab++**: Newton on the fixed mesh (no intrinsic flips).
|
||||||
|
- **geometry-central**: Ptolemy flips on an intrinsic triangulation.
|
||||||
|
|
||||||
|
An automated comparison on common meshes would be:
|
||||||
|
|
||||||
|
- A short paper (the disagreement modes are interesting in their own
|
||||||
|
right and connect to the decorated-DCE framework via canonical
|
||||||
|
tessellation invariants).
|
||||||
|
- A confidence-building tool for both libraries.
|
||||||
|
- ~3 days of plumbing (CMake-fetch geometry-central, write 5 common
|
||||||
|
test meshes, compare `u_per_vertex` to a tolerance).
|
||||||
|
|
||||||
|
**Question:** would you be interested in co-authoring such a comparison
|
||||||
|
note (with us doing the implementation)? Or do you know someone in a
|
||||||
|
neighbouring group who would be a natural co-author?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q6 — CGAL submission strategy: one package or several?
|
||||||
|
|
||||||
|
For the long-term CGAL submission:
|
||||||
|
|
||||||
|
- **(A) One package** "Discrete_conformal_map" — single entry header,
|
||||||
|
five solver functions, one set of named parameters. Easier for
|
||||||
|
users to find; harder to compartmentalise reviews.
|
||||||
|
- **(B) Five packages** "Discrete_*" — each DCE model is its own
|
||||||
|
CGAL package with its own concept + reference manual. More
|
||||||
|
ceremony for users; more familiar review surface for CGAL editors.
|
||||||
|
|
||||||
|
Today the code is structured per-functional (Strategy C — see
|
||||||
|
[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) §7).
|
||||||
|
Either submission packaging is achievable from this base.
|
||||||
|
|
||||||
|
**Question:** what's the CGAL editor convention for related-but-distinct
|
||||||
|
algorithms — `Polygon_mesh_processing` as one example (one package, many
|
||||||
|
algorithms), vs `Triangulation_2`/`Triangulation_3`/`Periodic_*`/
|
||||||
|
`Hyperbolic_*` as another (multiple packages for related algorithms)?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q7 — The "no" question (this is the highest-value answer)
|
||||||
|
|
||||||
|
Looking at any of the 12 architecture decisions in
|
||||||
|
[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md), is
|
||||||
|
there one where you think *"no, that's the wrong call, here's why"*?
|
||||||
|
|
||||||
|
This is a deliberately blunt question because positive feedback is
|
||||||
|
nice but negative feedback is rarer and more valuable. The 🔴
|
||||||
|
load-bearing decisions are the most consequential to revisit, because
|
||||||
|
waiting longer makes them more expensive:
|
||||||
|
|
||||||
|
- **#1** `CGAL::Surface_mesh<P>` as default mesh
|
||||||
|
- **#3** header-only, no compiled library
|
||||||
|
- **#6** Eigen as linear-algebra back-end
|
||||||
|
- **#11** MIT license (only relevant if it conflicts with a CGAL-
|
||||||
|
submission constraint)
|
||||||
|
|
||||||
|
"No" is the most useful answer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Things you do *not* need to comment on (unless you want)
|
||||||
|
|
||||||
|
- C++ style choices captured in `.clang-format` + `.clang-tidy`.
|
||||||
|
- Test framework choice (GTest).
|
||||||
|
- License (MIT, with vendored deps catalogued in
|
||||||
|
[`code/deps/THIRD-PARTY-LICENSES.md`](../../code/deps/THIRD-PARTY-LICENSES.md)).
|
||||||
|
- Build system (CMake ≥ 3.20, header-only consumer + optional
|
||||||
|
CLI/Viewer).
|
||||||
|
- Documentation tooling (Doxygen with auto-generated `headers.md`).
|
||||||
|
|
||||||
|
These are conscious decisions matched to CGAL conventions and are
|
||||||
|
not load-bearing in the sense that revisiting them later is cheap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## After the meeting — would you collaborate?
|
||||||
|
|
||||||
|
A separate "after the meeting" conversation, but flagged here so it
|
||||||
|
does not surprise you on the day:
|
||||||
|
|
||||||
|
- **Acknowledgement** in any future CGAL submission / paper would be
|
||||||
|
the default, and we would ask first.
|
||||||
|
- **Co-authorship** on Q5 (the GC-1 cross-validation note) is on the
|
||||||
|
table if you said yes there.
|
||||||
|
- **Periodic update cadence** (quarterly? per-milestone?) — open
|
||||||
|
question, no expectation.
|
||||||
|
- **Pull requests** from your side are welcome and reviewable on the
|
||||||
|
Codeberg repo. We would not expect them — but we would not turn
|
||||||
|
them away either.
|
||||||
@@ -22,7 +22,8 @@ as the reference implementation for expected behaviour, edge cases, and test cas
|
|||||||
| HyperIdeal Hessian — analytic via ζ → l → β/α | ❌ *(`hasHessian()==false`)* | ⚠️ FD (Phase 4a) → block-FD (Phase 9b) | **Java has NO Hessian for HyperIdeal** (verified: `HyperIdealFunctional.java:295-298` declares `hasHessian() { return false; }`). Both C++ Hessian variants are **new research beyond Java**; analytic Schläfli-based variant is Phase 9b-analytic. |
|
| HyperIdeal Hessian — analytic via ζ → l → β/α | ❌ *(`hasHessian()==false`)* | ⚠️ FD (Phase 4a) → block-FD (Phase 9b) | **Java has NO Hessian for HyperIdeal** (verified: `HyperIdealFunctional.java:295-298` declares `hasHessian() { return false; }`). Both C++ Hessian variants are **new research beyond Java**; analytic Schläfli-based variant is Phase 9b-analytic. |
|
||||||
| Newton solver | ✅ | ✅ | |
|
| Newton solver | ✅ | ✅ | |
|
||||||
| SparseQR fallback for gauge modes | unknown | ✅ | New in C++ |
|
| SparseQR fallback for gauge modes | unknown | ✅ | New in C++ |
|
||||||
| Cone metrics — prescribed Θᵥ ≠ 2π | ✅ fully | ⚠️ data structure only | |
|
| Cone metrics — prescribed Θᵥ ≠ 2π (Euclidean) | ✅ fully | ❌ Phase 9d.1 (port) | Java Euclidean-only; `ConesUtility.java` ~200 lines |
|
||||||
|
| Cone metrics — non-Euclidean (HyperIdeal / Spherical) | ❌ *(not in Java)* | ❌ Phase 9d.2 (research) | **No Java source.** Mathematical basis: Bobenko-Lutz 2025 (decorated DCE) + Crane et al. 2018 (optimal cone placement). |
|
||||||
| Layout / embedding — ℝ² / H² / S² | ✅ | ✅ priority-BFS all three | |
|
| Layout / embedding — ℝ² / H² / S² | ✅ | ✅ priority-BFS all three | |
|
||||||
| Exact hyperbolic trilateration | ✅ Möbius | ✅ Möbius + law of cosines | |
|
| Exact hyperbolic trilateration | ✅ Möbius | ✅ Möbius + law of cosines | |
|
||||||
| halfedge_uv — seam-aware UV (texture atlas) | ✅ | ✅ | |
|
| halfedge_uv — seam-aware UV (texture atlas) | ✅ | ✅ | |
|
||||||
@@ -49,6 +50,7 @@ They are candidates for Phase 9 or Phase 10.
|
|||||||
|
|
||||||
| Java class | Description | Phase |
|
| Java class | Description | Phase |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| `ConesUtility` (~200 lines) | Prescribed cone angles Θᵥ ≠ 2π — Euclidean mode only | 9d.1 |
|
||||||
| `CPEuclideanFunctional` | Face-based circle-packing energy (BPS 2010) | 9a.1 |
|
| `CPEuclideanFunctional` | Face-based circle-packing energy (BPS 2010) | 9a.1 |
|
||||||
| `FundamentalPolygonUtility` (698 lines) | Construction + canonicalisation of 4g-gons for genus-g | 9c |
|
| `FundamentalPolygonUtility` (698 lines) | Construction + canonicalisation of 4g-gons for genus-g | 9c |
|
||||||
| `CanonicalFormUtility` (532 lines) | High-level wrapper for 9c — drives canonicalisation pipeline | 9c |
|
| `CanonicalFormUtility` (532 lines) | High-level wrapper for 9c — drives canonicalisation pipeline | 9c |
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ mesh type.
|
|||||||
9b-analytic Full analytic HyperIdeal Hessian via Schläfli identity
|
9b-analytic Full analytic HyperIdeal Hessian via Schläfli identity
|
||||||
→ planned, see research-track.md
|
→ planned, see research-track.md
|
||||||
Mathematical source: Springborn 2020 §4 + Schläfli 1858/60
|
Mathematical source: Springborn 2020 §4 + Schläfli 1858/60
|
||||||
|
+ Rivin, Springborn 1999 "The Schläfli formula in
|
||||||
|
Einstein manifolds with boundary" (ERA-AMS 5)
|
||||||
+ Cho-Kim 1999 + Glickenstein 2011 §4
|
+ Cho-Kim 1999 + Glickenstein 2011 §4
|
||||||
Algorithm: explicit chain rule through (bᵢ,aₑ) → ℓᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ
|
Algorithm: explicit chain rule through (bᵢ,aₑ) → ℓᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ
|
||||||
Includes: short LaTeX correctness note in doc/math/.
|
Includes: short LaTeX correctness note in doc/math/.
|
||||||
@@ -129,7 +131,7 @@ mesh type.
|
|||||||
layer, +1 week integration.
|
layer, +1 week integration.
|
||||||
```
|
```
|
||||||
|
|
||||||
9d — Cone metrics + sphere utilities (Java port — 2026 library scan)
|
9d — Cone metrics + sphere utilities (Java port + research extension)
|
||||||
────────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -142,14 +144,28 @@ mesh type.
|
|||||||
- Quantization: snap cone angles to π/2, π/3, π/6 for
|
- Quantization: snap cone angles to π/2, π/3, π/6 for
|
||||||
quad / triangle / hexagonal atlas targets
|
quad / triangle / hexagonal atlas targets
|
||||||
Java reference: unwrapper/ConesUtility.java
|
Java reference: unwrapper/ConesUtility.java
|
||||||
|
Mathematical reference: Troyanov 1991 + Springborn 2020 §3
|
||||||
|
|
||||||
9d.2 StereographicUnwrapper + SphereUtility (Java port)
|
9d.2 Non-Euclidean cone extensions (RESEARCH, not in Java)
|
||||||
|
→ extend ConesUtility to HyperIdeal + Spherical modes
|
||||||
|
Java source: NONE — Java ConesUtility is Euclidean-only.
|
||||||
|
Mathematical reference:
|
||||||
|
Bobenko, Lutz 2025 "Decorated Discrete Conformal Equivalence in
|
||||||
|
Non-Euclidean Geometries" (Discrete & Comput. Geom. 2025,
|
||||||
|
arXiv:2310.17529) §3 — decorated DCE framework unifying cone
|
||||||
|
singularities and cusps in hyperbolic + spherical geometry.
|
||||||
|
Crane, Soliman, Ben-Chen, Schröder 2018 "Optimal Cone Singularities
|
||||||
|
for Conformal Flattening" (ACM SIGGRAPH 2018) — L¹-optimal
|
||||||
|
automatic cone placement; directly applicable to 9d.2 algorithm.
|
||||||
|
Status: 🔲 planned
|
||||||
|
|
||||||
|
9d.3 StereographicUnwrapper + SphereUtility (Java port)
|
||||||
→ stereographic_layout.hpp
|
→ stereographic_layout.hpp
|
||||||
Stereographic projection S²→ℂ∪{∞} + Möbius centering for
|
Stereographic projection S²→ℂ∪{∞} + Möbius centering for
|
||||||
genus-0 surfaces. Converts spherical DCE output to a flat 2-D atlas.
|
genus-0 surfaces. Converts spherical DCE output to a flat 2-D atlas.
|
||||||
Java reference: unwrapper/StereographicUnwrapper.java (266 lines)
|
Java reference: unwrapper/StereographicUnwrapper.java (266 lines)
|
||||||
|
|
||||||
9d.3 MobiusCenteringFunctional (Java port, optional upgrade)
|
9d.4 MobiusCenteringFunctional (Java port, optional upgrade)
|
||||||
→ integrate into layout.hpp normalise_hyperbolic()
|
→ integrate into layout.hpp normalise_hyperbolic()
|
||||||
Variational Möbius centering via Lorentz geometry:
|
Variational Möbius centering via Lorentz geometry:
|
||||||
E = Σ log(-⟨x,p⟩/√(-⟨x,x⟩))
|
E = Σ log(-⟨x,p⟩/√(-⟨x,x⟩))
|
||||||
@@ -170,6 +186,30 @@ mesh type.
|
|||||||
- CPEuclideanRotation: rotation-invariant CP functional variant
|
- CPEuclideanRotation: rotation-invariant CP functional variant
|
||||||
Java references: unwrapper/circlepattern/CirclePattern{Layout,Utility}.java
|
Java references: unwrapper/circlepattern/CirclePattern{Layout,Utility}.java
|
||||||
unwrapper/circlepattern/CPEuclideanRotation.java
|
unwrapper/circlepattern/CPEuclideanRotation.java
|
||||||
|
Mathematical reference: Bobenko-Springborn 2004 variational principle
|
||||||
|
+ Bobenko-Hoffmann-Springborn 2006 "Minimal
|
||||||
|
surfaces from circle patterns" (Discrete &
|
||||||
|
Comput. Geom. 35, 2006).
|
||||||
|
```
|
||||||
|
|
||||||
|
9f — Polygon Laplacian (RESEARCH — no Java equivalent)
|
||||||
|
──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
```
|
||||||
|
9f Discrete Laplacian on general polygonal meshes
|
||||||
|
→ polygon_laplacian.hpp
|
||||||
|
Java source: NONE
|
||||||
|
Mathematical reference:
|
||||||
|
Alexa, Wardetzky 2011 "Discrete Laplacians on General Polygonal
|
||||||
|
Meshes" (ACM SIGGRAPH 2011) — virtual-node construction,
|
||||||
|
polygon cotangent weights extending the Pinkall-Polthier formula.
|
||||||
|
Alexa 2020 "Discrete Laplacians on General Polygonal Meshes"
|
||||||
|
(ACM TOG 39, 2020) — extended journal treatment, error bounds.
|
||||||
|
Enables: DCE energy evaluation on quad-dominant / Voronoi /
|
||||||
|
polygon meshes without forced triangulation.
|
||||||
|
Replaces euclidean_hessian.hpp for non-triangular inputs.
|
||||||
|
Status: 🔲 planned (pure research, no Java source)
|
||||||
|
Effort: medium (~2 weeks core + tests; +1 week Newton integration).
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -283,6 +323,12 @@ Phase 10 Global uniformization for genus g ≥ 2
|
|||||||
10a Discrete holomorphic and harmonic 1-forms
|
10a Discrete holomorphic and harmonic 1-forms
|
||||||
→ Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
|
→ Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
|
||||||
Mathematical reference: Bobenko-Springborn 2004 §6 + Mercat 2001.
|
Mathematical reference: Bobenko-Springborn 2004 §6 + Mercat 2001.
|
||||||
|
Knöppel, Crane, Pinkall, Schröder 2015 "Stripe
|
||||||
|
Patterns on Surfaces" (ACM SIGGRAPH 2015) —
|
||||||
|
application of discrete holomorphic 1-forms to
|
||||||
|
direction field design; provides an independent
|
||||||
|
C++ reference implementation (geometry-central)
|
||||||
|
for cross-validating the Phase 10a computation.
|
||||||
Java sources (partial, port-with-research):
|
Java sources (partial, port-with-research):
|
||||||
CanonicalBasisUtility.java 337 lines (homology basis)
|
CanonicalBasisUtility.java 337 lines (homology basis)
|
||||||
HomologyUtility.java 122 lines
|
HomologyUtility.java 122 lines
|
||||||
@@ -295,6 +341,17 @@ Phase 10 Global uniformization for genus g ≥ 2
|
|||||||
→ Ωᵢⱼ = ∫_{bⱼ} ωᵢ
|
→ Ωᵢⱼ = ∫_{bⱼ} ωᵢ
|
||||||
→ Reduction to Siegel fundamental domain via Sp(2g,ℤ).
|
→ Reduction to Siegel fundamental domain via Sp(2g,ℤ).
|
||||||
Mathematical reference: Bobenko-Springborn 2004 + Gottschling 1959.
|
Mathematical reference: Bobenko-Springborn 2004 + Gottschling 1959.
|
||||||
|
Bobenko, Bücking 2009 "Conformal Structures and
|
||||||
|
Period Matrices of Polyhedral Surfaces" — discrete
|
||||||
|
period matrix Ωᵢⱼ on polyhedral surfaces.
|
||||||
|
Bobenko, Lutz 2024 IMRN "Decorated Discrete Conformal
|
||||||
|
Maps and Convex Polyhedral Cusps" — uniformization
|
||||||
|
theorem connecting cusps ↔ hyperideal vertices
|
||||||
|
(bridges Phase 2/3 HyperIdeal geometry to 10b).
|
||||||
|
Springborn 2019 "A discrete version of Liouville's
|
||||||
|
theorem on conformal maps" (arXiv:1911.00966) —
|
||||||
|
proves uniqueness/rigidity of the discrete conformal
|
||||||
|
structure; justifies that Ω is a conformal invariant.
|
||||||
Java partial reference: DiscreteRiemannUtility.java (186 lines).
|
Java partial reference: DiscreteRiemannUtility.java (186 lines).
|
||||||
Requires: 10a.
|
Requires: 10a.
|
||||||
Effort: ~1 week net after 10a.
|
Effort: ~1 week net after 10a.
|
||||||
@@ -318,6 +375,20 @@ Phase 10 Global uniformization for genus g ≥ 2
|
|||||||
→ Embedding as H²/Γ with Γ ⊂ PSL(2,ℝ) a Fuchsian group.
|
→ Embedding as H²/Γ with Γ ⊂ PSL(2,ℝ) a Fuchsian group.
|
||||||
Mathematical reference: Sechelmann 2016 §6 (discrete instance);
|
Mathematical reference: Sechelmann 2016 §6 (discrete instance);
|
||||||
Bers 1960 (continuous theory).
|
Bers 1960 (continuous theory).
|
||||||
|
Lutz 2023 "Canonical Tessellations of Decorated
|
||||||
|
Hyperbolic Surfaces" (Geom. Dedicata 217,
|
||||||
|
arXiv:2206.13461) — canonical Delaunay tessellations
|
||||||
|
in Penner coordinates; unifies the decorated
|
||||||
|
framework with the fundamental domain construction.
|
||||||
|
Bobenko, Lutz 2024 IMRN (arXiv:2305.10988) —
|
||||||
|
discrete uniformization theorem for decorated
|
||||||
|
piecewise Euclidean surfaces.
|
||||||
|
Springborn, Veselov 2015 "Quasiconformal distortion
|
||||||
|
of projective transformations and discrete conformal
|
||||||
|
maps" (Int. Math. Res. Not.) — error estimates for
|
||||||
|
the discrete-to-smooth conformal approximation;
|
||||||
|
quantifies how well H²/Γ approximates the smooth
|
||||||
|
hyperbolic metric.
|
||||||
Java reference: NONE — Java has the polygon + period matrix
|
Java reference: NONE — Java has the polygon + period matrix
|
||||||
pieces but does not assemble them into
|
pieces but does not assemble them into
|
||||||
a Fuchsian-group representation.
|
a Fuchsian-group representation.
|
||||||
@@ -327,6 +398,9 @@ Phase 10 Global uniformization for genus g ≥ 2
|
|||||||
10c' Optional Java-port additions (low priority)
|
10c' Optional Java-port additions (low priority)
|
||||||
→ KoebePolyhedron.java (321 lines) — Koebe-Andreev-Thurston
|
→ KoebePolyhedron.java (321 lines) — Koebe-Andreev-Thurston
|
||||||
circle packings. Adds a fifth DCE method.
|
circle packings. Adds a fifth DCE method.
|
||||||
|
Rigidity: Bowers, Bowers, Lutz 2026 "Rigidity of circle polyhedra
|
||||||
|
and hyperideal polyhedra: the tangency case" (arXiv:2601.22903)
|
||||||
|
— theoretical uniqueness backing the KAT construction.
|
||||||
→ ElectrostaticSphereFunctional (127 lines) — sphere
|
→ ElectrostaticSphereFunctional (127 lines) — sphere
|
||||||
distribution baseline.
|
distribution baseline.
|
||||||
→ CirclePatternLayout / CirclePatternUtility — face-circle
|
→ CirclePatternLayout / CirclePatternUtility — face-circle
|
||||||
|
|||||||
@@ -211,6 +211,77 @@ The phase numbers match `doc/roadmap/phases.md`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Non-Euclidean cone extensions (Phase 9d.2, 🔲 planned)
|
||||||
|
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Bobenko, Lutz** (2025). *Decorated Discrete Conformal Equivalence in
|
||||||
|
Non-Euclidean Geometries.* Discrete & Comput. Geom. arXiv:2310.17529.
|
||||||
|
→ §3: Penner-coordinate decoration unifies cone singularities (Θᵥ ≠ 2π)
|
||||||
|
and hyperideal cusps (Θᵥ = 0) in a single algebraic framework valid in
|
||||||
|
Euclidean, spherical, and hyperbolic geometry.
|
||||||
|
- **Crane, Soliman, Ben-Chen, Schröder** (2018). *Optimal Cone Singularities
|
||||||
|
for Conformal Flattening.* ACM SIGGRAPH 2018. DOI: 10.1145/3197517.3201367.
|
||||||
|
→ L¹-optimal cone placement via a sparse-recovery optimisation over the
|
||||||
|
curvature deficit Kᵥ = 2π − Θᵥ; directly gives the set of cone angles
|
||||||
|
to prescribe for a near-flat conformal parametrisation.
|
||||||
|
- **Lutz** (2024). *PhD thesis, TU Berlin.* DOI: 10.14279/depositonce-20357.
|
||||||
|
→ Full proofs for both non-Euclidean decorated DCE variants; single reference
|
||||||
|
covering 9d.2, 10b, and 10c.
|
||||||
|
|
||||||
|
* **Java reference:** ❌ **none.** Java `ConesUtility.java` handles only the
|
||||||
|
Euclidean case; the non-Euclidean extension is new research.
|
||||||
|
|
||||||
|
* **Scope:**
|
||||||
|
- Extend `cones_utility.hpp` (Phase 9d.1, Java port) to accept prescribed
|
||||||
|
cone angles in HyperIdeal and Spherical modes.
|
||||||
|
- Integrate the Bobenko-Lutz decoration into the variational framework of
|
||||||
|
`hyper_ideal_functional.hpp` and `spherical_functional.hpp`.
|
||||||
|
- Optionally: implement the Crane 2018 L¹-optimiser as a helper that
|
||||||
|
suggests cone positions automatically from the input curvature.
|
||||||
|
|
||||||
|
* **Status:** 🔲 planned; no PR yet.
|
||||||
|
* **Effort:** medium (1–2 weeks for Euclidean→HyperIdeal/Spherical extension;
|
||||||
|
+1 week if Crane 2018 optimiser is included).
|
||||||
|
* **Acceptance criteria:**
|
||||||
|
- Prescribed Θᵥ ≠ 2π in HyperIdeal mode: Gauss-Bonnet check passes with
|
||||||
|
`2π·χ = Σ Θᵥ − Σ αᵢⱼ` for given cone angles.
|
||||||
|
- Newton convergence on a mesh with two manually placed cone singularities
|
||||||
|
(Euclidean, Spherical, HyperIdeal).
|
||||||
|
- Cross-validation: at Θᵥ = 2π for all v, output equals existing non-cone solver.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Polygon Laplacian (Phase 9f, 🔲 planned)
|
||||||
|
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Alexa, Wardetzky** (2011). *Discrete Laplacians on General Polygonal
|
||||||
|
Meshes.* ACM SIGGRAPH 2011. DOI: 10.1145/1964921.1964997.
|
||||||
|
→ Virtual-node construction: each polygon face is replaced by a virtual
|
||||||
|
central node connected to all vertices; cotangent weights are computed
|
||||||
|
per sub-triangle; the resulting operator is symmetric and positive
|
||||||
|
semi-definite, mirroring Pinkall-Polthier for triangulations.
|
||||||
|
- **Alexa** (2020). *Discrete Laplacians on General Polygonal Meshes.*
|
||||||
|
ACM TOG 39(6). DOI: 10.1145/3414685.3417840.
|
||||||
|
→ Extended journal version with error bounds and convergence analysis.
|
||||||
|
|
||||||
|
* **Java reference:** ❌ **none.**
|
||||||
|
|
||||||
|
* **Scope:**
|
||||||
|
- Implement `polygon_laplacian.hpp` following the virtual-node construction.
|
||||||
|
- Slot it into `newton_solver.hpp` as a drop-in replacement for
|
||||||
|
`euclidean_hessian.hpp` when the input mesh is non-triangular.
|
||||||
|
- No change to the energy functional — only the Hessian approximation changes.
|
||||||
|
|
||||||
|
* **Status:** 🔲 planned; pure research, no Java reference.
|
||||||
|
* **Effort:** medium (~2 weeks core + tests; +1 week Newton integration).
|
||||||
|
* **Acceptance criteria:**
|
||||||
|
- Operator is symmetric and PSD (checked via `LDLT.info() == Success`).
|
||||||
|
- On a pure triangle mesh, output equals `euclidean_hessian.hpp` result.
|
||||||
|
- Newton convergence on a quad mesh (e.g., structured grid) with the
|
||||||
|
polygon Laplacian Hessian.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Genus g ≥ 2 fundamental domain (Phase 9c, 🔲 planned)
|
### Genus g ≥ 2 fundamental domain (Phase 9c, 🔲 planned)
|
||||||
* **Mathematical sources:**
|
* **Mathematical sources:**
|
||||||
- **Poincaré, H.** (1882). *Théorie des groupes fuchsiens.*
|
- **Poincaré, H.** (1882). *Théorie des groupes fuchsiens.*
|
||||||
|
|||||||
Reference in New Issue
Block a user