Files
ConformalLabpp/code/include/hyper_ideal_utility.hpp
user2595 704f42bbfd
Some checks failed
C++ Tests / test-fast (push) Has started running
C++ Tests / test-cgal (push) Has been cancelled
API Docs / doc-build (push) Has been cancelled
Doxygen → Codeberg Pages / publish (push) Has been cancelled
Markdown link check / check (push) Has been cancelled
Mirror to Codeberg / mirror (push) Has been cancelled
Merge pull request 'ci+quality: structural gates (CI: 3 new; local: 7 new + .clang-tidy)' (#18) from ci/structural-tests into main
2026-05-26 09:14:45 +00:00

111 lines
3.7 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
// Copyright (c) 2024-2026 Tarik Moussa.
// SPDX-License-Identifier: MIT
// Hyperbolic tetrahedron volume formulas.
// Ported from de.varylab.discreteconformal.functional.HyperIdealUtility (Java).
#include "clausen.hpp"
#include "constants.hpp"
#include <Eigen/Dense>
#include <cmath>
#include <complex>
namespace conformallab {
/// Volume of a generalized hyperbolic tetrahedron with dihedral
/// angles `A,…,F` via the Meyerhoff / Ushijima 2006 formula.
/// Same as Java `HyperIdealUtility.calculateTetrahedronVolume()`.
inline double calculateTetrahedronVolume(double A, double B, double C,
double D, double E, double F) {
// PI from constants.hpp (conformallab::PI)
// Degenerate if any angle equals pi.
if (A == PI || B == PI || C == PI || D == PI || E == PI || F == PI)
return 0.0;
const double sA = std::sin(A), sB = std::sin(B), sC = std::sin(C);
const double sD = std::sin(D), sE = std::sin(E), sF = std::sin(F);
const double cA = std::cos(A), cB = std::cos(B), cC = std::cos(C);
const double cD = std::cos(D), cE = std::cos(E), cF = std::cos(F);
// Unit complex numbers e^(i*angle).
using Cx = std::complex<double>;
auto polar = [](double angle) { return std::polar(1.0, angle); };
Cx ad = polar(A + D), be = polar(B + E), cf = polar(C + F);
Cx abc = polar(A + B + C), abf = polar(A + B + F);
Cx ace = polar(A + C + E), aef = polar(A + E + F);
Cx bcd = polar(B + C + D), bdf = polar(B + D + F);
Cx def = polar(D + E + F), cde = polar(C + D + E);
Cx abde = ad * be, acdf = ad * cf, bcef = be * cf;
Cx abcdef = abc * def;
Cx z = ad + be + cf + abf + ace + bcd + def + abcdef;
// Gram matrix of the tetrahedron.
Eigen::Matrix4d G;
G << 1.0, -cA, -cB, -cF,
-cA, 1.0, -cC, -cE,
-cB, -cC, 1.0, -cD,
-cF, -cE, -cD, 1.0;
Cx sqrtG = std::sqrt(Cx(G.determinant(), 0.0));
Cx f = Cx(sA*sD + sB*sE + sC*sF, 0.0);
Cx f1 = f - sqrtG;
Cx f2 = f + sqrtG;
Cx z1 = -2.0 * f1 / z;
Cx z2 = -2.0 * f2 / z;
auto U = [&](Cx zi) {
return 0.5 * (
+ ImLi2(zi)
+ ImLi2(abde * zi)
+ ImLi2(acdf * zi)
+ ImLi2(bcef * zi)
- ImLi2(-abc * zi)
- ImLi2(-aef * zi)
- ImLi2(-bdf * zi)
- ImLi2(-cde * zi)
);
};
return (U(z1) - U(z2)) / 2.0;
}
/// Volume of a hyperideal tetrahedron with one ideal vertex at γ via
/// the Kolpakov-Mednykh formula (arxiv math/0603097). Same as Java
/// `HyperIdealUtility.calculateTetrahedronVolumeWithIdealVertexAtGamma()`.
inline double calculateTetrahedronVolumeWithIdealVertexAtGamma(
double gamma1, double gamma2, double gamma3,
double alpha23, double alpha31, double alpha12)
{
// PI from constants.hpp (conformallab::PI)
auto L = [](double x) { return Lobachevsky(x); };
double result = L(gamma1) + L(gamma2) + L(gamma3);
result += L((PI + alpha31 - alpha12 - gamma1) / 2.0);
result += L((PI + alpha12 - alpha23 - gamma2) / 2.0);
result += L((PI + alpha23 - alpha31 - gamma3) / 2.0);
result += L((PI - alpha31 + alpha12 - gamma1) / 2.0);
result += L((PI - alpha12 + alpha23 - gamma2) / 2.0);
result += L((PI - alpha23 + alpha31 - gamma3) / 2.0);
result += L((PI + alpha31 + alpha12 - gamma1) / 2.0);
result += L((PI + alpha12 + alpha23 - gamma2) / 2.0);
result += L((PI + alpha23 + alpha31 - gamma3) / 2.0);
result += L((PI - alpha31 - alpha12 - gamma1) / 2.0);
result += L((PI - alpha12 - alpha23 - gamma2) / 2.0);
result += L((PI - alpha23 - alpha31 - gamma3) / 2.0);
return result / 2.0;
}
} // namespace conformallab