docs(doxygen): 100% public-API coverage (228 → 0 undocumented)
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m40s
API Docs / doc-build (pull_request) Successful in 1m2s
C++ Tests / test-cgal (pull_request) Failing after 11m52s

Completes the work begun in the previous commit on this branch.  Every
public symbol under code/include/ now carries a brief Doxygen comment
(0 undocumented per scripts/doxygen-coverage.sh, with the `detail::`
implementation namespaces excluded as before).

Trajectory on this branch:
  start (after Doxyfile fix):  24.0 %  (165 / 437 in the no-detail set
                                       was 105 / 437 when detail counted)
  after PR #17 base commit  :  42.4 %  (165 / 396)
  this commit               : 100.0 %  (396 / 396)

Files touched (all .hpp / .h headers under code/include/):
  * cgal/Conformal_map_traits.h
  * clausen.hpp, conformal_mesh.hpp, constants.hpp (already docd)
  * cp_euclidean_functional.hpp, cut_graph.hpp, discrete_elliptic_utility.hpp
  * euclidean_functional.hpp, euclidean_geometry.hpp, euclidean_hessian.hpp
  * fundamental_domain.hpp, gauss_bonnet.hpp
  * hyper_ideal_{functional,geometry,hessian,utility,visualization_utility}.hpp
  * inversive_distance_functional.hpp, layout.hpp
  * matrix_utility.hpp, mesh_builder.hpp, mesh_io.hpp
  * newton_solver.hpp, p2_utility.hpp, period_matrix.hpp, projective_math.hpp
  * serialization.hpp, spherical_functional.hpp, spherical_geometry.hpp
  * spherical_hessian.hpp, viewer_utils.h

CI:
.gitea/workflows/doxygen-pages.yml now enforces
`scripts/doxygen-coverage.sh --threshold 100`, so any future regression
(a new public function landed without a `///` brief) fails the build
before the Doxygen HTML is published to Codeberg Pages.

Doxygen warnings remain at 0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-24 04:22:49 +02:00
parent f6722d7e84
commit 62b02f88b9
30 changed files with 427 additions and 355 deletions

View File

