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,
|
||||
categorise,categorised,categorises,categorising,
|
||||
optimisation,optimisations,
|
||||
acknowledgement,acknowledgements,acknowledging,
|
||||
neighbour,neighbours,neighbouring,neighboured,
|
||||
labelled,labelling,labels,labelled,
|
||||
fulfil,fulfils,fulfilled,fulfilling,
|
||||
|
||||
@@ -112,3 +112,51 @@ jobs:
|
||||
# the price of guaranteeing the documented workflow stays working.
|
||||
- name: End-to-end smoke test (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: |
|
||||
set -eu
|
||||
# Build the publish payload in a clean scratch dir so the
|
||||
# orphan branch contains only the Doxygen output (and a
|
||||
# marker README), never any build/source artefacts.
|
||||
# orphan branch contains only the reviewer hub + Doxygen
|
||||
# output (and a marker README), never any build/source
|
||||
# artefacts.
|
||||
publish_dir=$(mktemp -d)
|
||||
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
|
||||
conformallab++ — Doxygen HTML API documentation.
|
||||
conformallab++ — Doxygen HTML API documentation + reviewer hub.
|
||||
Auto-generated by .gitea/workflows/doxygen-pages.yml from
|
||||
commit ${GITHUB_SHA:-$(git rev-parse HEAD)} on $(date -Iseconds).
|
||||
Source: https://codeberg.org/TMoussa/ConformalLabpp
|
||||
Reviewer hub: doc/reviewer/hub.html (in-repo)
|
||||
Doxygen index: /doxygen.html
|
||||
EOF
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
1
code/.gitignore
vendored
1
code/.gitignore
vendored
@@ -13,6 +13,7 @@ deps/*
|
||||
!deps/tarballs
|
||||
!deps/single_includes/
|
||||
!deps/CMakeLists.txt
|
||||
!deps/THIRD-PARTY-LICENSES.md
|
||||
|
||||
# macOS iCloud Drive duplicates ("file 2.cpp", "file 2.hpp", …)
|
||||
* 2.*
|
||||
|
||||
@@ -38,8 +38,9 @@ if(WITH_CGAL AND NOT WITH_VIEWER)
|
||||
set(WITH_VIEWER ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
# Propagate Boost requirement for both CGAL modes.
|
||||
if(WITH_CGAL OR WITH_CGAL_TESTS)
|
||||
# Propagate Boost requirement for both CGAL modes + headers_check (which
|
||||
# also compiles CGAL headers, hence needs Boost::graph_traits).
|
||||
if(WITH_CGAL OR WITH_CGAL_TESTS OR CONFORMALLAB_HEADERS_CHECK)
|
||||
find_package(Boost REQUIRED)
|
||||
endif()
|
||||
|
||||
@@ -54,6 +55,59 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
||||
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")
|
||||
# ─── Compiler-warning policy ─────────────────────────────────────────────
|
||||
# `-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()
|
||||
|
||||
# ── 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(CTest)
|
||||
enable_testing()
|
||||
include(CTest) # also defines BUILD_TESTING (default ON)
|
||||
|
||||
FetchContent_Declare(
|
||||
if(BUILD_TESTING)
|
||||
enable_testing()
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG v1.14.0
|
||||
)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
endif()
|
||||
|
||||
# ── External deps (lazy tarball extraction) ────────────────────────────────────
|
||||
add_subdirectory(deps)
|
||||
@@ -142,8 +205,67 @@ if(WITH_CGAL)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# ── Tests (always) ────────────────────────────────────────────────────────────
|
||||
add_subdirectory(tests)
|
||||
# ── Tests (gated on BUILD_TESTING) ────────────────────────────────────────────
|
||||
#
|
||||
# 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) ──────────────────────────────────────
|
||||
# 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 "../newton_solver.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
// ── Default traits for CP-Euclidean ───────────────────────────────────────────
|
||||
@@ -186,6 +188,45 @@ auto discrete_circle_packing_euclidean(
|
||||
result.iterations = nr.iterations;
|
||||
result.gradient_norm = nr.grad_inf_norm;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,6 +207,54 @@ auto discrete_inversive_distance_map(
|
||||
result.iterations = nr.iterations;
|
||||
result.gradient_norm = nr.grad_inf_norm;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
// After translation and projection to the Poincaré disk their circumcircle
|
||||
// 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 <cmath>
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
// `Kernel_d::Point_3` (test scaffolding).
|
||||
|
||||
#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>
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
// Ported from de.jreality.math.Pn / Rn and
|
||||
// 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 <algorithm>
|
||||
#include <array>
|
||||
|
||||
@@ -27,6 +27,15 @@ target_include_directories(conformallab_tests PRIVATE
|
||||
|
||||
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)
|
||||
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>
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# ── 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)
|
||||
gtest_discover_tests(conformallab_cgal_tests
|
||||
TEST_PREFIX "cgal."
|
||||
|
||||
@@ -288,6 +288,60 @@ TEST(CGALPhase8bLite, OutputUvMap_HyperIdeal_PointsInPoincareDisk)
|
||||
// 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)
|
||||
{
|
||||
// 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) |
|
||||
| `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 |
|
||||
| `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
|
||||
> on first principles and easy to revisit).
|
||||
>
|
||||
> **Why this matters now.** A v0.9.0 + Springborn-Bobenko-alumnus
|
||||
> external review (May 2026) is the right moment to surface these
|
||||
> **Why this matters now.** A v0.9.0 snapshot + external review by
|
||||
> 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 need revisiting, this is the cheapest moment in the
|
||||
> 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 |
|
||||
|---|---|---|
|
||||
| **`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) |
|
||||
| **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 |
|
||||
|
||||
@@ -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 |
|
||||
| **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 |
|
||||
| **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 |
|
||||
| **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, 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. |
|
||||
| Newton solver | ✅ | ✅ | |
|
||||
| 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 | |
|
||||
| Exact hyperbolic trilateration | ✅ Möbius | ✅ Möbius + law of cosines | |
|
||||
| halfedge_uv — seam-aware UV (texture atlas) | ✅ | ✅ | |
|
||||
@@ -49,6 +50,7 @@ They are candidates for Phase 9 or Phase 10.
|
||||
|
||||
| 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 |
|
||||
| `FundamentalPolygonUtility` (698 lines) | Construction + canonicalisation of 4g-gons for genus-g | 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
|
||||
→ planned, see research-track.md
|
||||
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
|
||||
Algorithm: explicit chain rule through (bᵢ,aₑ) → ℓᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ
|
||||
Includes: short LaTeX correctness note in doc/math/.
|
||||
@@ -129,7 +131,7 @@ mesh type.
|
||||
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
|
||||
quad / triangle / hexagonal atlas targets
|
||||
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 projection S²→ℂ∪{∞} + Möbius centering for
|
||||
genus-0 surfaces. Converts spherical DCE output to a flat 2-D atlas.
|
||||
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()
|
||||
Variational Möbius centering via Lorentz geometry:
|
||||
E = Σ log(-⟨x,p⟩/√(-⟨x,x⟩))
|
||||
@@ -170,6 +186,30 @@ mesh type.
|
||||
- CPEuclideanRotation: rotation-invariant CP functional variant
|
||||
Java references: unwrapper/circlepattern/CirclePattern{Layout,Utility}.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
|
||||
→ Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
|
||||
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):
|
||||
CanonicalBasisUtility.java 337 lines (homology basis)
|
||||
HomologyUtility.java 122 lines
|
||||
@@ -295,6 +341,17 @@ Phase 10 Global uniformization for genus g ≥ 2
|
||||
→ Ωᵢⱼ = ∫_{bⱼ} ωᵢ
|
||||
→ Reduction to Siegel fundamental domain via Sp(2g,ℤ).
|
||||
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).
|
||||
Requires: 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.
|
||||
Mathematical reference: Sechelmann 2016 §6 (discrete instance);
|
||||
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
|
||||
pieces but does not assemble them into
|
||||
a Fuchsian-group representation.
|
||||
@@ -327,6 +398,9 @@ Phase 10 Global uniformization for genus g ≥ 2
|
||||
10c' Optional Java-port additions (low priority)
|
||||
→ KoebePolyhedron.java (321 lines) — Koebe-Andreev-Thurston
|
||||
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
|
||||
distribution baseline.
|
||||
→ 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)
|
||||
* **Mathematical sources:**
|
||||
- **Poincaré, H.** (1882). *Théorie des groupes fuchsiens.*
|
||||
|
||||
Reference in New Issue
Block a user