docs(doxygen): 100% public-API coverage (228 → 0 undocumented)
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:
@@ -75,28 +75,38 @@ namespace conformallab {
|
||||
// For hyperbolic holonomy the map is an orientation-preserving isometry of
|
||||
// the Poincaré disk (SU(1,1) element).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
/// Möbius transformation `T(z) = (a·z + b) / (c·z + d)` of the Riemann
|
||||
/// sphere; restricted to SU(1,1) for hyperbolic holonomy on the
|
||||
/// Poincaré disk.
|
||||
struct MobiusMap {
|
||||
/// Complex scalar used for all entries.
|
||||
using C = std::complex<double>;
|
||||
C a{1.0, 0.0};
|
||||
C b{0.0, 0.0};
|
||||
C c{0.0, 0.0};
|
||||
C d{1.0, 0.0};
|
||||
C a{1.0, 0.0}; ///< Top-left coefficient.
|
||||
C b{0.0, 0.0}; ///< Top-right coefficient.
|
||||
C c{0.0, 0.0}; ///< Bottom-left coefficient.
|
||||
C d{1.0, 0.0}; ///< Bottom-right coefficient.
|
||||
|
||||
/// Apply the transformation to a complex point.
|
||||
C apply(C z) const { return (a * z + b) / (c * z + d); }
|
||||
|
||||
/// Apply the transformation to a 2-D real point (interpreted as `x + iy`).
|
||||
Eigen::Vector2d apply(const Eigen::Vector2d& p) const {
|
||||
C w = apply(C(p.x(), p.y()));
|
||||
return Eigen::Vector2d(w.real(), w.imag());
|
||||
}
|
||||
|
||||
/// Identity map.
|
||||
static MobiusMap identity() { return {C(1), C(0), C(0), C(1)}; }
|
||||
|
||||
/// Inverse map.
|
||||
MobiusMap inverse() const { return {d, -b, -c, a}; }
|
||||
/// Composition `(*this) ∘ T`, i.e. apply `T` first then `*this`.
|
||||
MobiusMap compose(const MobiusMap& T) const {
|
||||
return { a*T.a + b*T.c, a*T.b + b*T.d,
|
||||
c*T.a + d*T.c, c*T.b + d*T.d };
|
||||
}
|
||||
|
||||
/// `true` iff the map is the identity up to tolerance `tol`.
|
||||
bool is_identity(double tol = 1e-9) const {
|
||||
if (std::abs(d) < 1e-14) return false;
|
||||
C a_ = a/d, b_ = b/d, c_ = c/d;
|
||||
@@ -121,6 +131,9 @@ struct MobiusMap {
|
||||
|
||||
// ── Result types ──────────────────────────────────────────────────────────────
|
||||
|
||||
/// Result of a 2-D layout (`euclidean_layout`, `hyper_ideal_layout`):
|
||||
/// per-vertex UV coordinates plus a per-half-edge UV atlas for seamed
|
||||
/// textures.
|
||||
struct Layout2D {
|
||||
/// uv[v.idx()] — primary 2-D position (first / shallowest-BFS-depth visit).
|
||||
std::vector<Eigen::Vector2d> uv;
|
||||
@@ -136,14 +149,15 @@ struct Layout2D {
|
||||
/// Size = mesh.number_of_halfedges(). Border halfedges = (0,0).
|
||||
std::vector<Eigen::Vector2d> halfedge_uv;
|
||||
|
||||
bool success = false;
|
||||
bool has_seam = false; ///< true when a vertex was reached via two paths
|
||||
bool success = false; ///< `true` iff the BFS placed every vertex.
|
||||
bool has_seam = false; ///< `true` when a vertex was reached via two paths.
|
||||
};
|
||||
|
||||
/// Result of a 3-D layout (`spherical_layout`): per-vertex positions on S².
|
||||
struct Layout3D {
|
||||
std::vector<Eigen::Vector3d> pos;
|
||||
bool success = false;
|
||||
bool has_seam = false;
|
||||
std::vector<Eigen::Vector3d> pos; ///< Per-vertex spherical positions.
|
||||
bool success = false; ///< `true` iff the BFS placed every vertex.
|
||||
bool has_seam = false; ///< `true` when a vertex was reached via two paths.
|
||||
};
|
||||
|
||||
/// Per-cut-edge holonomy.
|
||||
@@ -156,9 +170,9 @@ struct Layout3D {
|
||||
/// trilaterated virtual position obtained by continuing the unfolding across
|
||||
/// the cut.
|
||||
struct HolonomyData {
|
||||
std::vector<Eigen::Vector2d> translations; ///< Euclidean / spherical
|
||||
std::vector<MobiusMap> mobius_maps; ///< hyperbolic (Phase 7)
|
||||
std::vector<std::size_t> cut_edge_indices;
|
||||
std::vector<Eigen::Vector2d> translations; ///< Euclidean / spherical translation per cut edge.
|
||||
std::vector<MobiusMap> mobius_maps; ///< Hyperbolic Möbius isometry per cut edge (Phase 7).
|
||||
std::vector<std::size_t> cut_edge_indices; ///< Index (in the cut-graph edge list) of each holonomy entry.
|
||||
};
|
||||
|
||||
// ── Internal helpers ──────────────────────────────────────────────────────────
|
||||
@@ -343,7 +357,8 @@ inline void center_poincare_disk_weighted(
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ── Vertex Voronoi area weights ───────────────────────────────────────────────
|
||||
/// Compute per-vertex area weights (sum of 1/3 of each adjacent triangle area).
|
||||
/// Used by area-weighted layout normalisation routines.
|
||||
inline std::vector<double> compute_vertex_area_weights(const ConformalMesh& mesh)
|
||||
{
|
||||
std::vector<double> w(mesh.number_of_vertices(), 0.0);
|
||||
@@ -357,6 +372,8 @@ inline std::vector<double> compute_vertex_area_weights(const ConformalMesh& mesh
|
||||
|
||||
// ── Layout normalisation ──────────────────────────────────────────────────────
|
||||
|
||||
/// Euclidean canonical normalisation: translate centroid to the origin
|
||||
/// and rotate the principal axis of the UV cloud onto the x-axis.
|
||||
inline void normalise_euclidean(Layout2D& layout)
|
||||
{
|
||||
if (!layout.success || layout.uv.empty()) return;
|
||||
@@ -388,6 +405,8 @@ inline void normalise_hyperbolic(Layout2D& layout, const ConformalMesh& mesh)
|
||||
// halfedge_uv follows the same Möbius map
|
||||
detail::center_poincare_disk(layout.halfedge_uv);
|
||||
}
|
||||
/// Hyperbolic canonical normalisation, mesh-free fallback: uniform
|
||||
/// (unweighted) iterative Möbius centring of the Poincaré disk.
|
||||
inline void normalise_hyperbolic(Layout2D& layout) // fallback without mesh
|
||||
{
|
||||
if (!layout.success || layout.uv.empty()) return;
|
||||
@@ -395,6 +414,9 @@ inline void normalise_hyperbolic(Layout2D& layout) // fallback without mesh
|
||||
detail::center_poincare_disk(layout.halfedge_uv);
|
||||
}
|
||||
|
||||
/// Spherical canonical normalisation: rotate the layout so that the
|
||||
/// per-vertex centroid (projected back to S²) coincides with the north
|
||||
/// pole (Rodrigues rotation).
|
||||
inline void normalise_spherical(Layout3D& layout)
|
||||
{
|
||||
if (!layout.success || layout.pos.empty()) return;
|
||||
@@ -852,6 +874,8 @@ inline Layout2D hyper_ideal_layout(
|
||||
|
||||
// ── Convenience: save layout as OFF ──────────────────────────────────────────
|
||||
|
||||
/// Write a 2-D layout to disk in OFF format with z = 0. Convenience
|
||||
/// helper for quickly inspecting the UV result in any OFF viewer.
|
||||
inline void save_layout_off(
|
||||
const std::string& path, ConformalMesh& mesh, const Layout2D& layout)
|
||||
{
|
||||
@@ -865,6 +889,7 @@ inline void save_layout_off(
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a 3-D (spherical) layout to disk in OFF format.
|
||||
inline void save_layout_off(
|
||||
const std::string& path, ConformalMesh& mesh, const Layout3D& layout)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user