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

@@ -39,18 +39,23 @@ namespace conformallab {
// ── Property-map type aliases ─────────────────────────────────────────────────
/// Property map vertex → `double` (HyperIdeal scalar-per-vertex data).
using VMapD = ConformalMesh::Property_map<Vertex_index, double>;
/// Property map vertex → `int` (HyperIdeal DOF indices).
using VMapI = ConformalMesh::Property_map<Vertex_index, int>;
/// Property map edge → `double` (HyperIdeal scalar-per-edge data).
using EMapD = ConformalMesh::Property_map<Edge_index, double>;
/// Property map edge → `int` (HyperIdeal DOF indices).
using EMapI = ConformalMesh::Property_map<Edge_index, int>;
// ── Persistent map bundle ─────────────────────────────────────────────────────
/// Bundle of the four property maps consumed by the HyperIdeal functional.
struct HyperIdealMaps {
VMapI v_idx; // DOF index per vertex (-1 = pinned / ideal point)
EMapI e_idx; // DOF index per edge (-1 = fixed)
VMapD theta_v; // target cone angle Θ_v (parameter, not variable)
EMapD theta_e; // target intersection angle θ_e
VMapI v_idx; ///< DOF index per vertex (1 = pinned / ideal point).
EMapI e_idx; ///< DOF index per edge (1 = fixed).
VMapD theta_v; ///< Target cone angle Θ (parameter, not variable).
EMapD theta_e; ///< Target intersection angle θₑ.
};
/// Attach the four HyperIdeal property maps to `mesh` and return their
@@ -105,20 +110,22 @@ inline int assign_all_dof_indices(ConformalMesh& mesh, HyperIdealMaps& m)
// ── Evaluation result ─────────────────────────────────────────────────────────
/// Output of `evaluate_hyper_ideal()` — the energy value and (optionally)
/// its gradient evaluated at the current DOF vector.
struct HyperIdealResult {
double energy = 0.0;
std::vector<double> gradient; // empty when gradient was not requested
double energy = 0.0; ///< Functional value at the input DOFs.
std::vector<double> gradient; ///< Gradient ∇E; empty when not requested.
};
// ── Internal helpers ──────────────────────────────────────────────────────────
// Get the DOF value from x, or 0.0 if pinned.
/// Read the DOF value from `x` for index `idx`; return 0 if pinned (idx < 0).
static inline double dof_val(int idx, const std::vector<double>& x)
{
return idx >= 0 ? x[static_cast<std::size_t>(idx)] : 0.0;
}
// Convert a CGAL halfedge index to a plain std::size_t (for vector indexing).
/// Convert a CGAL half-edge index to a plain `std::size_t` for vector indexing.
static inline std::size_t hidx(Halfedge_index h)
{
return static_cast<std::size_t>(static_cast<std::uint32_t>(h));
@@ -144,11 +151,21 @@ static inline std::size_t hidx(Halfedge_index h)
// HyperIdealFunctional.java's defensive behaviour (lines 122-127 of the
// Java original); this keeps the FD perturbation regime well-defined.
/// Six per-face angle outputs computed from local DOFs (see
/// `face_angles_from_local_dofs`). Used by the block-FD Hessian.
struct FaceAngleOutputs {
double beta1, beta2, beta3; ///< interior angles at v₁,v₂,v₃
double alpha12, alpha23, alpha31; ///< dihedral angles at e₁₂,e₂₃,e₃₁
double beta1; ///< Interior angle at v₁.
double beta2; ///< Interior angle at v₂.
double beta3; ///< Interior angle at v₃.
double alpha12; ///< Dihedral angle at edge e₁₂.
double alpha23; ///< Dihedral angle at edge e₂₃.
double alpha31; ///< Dihedral angle at edge e₃₁.
};
/// Pure-math 6→6 kernel: given the six local DOFs (b₁,b₂,b₃,a₁₂,a₂₃,a₃₁)
/// of one face plus the per-vertex variability flags, return the six
/// HyperIdeal angle outputs. No mesh, no property maps — used by the
/// per-face block-FD Hessian in `hyper_ideal_hessian.hpp`.
inline FaceAngleOutputs face_angles_from_local_dofs(
double b1, double b2, double b3,
double a12, double a23, double a31,
@@ -196,14 +213,29 @@ inline FaceAngleOutputs face_angles_from_local_dofs(
// ── Per-face angle kernel ─────────────────────────────────────────────────────
/// Per-face angle bundle returned by `compute_face_angles()`. Carries
/// the six output angles plus the six input DOFs (so the energy and
/// gradient kernels can reuse them without re-reading the mesh).
struct FaceAngles {
double alpha12, alpha23, alpha31; // dihedral angles at each edge
double beta1, beta2, beta3; // interior angles at each vertex
double a12, a23, a31; // edge DOF values (used in energy)
double b1, b2, b3; // vertex DOF values
bool v1b, v2b, v3b; // whether each vertex is variable
double alpha12; ///< Dihedral angle at edge e₁₂.
double alpha23; ///< Dihedral angle at edge e₂₃.
double alpha31; ///< Dihedral angle at edge e₃₁.
double beta1; ///< Interior angle at vertex v₁.
double beta2; ///< Interior angle at vertex v₂.
double beta3; ///< Interior angle at vertex v₃.
double a12; ///< Edge DOF value at e₁₂.
double a23; ///< Edge DOF value at e₂₃.
double a31; ///< Edge DOF value at e₃₁.
double b1; ///< Vertex DOF value at v₁.
double b2; ///< Vertex DOF value at v₂.
double b3; ///< Vertex DOF value at v₃.
bool v1b; ///< `true` iff vertex v₁ is variable (not pinned).
bool v2b; ///< `true` iff vertex v₂ is variable.
bool v3b; ///< `true` iff vertex v₃ is variable.
};
/// Compute the six per-face angles (+ remember the input DOFs) for face
/// `f` of `mesh`, given the current DOF vector `x` and DOF-index maps.
static FaceAngles compute_face_angles(
const ConformalMesh& mesh,
Face_index f,
@@ -281,7 +313,7 @@ static FaceAngles compute_face_angles(
return fa;
}
// Per-face energy contribution U(f) (before subtracting θ·a and Θ·b terms).
/// Per-face energy contribution U(f) before subtracting the θ·a and Θ·b terms.
static double face_energy(const FaceAngles& fa)
{
double aa = fa.a12*fa.alpha12 + fa.a23*fa.alpha23 + fa.a31*fa.alpha31;
@@ -310,6 +342,14 @@ static double face_energy(const FaceAngles& fa)
// ── Full evaluation ───────────────────────────────────────────────────────────
/// Evaluate the HyperIdeal functional at DOF vector `x`. Returns the
/// energy value and (optionally) the gradient in a `HyperIdealResult`.
///
/// \param mesh Triangle mesh carrying the DOF-index property maps.
/// \param x Current DOF vector (length = `hyper_ideal_dimension(...)`).
/// \param m Property-map bundle from `setup_hyper_ideal_maps(...)`.
/// \param need_energy If `true`, fill `result.energy` (default: `true`).
/// \param need_gradient If `true`, fill `result.gradient` (default: `true`).
inline HyperIdealResult evaluate_hyper_ideal(
ConformalMesh& mesh,
const std::vector<double>& x,
@@ -393,10 +433,10 @@ inline HyperIdealResult evaluate_hyper_ideal(
return res;
}
// ── Finite-difference gradient check ─────────────────────────────────────────
//
// Returns true if |G[i] fd[i]| / max(1, |G[i]|) < tol for all DOFs.
// eps = step size, tol = tolerance (same defaults as Java FunctionalTest).
/// Finite-difference gradient check (central differences).
///
/// Returns `true` iff `|G[i] fd[i]| / max(1, |G[i]|) < tol` for every
/// DOF. Defaults `eps = 1e-5`, `tol = 1e-4` match the Java `FunctionalTest`.
inline bool gradient_check(
ConformalMesh& mesh,
const std::vector<double>& x0,