Files
ConformalLabpp/code/include/spherical_geometry.hpp
Tarik Moussa a4c2a89e7e feat(phase3c): port SphericalFunctional onto ConformalMesh; update README
New headers:
- spherical_geometry.hpp: spherical arc length l(λ) and half-angle formula
  for interior angles of a spherical triangle (SphericalFaceAngles struct)
- spherical_functional.hpp: SphericalMaps bundle, setup/assign DOF helpers,
  compute_lambda0_from_mesh(), gradient (Θ_v − Σα_v; Schläfli edge formula),
  energy via 10-point Gauss-Legendre path integral, gradient_check_spherical()

Updated:
- mesh_builder.hpp: add make_spherical_tetrahedron() (vertices on unit sphere)
  and make_octahedron_face() (single right-angled spherical triangle)
- tests/cgal/CMakeLists.txt: enable test_spherical_functional.cpp
- README.md: rewrite for CGAL-package goal, two test targets, all headers,
  updated project tree, Phase progress table, key design decisions

Tests (cgal.SphericalFunctional.*): 8 active + 1 skip
- OctaFaceAnglesAreRightAngles, SpherTetAngleSumExceedsPi
- GradientCheck_{OctaFaceVertex, SpherTetVertex, SpherTetAllDofs,
  SpherFan4Vertex, MixedPinnedVertices}
- AnglesFiniteAtKnownPoint
All 30 cgal.* tests pass (2 @Ignore skips).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 00:01:24 +02:00

83 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
// spherical_geometry.hpp
//
// Pure-math building blocks for the spherical discrete conformal map.
// Ported from de.varylab.discreteconformal.functional.SphericalFunctional
// (the geometry helpers embedded there).
//
// Notation:
// u_i vertex conformal factor (DOF)
// λ°_e base log-length of edge e (fixed initial value)
// λ_ij effective log-length = λ°_ij + u_i + u_j
// l_ij spherical arc length = 2·asin(min(exp(λ_ij/2), 1))
// α_k interior angle of the spherical triangle at vertex k
#include <cmath>
#include <algorithm>
namespace conformallab {
constexpr double PI_SPHER = 3.14159265358979323846264338328;
// ── Effective spherical arc length ────────────────────────────────────────────
// l(λ) = 2·asin(min(exp(λ/2), 1)).
// Clamps exp(λ/2) to [0, 1] so the arcsin stays in domain.
inline double spherical_l(double lambda)
{
double half = std::exp(lambda * 0.5);
if (half >= 1.0) half = 1.0 - 1e-15;
if (half <= 0.0) return 0.0;
return 2.0 * std::asin(half);
}
// ── Interior angles of a spherical triangle ──────────────────────────────────
struct SphericalFaceAngles {
double alpha1, alpha2, alpha3; // corner angles at v1, v2, v3
bool valid; // false when the three lengths fail the
// spherical triangle inequality
};
// Compute corner angles from spherical arc lengths using the half-angle formula.
//
// Convention (matching the halfedge cycle h0→v1→v2, h1→v2→v3, h2→v3→v1):
// l12 arc length of edge opposite v3 (edge e12)
// l23 arc length of edge opposite v1 (edge e23)
// l31 arc length of edge opposite v2 (edge e31)
//
// Half-angle formula (spherical law of cosines):
// α_k = 2·atan2(sqrt(sin(s-a)·sin(s-b)), sqrt(sin(s)·sin(s-c)))
// where a,b are the two edges ADJACENT to vertex k, c is the opposite edge.
//
// Equivalently (in terms of s-deficiencies):
// α1 = 2·atan2( sqrt(sin(s12)·sin(s31)), sqrt(sin(s)·sin(s23)) )
// α2 = 2·atan2( sqrt(sin(s12)·sin(s23)), sqrt(sin(s)·sin(s31)) )
// α3 = 2·atan2( sqrt(sin(s23)·sin(s31)), sqrt(sin(s)·sin(s12)) )
//
// where s = (l12+l23+l31)/2 and s_ij = s - l_ij.
inline SphericalFaceAngles spherical_angles(double l12, double l23, double l31)
{
double s = (l12 + l23 + l31) * 0.5;
double s12 = s - l12;
double s23 = s - l23;
double s31 = s - l31;
// Spherical triangle inequalities: all s-deficiencies > 0 and s < π.
if (s12 <= 0.0 || s23 <= 0.0 || s31 <= 0.0 || s >= PI_SPHER)
return {0.0, 0.0, 0.0, false};
const double ss = std::sin(s);
const double ss12 = std::sin(s12);
const double ss23 = std::sin(s23);
const double ss31 = std::sin(s31);
double a1 = 2.0 * std::atan2(std::sqrt(ss12 * ss31), std::sqrt(ss * ss23));
double a2 = 2.0 * std::atan2(std::sqrt(ss12 * ss23), std::sqrt(ss * ss31));
double a3 = 2.0 * std::atan2(std::sqrt(ss23 * ss31), std::sqrt(ss * ss12));
return {a1, a2, a3, true};
}
} // namespace conformallab