@@ -40,19 +40,24 @@ namespace conformallab {
// ── Property-map type aliases ─────────────────────────────────────────────────
/// Property map vertex → `double` for the Spherical functional.
using SpherVMapD = ConformalMesh::Property_map<Vertex_index, double>;
/// Property map vertex → `int` for the Spherical functional.
using SpherVMapI = ConformalMesh::Property_map<Vertex_index, int>;
/// Property map edge → `double` for the Spherical functional.
using SpherEMapD = ConformalMesh::Property_map<Edge_index, double>;
/// Property map edge → `int` for the Spherical functional.
using SpherEMapI = ConformalMesh::Property_map<Edge_index, int>;
// ── Persistent map bundle ─────────────────────────────────────────────────────
/// Bundle of the five property maps consumed by the Spherical functional.
struct SphericalMaps {
SpherVMapI v_idx; // DOF index per vertex (-1 = pinned / u_v = 0)
SpherEMapI e_idx; // DOF index per edge (-1 = no edge DOF)
SpherVMapD theta_v; // target cone angle Θ_v (default 2π)
SpherEMapD theta_e; // target edge angle θ_e (default π)
SpherEMapD lambda0; // base log-length λ°_e (default 0.0)
SpherVMapI v_idx; ///< DOF index per vertex (1 = pinned / u_v = 0).
SpherEMapI e_idx; ///< DOF index per edge (1 = no edge DOF).
SpherVMapD theta_v; ///< Target cone angle Θ (default 2π).
SpherEMapD theta_e; ///< Target edge angle θ (default π).
SpherEMapD lambda0; ///< Base log-length λ⁰ₑ (default 0).
};
// Defaults: theta_v = 2π, theta_e = π, lambda0 = 0.
@@ -133,18 +138,21 @@ inline void compute_lambda0_from_mesh(ConformalMesh& mesh, SphericalMaps& m)
// ── Evaluation result ─────────────────────────────────────────────────────────
/// Output of `evaluate_spherical()` — energy plus optional gradient.
struct SphericalResult {
double energy = 0.0;
std::vector<double> gradient;
double energy = 0.0; ///< Functional value at input DOFs.
std::vector<double> gradient; ///< Gradient ∇E (empty if not requested).
};
// ── Internal helpers ──────────────────────────────────────────────────────────
/// Read DOF value from `x` for index `idx`; return 0 if pinned (idx < 0).
static inline double spher_dof_val(int idx, const std::vector<double>& x)
{
return idx >= 0 ? x[static_cast<std::size_t>(idx)] : 0.0;
}
/// Convert a CGAL half-edge index to a plain `std::size_t` for vector indexing.
static inline std::size_t spher_hidx(Halfedge_index h)
{
return static_cast<std::size_t>(static_cast<std::uint32_t>(h));
@@ -152,14 +160,13 @@ static inline std::size_t spher_hidx(Halfedge_index h)
// ── Gradient only (no energy) ─────────────────────────────────────────────────
// Compute gradient G(x).
// G_v = Θ_v Σ_faces α_v(face)
// G_e = α_opp(face+) + α_opp(face) θ_e
//
// The corner angle α_v is stored on halfedges using the convention:
// h_alpha[h] = corner angle at source(prev(h)) = corner angle at the vertex
// ACROSS FROM the edge of halfedge h in its face.
// This convention makes both the vertex and edge gradient accumulators natural.
/// Compute the Spherical-functional gradient G(x):
/// * `G_v = Θ_v Σ_faces α_v(face)`
/// * `G_e = α_opp(face) + α_opp(face) θ_e`
///
/// The corner angle α_v is stored on half-edges via the convention
/// `h_alpha[h] = corner angle at the vertex ACROSS FROM the edge of h
/// in its face`, which makes both gradient accumulators natural.
inline std::vector<double> spherical_gradient(
ConformalMesh& mesh,
const std::vector<double>& x,
@@ -274,6 +281,9 @@ inline std::vector<double> spherical_gradient(
//
// 10-point GL nodes and weights on [0, 1] (transformed from [-1, 1]):
// t_k = (1 + s_k) / 2, w_k = w_GL_k / 2
/// Spherical energy `E(x) = ∫₀¹ ⟨G(t·x), x⟩ dt`, evaluated with
/// 10-point Gauss-Legendre quadrature. This is the correct potential
/// for any conservative `G = ∇E`; error ≈ O(h²⁰) for smooth G.
inline double spherical_energy(
ConformalMesh& mesh,
const std::vector<double>& x,
@@ -318,6 +328,8 @@ inline double spherical_energy(
// ── Full evaluation (energy + gradient) ──────────────────────────────────────
/// Evaluate the Spherical functional at DOFs `x`. Returns energy and
/// gradient (toggle via `need_energy` / `need_gradient`).
inline SphericalResult evaluate_spherical(
ConformalMesh& mesh,
const std::vector<double>& x,
@@ -333,10 +345,8 @@ inline SphericalResult evaluate_spherical(
return res;
}
// ── Finite-difference gradient check ─────────────────────────────────────────
//
// Tests |G[i] fd[i]| / max(1, |G[i]|) < tol for all DOFs.
// Same defaults as the hyper-ideal gradient check (Java FunctionalTest).
/// Finite-difference gradient check for the Spherical functional
/// (central differences). Same defaults as the Java `FunctionalTest`.
inline bool gradient_check_spherical(
ConformalMesh& mesh,
const std::vector<double>& x0,
@@ -390,6 +400,8 @@ inline bool gradient_check_spherical(
//
// Returns 0.0 if the zero cannot be bracketed (already at gauge maximum,
// or open surface — no shift needed).
/// Find the global-scale gauge shift `t*` for the closed-spherical case
/// (see comment block above for the maths). Apply via `apply_spherical_gauge`.
inline double spherical_gauge_shift(
ConformalMesh& mesh,
const std::vector<double>& x,
@@ -470,7 +482,8 @@ inline double spherical_gauge_shift(
return t;
}
// Apply the gauge shift in-place: x_v ← x_v + t* for all variable vertices.
/// Apply the spherical gauge shift in-place: `x_v ← x_v + t*` for every
/// variable vertex, where `t* = spherical_gauge_shift(mesh, x, m, ...)`.
inline void apply_spherical_gauge(
ConformalMesh& mesh,
std::vector<double>& x,