docs: restructure documentation into focused files
Some checks failed
C++ Tests / test-fast (push) Successful in 2m25s
C++ Tests / test-cgal (push) Failing after 1m58s

README.md: reduced from 703 to ~75 lines — what/why, status, quick
start, minimal usage example, navigation table to doc/ files.

doc/architecture/overall_pipeline.md: trimmed — roadmap, extension
points, declarative pipeline YAML, and references sections removed
(each now has its own dedicated file). Replaced with a link table.

New files:
  doc/getting-started.md       — build modes, single-test invocation, CLI
  doc/api/pipeline.md          — full pipeline API with code for all 3 geometries
  doc/api/extending.md         — new functionals, geometry modes, Java porting guide
  doc/api/contracts.md         — processing unit preconditions/provides table
  doc/api/cgal-package.md      — Phase 8 CGAL package design + YAML pipeline (TODO)
  doc/math/geometry-modes.md   — Euclidean/Spherical/HyperIdeal comparison
  doc/math/references.md       — all papers by module
  doc/roadmap/phases.md        — Phases 1–10 with porting/research boundary
  doc/roadmap/java-parity.md   — Java vs C++ feature parity table
  doc/contributing.md          — language policy, test standards, release flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-17 21:17:15 +02:00
parent 279f964b96
commit 14134b99ce
12 changed files with 1229 additions and 835 deletions

141
doc/api/extending.md Normal file
View File

@@ -0,0 +1,141 @@
# Extending conformallab++
## Adding a new functional
All three existing functionals (`euclidean_functional.hpp`, `spherical_functional.hpp`,
`hyper_ideal_functional.hpp`) follow the same pattern. Copy the structure of the
simplest one (`euclidean_functional.hpp`) as a template.
### Step 1 — Maps struct
```cpp
// my_functional.hpp
struct MyMaps {
ConformalMesh::Property_map<Vertex_index, double> lambda0; // initial log-lengths
ConformalMesh::Property_map<Vertex_index, double> theta_v; // target angles
ConformalMesh::Property_map<Vertex_index, int> v_idx; // DOF index, -1 = pinned
// add edge DOFs if needed:
ConformalMesh::Property_map<Edge_index, int> e_idx;
};
MyMaps setup_my_maps(ConformalMesh& mesh);
void compute_my_lambda0_from_mesh(ConformalMesh& mesh, MyMaps& maps);
```
### Step 2 — Gradient
The gradient must satisfy: `G_v = Σ(angle contributions at v) theta_v[v]`.
```cpp
std::vector<double> my_gradient(
const ConformalMesh& mesh,
const std::vector<double>& x,
const MyMaps& maps)
{
std::vector<double> G(n_dofs, 0.0);
for (auto f : mesh.faces()) {
// compute angles in face f given current x
// accumulate into G[maps.v_idx[v]] for each vertex v of f
}
// subtract target angles
for (auto v : mesh.vertices())
if (maps.v_idx[v] >= 0)
G[maps.v_idx[v]] -= maps.theta_v[v];
return G;
}
```
### Step 3 — Gradient check test
Before claiming correctness, verify with finite differences. Copy any `GradientCheck_*`
test suite from `tests/cgal/test_*_functional.cpp`:
```cpp
TEST(MyFunctional, GradientCheck_Triangle) {
ConformalMesh mesh = make_single_triangle();
MyMaps maps = setup_my_maps(mesh);
// ... assign DOFs, set natural theta ...
const double eps = 1e-5;
auto G = my_gradient(mesh, x0, maps);
for (int i = 0; i < n; ++i) {
std::vector<double> xp = x0, xm = x0;
xp[i] += eps; xm[i] -= eps;
double fd = (my_energy(mesh, xp, maps) - my_energy(mesh, xm, maps)) / (2*eps);
EXPECT_NEAR(G[i], fd, 1e-7) << "DOF " << i;
}
}
```
### Step 4 — Hessian and Newton wrapper
```cpp
// Reuse solve_linear_system from newton_solver.hpp
Eigen::SparseMatrix<double> H = my_hessian(mesh, x, maps);
bool used_fallback;
auto dx = conformallab::solve_linear_system(H, -G, &used_fallback);
```
Or write a thin `newton_my()` wrapper following the structure of `newton_euclidean()`.
---
## Adding a new geometry mode
To add a new space (e.g. de Sitter, flat 3-torus):
1. **Trilateration function** — implement `trilaterate_my(p1, p2, l12, l13, l23)` that
places a third point given two placed points and three edge lengths.
This is the only geometry-specific part of the layout.
2. **BFS structure** — reuse the priority-BFS loop from `euclidean_layout()` in `layout.hpp`.
The loop itself is geometry-agnostic; swap in your trilateration function.
3. **Holonomy** — if the space has a holonomy group, record the transition maps at seam edges
the same way `HolonomyData` does for translations (Euclidean) or Möbius maps (hyperbolic).
---
## Adding a new processing unit
1. Declare preconditions and outputs explicitly (see [contracts.md](contracts.md)).
2. Write a header-only implementation in `code/include/my_unit.hpp`.
3. Add tests in `code/tests/cgal/test_my_unit.cpp` and register in
`code/tests/cgal/CMakeLists.txt`.
4. Pipeline validation is currently manual (documented contracts). A compile-time or
runtime check via the declarative YAML pipeline (Phase 8e) is the planned upgrade —
see [cgal-package.md](cgal-package.md).
---
## Porting from Java
When porting a class from the Java library:
1. Locate the original at [github.com/varylab/conformallab](https://github.com/varylab/conformallab)
under `src/main/java/de/varylab/discreteconformal/`.
2. The Java library uses `CoHDS` (half-edge data structure) with intrusive vertex/edge data.
Map these to CGAL property maps:
```
Java: vertex.getLambda() → C++: maps.lambda0[v]
Java: edge.getAlpha() → C++: maps.e_alpha[e]
Java: vertex.getTheta() → C++: maps.theta_v[v]
Java: vertex.getSolverIndex() → C++: maps.v_idx[v]
```
3. Java uses `HalfedgeInterface` adapters with named accessors like `getOppositeVertex()`.
C++ equivalent:
```cpp
// Java: h.getOppositeVertex()
Vertex_index v_opp = mesh.target(mesh.next(h));
// Java: h.getNextHalfedge().getOppositeVertex()
Vertex_index v_opp2 = mesh.target(mesh.next(mesh.next(h)));
```
4. Port the test cases from the Java `@Test` methods. The "natural theta" trick
(`theta_v[v] = actual_angle_sum`) works the same way in both languages.