chore: translate all German text to English across code, docs, and CI
Unified the codebase language to English throughout. German text appeared in code comments, test file headers, CI step names, and several markdown documents. All natural-language text is now English; proper nouns (Institut für Mathematik, Technische Universität Berlin) are unchanged. Files changed: - .gitea/workflows/cpp-tests.yml — CI step names and job comments - code/include/mesh_utils.hpp — inline comment - code/tests/cgal/CMakeLists.txt — section comment block - code/tests/cgal/test_geometry_utils.cpp — full file header + all test comments - doc/math/references.md — geometry-central section - doc/math/validation.md — Section 9 (geometry-central cross-validation) - doc/roadmap/phases.md — Optional geometry-central track (GC-1/2/3) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,8 @@ on:
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Job 1 — test-fast
|
||||
# Pure-math tests (Clausen, ImLi₂, Hyper-ideal Geometrie).
|
||||
# Kein CGAL, kein Boost. Nur Eigen + GTest. Läuft auf ALLEN Branches.
|
||||
# Pure-math tests (Clausen, ImLi₂, Hyper-ideal geometry).
|
||||
# No CGAL, no Boost. Eigen + GTest only. Runs on ALL branches.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
jobs:
|
||||
test-fast:
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
--output-on-failure
|
||||
--output-junit test-results.xml
|
||||
|
||||
- name: Zusammenfassung
|
||||
- name: Summary
|
||||
if: always()
|
||||
run: |
|
||||
if [ -f test-results.xml ]; then
|
||||
@@ -48,14 +48,14 @@ jobs:
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Job 2 — test-cgal
|
||||
# Vollständige CGAL-Test-Suite (Phase 3–7, 158 Tests).
|
||||
# Läuft NUR bei Pull Requests (nicht bei direkten Pushes auf dev/main).
|
||||
# Startet erst nach erfolgreichem test-fast.
|
||||
# Full CGAL test suite (Phase 3–7, 158 tests).
|
||||
# Runs ONLY on pull requests (not on direct pushes to dev/main).
|
||||
# Starts only after test-fast succeeds.
|
||||
#
|
||||
# Verwendet -DWITH_CGAL_TESTS=ON (nicht -DWITH_CGAL=ON), damit kein
|
||||
# Viewer/GLFW gebaut wird — der CI-Container hat kein wayland-scanner.
|
||||
# Uses -DWITH_CGAL_TESTS=ON (not -DWITH_CGAL=ON) to avoid building
|
||||
# Viewer/GLFW — the CI container has no wayland-scanner.
|
||||
#
|
||||
# Boost (libboost-dev) ist seit Image-Rebuild bereits im Container.
|
||||
# Boost (libboost-dev) is already present in the container since the image rebuild.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
test-cgal:
|
||||
needs: test-fast
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure (WITH_CGAL_TESTS — kein Viewer, kein wayland-scanner)
|
||||
- name: Configure (WITH_CGAL_TESTS — no viewer, no wayland-scanner)
|
||||
run: cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build CGAL-Tests
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
--output-on-failure
|
||||
--output-junit cgal-results.xml
|
||||
|
||||
- name: Zusammenfassung
|
||||
- name: Summary
|
||||
if: always()
|
||||
run: |
|
||||
if [ -f cgal-results.xml ]; then
|
||||
|
||||
@@ -36,7 +36,7 @@ void simple_visualize_mesh(Eigen::MatrixXd& V, Eigen::MatrixXi& F) {
|
||||
viewer.data().set_mesh(V, F);
|
||||
viewer.launch();
|
||||
}
|
||||
// Zero-Copy Map für V (optional)
|
||||
// Zero-copy map for V (optional)
|
||||
template <typename Kernel>
|
||||
Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, 3, Eigen::RowMajor>>
|
||||
get_vertex_map(CGAL::Surface_mesh<typename Kernel::Point_3>& mesh) {
|
||||
|
||||
@@ -44,10 +44,10 @@ add_executable(conformallab_cgal_tests
|
||||
# period matrix, fundamental domain, tiling
|
||||
test_phase7.cpp
|
||||
|
||||
# ── Java-Parität: Geometrie-Utility-Tests ─────────────────────────────────
|
||||
# Portiert aus CuttinUtilityTest, UnwrapUtilityTest,
|
||||
# ConvergenceUtilityTests, HomologyTest (Tests 1–6).
|
||||
# Test 7 (Genus-2-Homologie) als GTEST_SKIP-Stub bis Phase 8.
|
||||
# ── Java parity: geometry utility tests ──────────────────────────────────
|
||||
# Ported from CuttinUtilityTest, UnwrapUtilityTest,
|
||||
# ConvergenceUtilityTests, HomologyTest (tests 1–6).
|
||||
# Test 7 (genus-2 homology) as GTEST_SKIP stub until Phase 8.
|
||||
test_geometry_utils.cpp
|
||||
|
||||
# ── Scalability smoke tests ────────────────────────────────────────────────
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
// test_geometry_utils.cpp
|
||||
//
|
||||
// Portierung der Java ConformalLab Geometrie-Utility-Tests.
|
||||
// Port of the Java ConformalLab geometry utility tests.
|
||||
//
|
||||
// Java-Quelle Java-Testmethode Status
|
||||
// Java source Java test method Status
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────
|
||||
// CuttinUtilityTest.java testIsInConvexTextureFace_False PORTIERT
|
||||
// CuttinUtilityTest.java testIsInConvexTextureFace_True PORTIERT
|
||||
// UnwrapUtilityTest.java testGetAngleReturnsPI PORTIERT
|
||||
// ConvergenceUtilityTests.java testGetTextureCircumRadius PORTIERT
|
||||
// ConvergenceUtilityTests.java testGetTextureTriangleArea PORTIERT
|
||||
// ConvergenceUtilityTests.java testScaleInvariantCircumCircleRadius PORTIERT
|
||||
// HomologyTest.java testHomology PORTIERT
|
||||
// EuclideanLayoutTest.java testDoLayout PORTIERT
|
||||
// EuclideanCyclicConvergenceTest.java testEuclideanConvergence PORTIERT
|
||||
// SphericalConvergenceTest.java testSphericalConvergence PORTIERT
|
||||
// CuttinUtilityTest.java testIsInConvexTextureFace_False PORTED
|
||||
// CuttinUtilityTest.java testIsInConvexTextureFace_True PORTED
|
||||
// UnwrapUtilityTest.java testGetAngleReturnsPI PORTED
|
||||
// ConvergenceUtilityTests.java testGetTextureCircumRadius PORTED
|
||||
// ConvergenceUtilityTests.java testGetTextureTriangleArea PORTED
|
||||
// ConvergenceUtilityTests.java testScaleInvariantCircumCircleRadius PORTED
|
||||
// HomologyTest.java testHomology PORTED
|
||||
// EuclideanLayoutTest.java testDoLayout PORTED
|
||||
// EuclideanCyclicConvergenceTest.java testEuclideanConvergence PORTED
|
||||
// SphericalConvergenceTest.java testSphericalConvergence PORTED
|
||||
//
|
||||
// ─── Geometrische Grundlage ──────────────────────────────────────────────────────────
|
||||
// ─── Geometric background ────────────────────────────────────────────────────────────
|
||||
//
|
||||
// Tests 1–2 Punkt-in-konvexem-Dreieck (2D UV-Raum, baryzentrische Vorzeichen-Methode)
|
||||
// Tests 1–2 Point-in-convex-triangle (2D UV space, barycentric sign method)
|
||||
// Java: CuttingUtility.isInConvexTextureFace(pp, face, adapters)
|
||||
// Hinweis: Java-Test 2 hat ein 5-elementiges T-Array mit w=0 (Punkt im
|
||||
// Unendlichen), was ein Tippfehler im Original ist. Hier werden
|
||||
// äquivalente, wohlgeformte Koordinaten verwendet.
|
||||
// Note: Java test 2 has a 5-element T-array with w=0 (point at
|
||||
// infinity), which is a typo in the original. Equivalent, well-formed
|
||||
// coordinates are used here instead.
|
||||
//
|
||||
// Test 3 Eckenwinkel für kollineare Vertices über den Kosinussatz.
|
||||
// Java: UnwrapUtility.getAngle(edge, adapters) — gibt den Winkel am
|
||||
// Zielknoten zurück. Für v0=(-1,0,0), v1=(0,0,0), v2=(1,0,0) ist
|
||||
// der Winkel bei v1 genau π (Dreiecksungleichung entartet).
|
||||
// Test 3 Corner angle for collinear vertices via the law of cosines.
|
||||
// Java: UnwrapUtility.getAngle(edge, adapters) — returns the angle at
|
||||
// the target vertex. For v0=(-1,0,0), v1=(0,0,0), v2=(1,0,0) the
|
||||
// angle at v1 is exactly π (degenerate triangle inequality).
|
||||
//
|
||||
// Tests 4–5 2D Umkreisradius und Dreiecksfläche.
|
||||
// Tests 4–5 2D circumradius and triangle area.
|
||||
// Java: ConvergenceUtility.getTextureCircumCircleRadius(face)
|
||||
// ConvergenceUtility.getTextureTriangleArea(face)
|
||||
// Formeln: Area = |det([B-A, C-A])| / 2
|
||||
// R = (a·b·c) / (4·Area)
|
||||
// Formulas: Area = |det([B-A, C-A])| / 2
|
||||
// R = (a·b·c) / (4·Area)
|
||||
//
|
||||
// Test 6 Skaleninvarianter Umkreisradius über ein Mesh.
|
||||
// Test 6 Scale-invariant circumradius over a mesh.
|
||||
// Java: ConvergenceUtility.getMaxMeanSumScaleInvariantCircumRadius(hds)
|
||||
// Gibt [max, mean, sum] von R_f / sqrt(total_texture_area) zurück.
|
||||
// Invariant unter uniformer Skalierung der Texturkoordinaten (Test mit
|
||||
// homogenem Gewicht w: Position = (T[0]/w, T[1]/w)).
|
||||
// Returns [max, mean, sum] of R_f / sqrt(total_texture_area).
|
||||
// Invariant under uniform scaling of texture coordinates (tested with
|
||||
// homogeneous weight w: position = (T[0]/w, T[1]/w)).
|
||||
//
|
||||
// Test 7 Genus-2 Homologie-Generatoren.
|
||||
// Test 7 Genus-2 homology generators.
|
||||
// Java: HomologyTest.testHomology (brezel2.obj)
|
||||
// Erwartet: getGeneratorPaths(root).size() == 4 (2g = 4 für g = 2)
|
||||
// Expected: getGeneratorPaths(root).size() == 4 (2g = 4 for g = 2)
|
||||
// C++: compute_cut_graph(mesh).cut_edge_indices.size() == 4
|
||||
// Mesh: code/data/obj/brezel2.obj (V=2622, F=5248, χ=−2, g=2)
|
||||
// Pfad zur Compile-Zeit via CONFORMALLAB_DATA_DIR (CMakeLists.txt).
|
||||
// Path set at compile time via CONFORMALLAB_DATA_DIR (CMakeLists.txt).
|
||||
//
|
||||
// Tests 8–9 Layout-Kanten-Längenerhalt (tetraflat.obj).
|
||||
// Tests 8–9 Layout edge-length preservation (tetraflat.obj).
|
||||
// Java: EuclideanLayoutTest.testDoLayout
|
||||
// Nach Layout mit u=0 müssen UV-Kantenlängen == 3D-Kantenlängen (±1e-10).
|
||||
// After layout with u=0, UV edge lengths must equal 3D edge lengths (±1e-10).
|
||||
//
|
||||
// Test 10 Euklidischer Newton auf cathead.obj — Konvergenz + Winkeldefekt.
|
||||
// Java: EuclideanLayoutTest.testLayout02 (130-Werte-Array für cathead.heml)
|
||||
// C++: Newton ab u=0, prüft Konvergenz + Σα_v ≈ 2π für alle inneren Knoten.
|
||||
// Test 10 Euclidean Newton on cathead.obj — convergence + angle deficit.
|
||||
// Java: EuclideanLayoutTest.testLayout02 (130-value array for cathead.heml)
|
||||
// C++: Newton from u=0, checks convergence + Σα_v ≈ 2π for all interior nodes.
|
||||
//
|
||||
// Test 11 Sphärischer Newton auf Oktaeder — Konvergenz + Winkeldefekt.
|
||||
// Java: SphericalConvergenceTest.testSphericalConvergence (Oktaeder, zufällig
|
||||
// störe Radien, seed=1). C++: konstruierter regulärer Oktaeder, prüft
|
||||
// Konvergenz und dass Σα_v ≈ 2π (Target für Sphäre nach prepareInvariantData).
|
||||
// Test 11 Spherical Newton on octahedron — convergence + angle deficit.
|
||||
// Java: SphericalConvergenceTest.testSphericalConvergence (octahedron, randomly
|
||||
// perturbed radii, seed=1). C++: constructed regular octahedron, checks
|
||||
// convergence and that Σα_v ≈ 2π (target for sphere after prepareInvariantData).
|
||||
//
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -81,12 +81,12 @@
|
||||
using namespace conformallab;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Lokale Geometrie-Hilfsfunktionen
|
||||
// (portiert aus Java CuttingUtility / ConvergenceUtility)
|
||||
// Local geometry helper functions
|
||||
// (ported from Java CuttingUtility / ConvergenceUtility)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Punkt-in-Dreieck Test (2D, baryzentrische Vorzeichenmethode).
|
||||
/// Gibt true zurück wenn p strikt innerhalb oder auf dem Rand von v0-v1-v2 liegt.
|
||||
/// Point-in-triangle test (2D, barycentric sign method).
|
||||
/// Returns true if p lies strictly inside or on the boundary of v0-v1-v2.
|
||||
/// Java: CuttingUtility.isInConvexTextureFace
|
||||
static bool point_in_triangle_2d(
|
||||
Eigen::Vector2d p,
|
||||
@@ -103,7 +103,7 @@ static bool point_in_triangle_2d(
|
||||
return !(has_neg && has_pos);
|
||||
}
|
||||
|
||||
/// 2D Dreiecksfläche (halbes Kreuzprodukt).
|
||||
/// 2D triangle area (half cross product).
|
||||
/// Java: ConvergenceUtility.getTextureTriangleArea
|
||||
static double triangle_area_2d(
|
||||
Eigen::Vector2d A, Eigen::Vector2d B, Eigen::Vector2d C)
|
||||
@@ -112,7 +112,7 @@ static double triangle_area_2d(
|
||||
- (B - A).y() * (C - A).x()) * 0.5;
|
||||
}
|
||||
|
||||
/// 2D Umkreisradius: R = (a·b·c) / (4·Area).
|
||||
/// 2D circumradius: R = (a·b·c) / (4·Area).
|
||||
/// Java: ConvergenceUtility.getTextureCircumCircleRadius
|
||||
static double circumradius_2d(
|
||||
Eigen::Vector2d A, Eigen::Vector2d B, Eigen::Vector2d C)
|
||||
@@ -125,17 +125,17 @@ static double circumradius_2d(
|
||||
return (a * b * c) / (4.0 * area);
|
||||
}
|
||||
|
||||
/// Skaleninvarianter Umkreisradius für ein Mesh:
|
||||
/// Scale-invariant circumradius for a mesh:
|
||||
/// scale_R_f = R_f / sqrt(total_area)
|
||||
/// Gibt {max, mean, sum} über alle Flächen zurück.
|
||||
/// Returns {max, mean, sum} over all faces.
|
||||
/// Java: ConvergenceUtility.getMaxMeanSumScaleInvariantCircumRadius
|
||||
///
|
||||
/// Homogene Koordinaten: Position = (x/w, y/w).
|
||||
/// Homogeneous coordinates: position = (x/w, y/w).
|
||||
static std::array<double, 3> scale_invariant_circumradius_stats(
|
||||
const std::vector<Eigen::Vector2d>& verts,
|
||||
const std::vector<std::array<int, 3>>& faces)
|
||||
{
|
||||
// Gesamtfläche
|
||||
// Total area
|
||||
double total_area = 0.0;
|
||||
for (auto& f : faces)
|
||||
total_area += triangle_area_2d(verts[f[0]], verts[f[1]], verts[f[2]]);
|
||||
@@ -154,70 +154,70 @@ static std::array<double, 3> scale_invariant_circumradius_stats(
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Tests 1–2 — CuttingUtility: Punkt-in-konvexem-Dreieck (2D UV-Raum)
|
||||
// Tests 1–2 — CuttingUtility: point-in-convex-triangle (2D UV space)
|
||||
// Java: CuttinUtilityTest.testIsInConvexTextureFace_False / _True
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// Test 1: Punkt liegt weit außerhalb — exakte Java-Koordinaten
|
||||
// Test 1: point lies far outside — exact Java coordinates
|
||||
TEST(CuttingUtility, IsInConvexTextureFace_False)
|
||||
{
|
||||
// Winziges Dreieck um (0.7488, 0.0629) — Java-Testkoordinaten (T[3]=1, w=1)
|
||||
// Tiny triangle around (0.7488, 0.0629) — Java test coordinates (T[3]=1, w=1)
|
||||
Eigen::Vector2d v0(0.7488102998904661, 0.06293998610761144);
|
||||
Eigen::Vector2d v1(0.7487811940754379, 0.06289451051246124);
|
||||
Eigen::Vector2d v2(0.7487254625255592, 0.06291429499873116);
|
||||
// Testpunkt weit entfernt bei (0.447, 0.000228)
|
||||
// Test point far away at (0.447, 0.000228)
|
||||
Eigen::Vector2d pp(0.44661534423161037, 2.2808373704822393e-4);
|
||||
|
||||
EXPECT_FALSE(point_in_triangle_2d(pp, v0, v1, v2));
|
||||
}
|
||||
|
||||
// Test 2: Punkt liegt innerhalb
|
||||
// Hinweis: Das originale Java-Array p2 hat 5 Elemente mit w=0 (Tippfehler im
|
||||
// Java-Original). Hier werden äquivalente, wohlgeformte Koordinaten verwendet,
|
||||
// die dasselbe geometrische Szenario abbilden.
|
||||
// Test 2: point lies inside
|
||||
// Note: the original Java array p2 has 5 elements with w=0 (typo in the
|
||||
// Java original). Equivalent, well-formed coordinates are used here
|
||||
// that represent the same geometric scenario.
|
||||
TEST(CuttingUtility, IsInConvexTextureFace_True)
|
||||
{
|
||||
// Dreieck: (0,0) — (1e-8, 0) — (0, 1e-8)
|
||||
// Triangle: (0,0) — (1e-8, 0) — (0, 1e-8)
|
||||
Eigen::Vector2d v0(0.0, 0.0);
|
||||
Eigen::Vector2d v1(1e-8, 0.0);
|
||||
Eigen::Vector2d v2(0.0, 1e-8);
|
||||
// Schwerpunkt des Dreiecks — liegt immer innen
|
||||
// Centroid of the triangle — always lies inside
|
||||
Eigen::Vector2d pp(1e-8 / 3.0, 1e-8 / 3.0);
|
||||
|
||||
EXPECT_TRUE(point_in_triangle_2d(pp, v0, v1, v2));
|
||||
}
|
||||
|
||||
// Zusätzlich: einfaches Einheitsdreieck für Klarheit
|
||||
// Additional: simple unit triangle for clarity
|
||||
TEST(CuttingUtility, IsInConvexTextureFace_UnitTriangle_InAndOut)
|
||||
{
|
||||
Eigen::Vector2d v0(0.0, 0.0), v1(1.0, 0.0), v2(0.0, 1.0);
|
||||
EXPECT_TRUE( point_in_triangle_2d(Eigen::Vector2d(0.25, 0.25), v0, v1, v2));
|
||||
EXPECT_FALSE(point_in_triangle_2d(Eigen::Vector2d(2.0, 2.0), v0, v1, v2));
|
||||
EXPECT_FALSE(point_in_triangle_2d(Eigen::Vector2d(0.6, 0.6), v0, v1, v2)); // jenseits Hypotenuse
|
||||
EXPECT_FALSE(point_in_triangle_2d(Eigen::Vector2d(0.6, 0.6), v0, v1, v2)); // beyond hypotenuse
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 3 — UnwrapUtility: Eckenwinkel = π für kollineare Vertices
|
||||
// Test 3 — UnwrapUtility: corner angle = π for collinear vertices
|
||||
// Java: UnwrapUtilityTest.testGetAngleReturnsPI
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// Java: v0=(-1,0,0), v1=(0,0,0), v2=(1,0,0) kollinear.
|
||||
// Kante e von v2 nach v1. getAngle(e) = Winkel bei v1 = π.
|
||||
// Java: v0=(-1,0,0), v1=(0,0,0), v2=(1,0,0) collinear.
|
||||
// Edge e from v2 to v1. getAngle(e) = angle at v1 = π.
|
||||
//
|
||||
// C++: Kosinussatz mit Kantenlängen a=|v0-v1|=1, b=|v1-v2|=1, c=|v0-v2|=2.
|
||||
// C++: law of cosines with edge lengths a=|v0-v1|=1, b=|v1-v2|=1, c=|v0-v2|=2.
|
||||
// cos(γ_v1) = (a² + b² − c²) / (2ab) = (1 + 1 − 4) / 2 = −1 → γ = π
|
||||
TEST(UnwrapUtility, GetAngle_CollinearVertices_ReturnsPI)
|
||||
{
|
||||
const double a = 1.0; // |v0 − v1|
|
||||
const double b = 1.0; // |v1 − v2|
|
||||
const double c = 2.0; // |v0 − v2| (= a + b, entartet)
|
||||
const double c = 2.0; // |v0 − v2| (= a + b, degenerate)
|
||||
double cos_angle = (a*a + b*b - c*c) / (2.0 * a * b);
|
||||
cos_angle = std::max(-1.0, std::min(1.0, cos_angle)); // numerisches Clamp
|
||||
cos_angle = std::max(-1.0, std::min(1.0, cos_angle)); // numeric clamp
|
||||
double angle = std::acos(cos_angle);
|
||||
EXPECT_NEAR(M_PI, angle, 1e-15);
|
||||
}
|
||||
|
||||
// Gegenkontrolle: gleichseitiges Dreieck → Winkel = π/3
|
||||
// Counter-check: equilateral triangle → angle = π/3
|
||||
TEST(UnwrapUtility, GetAngle_EquilateralTriangle_ReturnsPiOver3)
|
||||
{
|
||||
const double s = 1.0;
|
||||
@@ -227,57 +227,57 @@ TEST(UnwrapUtility, GetAngle_EquilateralTriangle_ReturnsPiOver3)
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 4 — ConvergenceUtility: 2D Umkreisradius
|
||||
// Test 4 — ConvergenceUtility: 2D circumradius
|
||||
// Java: ConvergenceUtilityTests.testGetTextureCircumRadius
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(ConvergenceUtility, TextureCircumRadius_RightTriangle)
|
||||
{
|
||||
// A=(0,0), B=(1,0), C=(0,1): rechtwinkliges gleichschenkliges Dreieck
|
||||
// Seiten: 1, 1, √2. R = √2 / (4 · 0.5) = √2/2
|
||||
// A=(0,0), B=(1,0), C=(0,1): right isosceles triangle
|
||||
// Sides: 1, 1, √2. R = √2 / (4 · 0.5) = √2/2
|
||||
Eigen::Vector2d A(0.0, 0.0), B(1.0, 0.0), C(0.0, 1.0);
|
||||
EXPECT_NEAR(std::sqrt(2.0) / 2.0, circumradius_2d(A, B, C), 1e-10);
|
||||
}
|
||||
|
||||
TEST(ConvergenceUtility, TextureCircumRadius_SmallerTriangle)
|
||||
{
|
||||
// A=(0,0), B=(0.5,0.5), C=(0,1): Java-Variante mit B.T={0.5,0.5,0,1}
|
||||
// Seiten: √0.5, √0.5, 1. Area = 0.25. R = (√0.5·√0.5·1)/(4·0.25) = 0.5
|
||||
// A=(0,0), B=(0.5,0.5), C=(0,1): Java variant with B.T={0.5,0.5,0,1}
|
||||
// Sides: √0.5, √0.5, 1. Area = 0.25. R = (√0.5·√0.5·1)/(4·0.25) = 0.5
|
||||
Eigen::Vector2d A(0.0, 0.0), B(0.5, 0.5), C(0.0, 1.0);
|
||||
EXPECT_NEAR(0.5, circumradius_2d(A, B, C), 1e-10);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 5 — ConvergenceUtility: 2D Dreiecksfläche
|
||||
// Test 5 — ConvergenceUtility: 2D triangle area
|
||||
// Java: ConvergenceUtilityTests.testGetTextureTriangleArea
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(ConvergenceUtility, TextureTriangleArea_RightTriangle)
|
||||
{
|
||||
// A=(0,0), B=(1,0), C=(0,1) → Fläche = 0.5
|
||||
// A=(0,0), B=(1,0), C=(0,1) → area = 0.5
|
||||
Eigen::Vector2d A(0.0, 0.0), B(1.0, 0.0), C(0.0, 1.0);
|
||||
EXPECT_NEAR(0.5, triangle_area_2d(A, B, C), 1e-10);
|
||||
}
|
||||
|
||||
TEST(ConvergenceUtility, TextureTriangleArea_SmallerTriangle)
|
||||
{
|
||||
// A=(0,0), B=(0.5,0.5), C=(0,1) → Fläche = 0.25
|
||||
// A=(0,0), B=(0.5,0.5), C=(0,1) → area = 0.25
|
||||
Eigen::Vector2d A(0.0, 0.0), B(0.5, 0.5), C(0.0, 1.0);
|
||||
EXPECT_NEAR(0.25, triangle_area_2d(A, B, C), 1e-10);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 6 — ConvergenceUtility: Skaleninvarianter Umkreisradius
|
||||
// Test 6 — ConvergenceUtility: scale-invariant circumradius
|
||||
// Java: ConvergenceUtilityTests.testScaleInvariantCircumCircleRadius
|
||||
//
|
||||
// Mesh: 4 Vertices (v1..v4), 2 Flächen (f1: v1-v2-v3, f2: v1-v3-v4).
|
||||
// Skaleninvariante Größe: R_f / sqrt(total_area) — invariant unter
|
||||
// uniformer Skalierung (homogeneous weight w: pos = (x/w, y/w)).
|
||||
// Mesh: 4 vertices (v1..v4), 2 faces (f1: v1-v2-v3, f2: v1-v3-v4).
|
||||
// Scale-invariant quantity: R_f / sqrt(total_area) — invariant under
|
||||
// uniform scaling (homogeneous weight w: pos = (x/w, y/w)).
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(ConvergenceUtility, ScaleInvariantCircumRadius_BaseScale)
|
||||
{
|
||||
// Positionen bei w=1 (T[3]=1): v1=(0,0), v2=(1,0), v3=(0,1), v4=(-1,0)
|
||||
// Positions at w=1 (T[3]=1): v1=(0,0), v2=(1,0), v3=(0,1), v4=(-1,0)
|
||||
std::vector<Eigen::Vector2d> verts = {
|
||||
{0.0, 0.0}, // v1
|
||||
{1.0, 0.0}, // v2
|
||||
@@ -287,13 +287,13 @@ TEST(ConvergenceUtility, ScaleInvariantCircumRadius_BaseScale)
|
||||
// f1: v1-v2-v3, f2: v1-v3-v4
|
||||
std::vector<std::array<int, 3>> faces = { {0, 1, 2}, {0, 2, 3} };
|
||||
|
||||
// Einzelflächen-Prüfung (Java testGetTextureTriangleArea-Anforderung)
|
||||
// Per-face check (Java testGetTextureTriangleArea requirement)
|
||||
EXPECT_NEAR(0.5, triangle_area_2d(verts[0], verts[1], verts[2]), 1e-10);
|
||||
EXPECT_NEAR(0.5, triangle_area_2d(verts[0], verts[2], verts[3]), 1e-10);
|
||||
|
||||
auto [max_r, mean_r, sum_r] = scale_invariant_circumradius_stats(verts, faces);
|
||||
|
||||
// Erwartet: sin(π/4) = √2/2 für max und mean (beide Dreiecke identisch)
|
||||
// Expected: sin(π/4) = √2/2 for max and mean (both triangles identical)
|
||||
EXPECT_NEAR(std::sin(M_PI / 4.0), max_r, 1e-10);
|
||||
EXPECT_NEAR(std::sin(M_PI / 4.0), mean_r, 1e-10);
|
||||
EXPECT_NEAR(2.0 * std::sin(M_PI / 4.0), sum_r, 1e-10);
|
||||
@@ -301,7 +301,7 @@ TEST(ConvergenceUtility, ScaleInvariantCircumRadius_BaseScale)
|
||||
|
||||
TEST(ConvergenceUtility, ScaleInvariantCircumRadius_HalvedByW2_SameResult)
|
||||
{
|
||||
// Skalierung durch w=2: alle Positionen halbiert (homogene Koordinaten)
|
||||
// Scaling by w=2: all positions halved (homogeneous coordinates)
|
||||
// pos_scaled = (T[0]/2, T[1]/2)
|
||||
std::vector<Eigen::Vector2d> verts = {
|
||||
{0.0, 0.0}, // v1/2
|
||||
@@ -311,35 +311,35 @@ TEST(ConvergenceUtility, ScaleInvariantCircumRadius_HalvedByW2_SameResult)
|
||||
};
|
||||
std::vector<std::array<int, 3>> faces = { {0, 1, 2}, {0, 2, 3} };
|
||||
|
||||
// Flächen sind ein Viertel der ursprünglichen (Längen halbiert → Area / 4)
|
||||
// Areas are one quarter of the original (lengths halved → Area / 4)
|
||||
EXPECT_NEAR(0.125, triangle_area_2d(verts[0], verts[1], verts[2]), 1e-10);
|
||||
EXPECT_NEAR(0.125, triangle_area_2d(verts[0], verts[2], verts[3]), 1e-10);
|
||||
|
||||
auto [max_r, mean_r, sum_r] = scale_invariant_circumradius_stats(verts, faces);
|
||||
|
||||
// Skaleninvariante Größe muss identisch zu w=1 sein
|
||||
// Scale-invariant quantity must be identical to the w=1 case
|
||||
EXPECT_NEAR(std::sin(M_PI / 4.0), max_r, 1e-10);
|
||||
EXPECT_NEAR(std::sin(M_PI / 4.0), mean_r, 1e-10);
|
||||
EXPECT_NEAR(2.0 * std::sin(M_PI / 4.0), sum_r, 1e-10);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 7 — HomologyTest: Genus-2 Homologie-Generatoren
|
||||
// Test 7 — HomologyTest: genus-2 homology generators
|
||||
// Java: HomologyTest.testHomology
|
||||
//
|
||||
// Java-Test:
|
||||
// CoHDS hds = TestUtility.readOBJ("brezel2.obj"); // Genus-2-Brezel-Fläche
|
||||
// Java test:
|
||||
// CoHDS hds = TestUtility.readOBJ("brezel2.obj"); // genus-2 pretzel surface
|
||||
// List<Set<CoEdge>> paths = getGeneratorPaths(hds.getVertex(0), weightAdapter);
|
||||
// Assert.assertEquals(4, paths.size()); // 2g = 4 für g = 2
|
||||
// Assert.assertEquals(4, paths.size()); // 2g = 4 for g = 2
|
||||
//
|
||||
// C++-Äquivalent:
|
||||
// C++ equivalent:
|
||||
// ConformalMesh mesh = load_mesh("code/data/obj/brezel2.obj");
|
||||
// CutGraph cg = compute_cut_graph(mesh);
|
||||
// EXPECT_EQ(4u, cg.cut_edge_indices.size()); // 2g = 4
|
||||
// EXPECT_EQ(2, cg.genus);
|
||||
//
|
||||
// Mesh: V=2622, F=5248, E=7872, χ=−2, genus=2.
|
||||
// Pfad via CONFORMALLAB_DATA_DIR (CMakeLists.txt: ${CMAKE_SOURCE_DIR}/data).
|
||||
// Path via CONFORMALLAB_DATA_DIR (CMakeLists.txt: ${CMAKE_SOURCE_DIR}/data).
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(HomologyGenerators, Genus2_FourCutEdges)
|
||||
@@ -359,17 +359,17 @@ TEST(HomologyGenerators, Genus2_FourCutEdges)
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Tests 8–9 — EuclideanLayoutTest: Kantenlängenerhalt auf tetraflat.obj
|
||||
// Tests 8–9 — EuclideanLayoutTest: edge-length preservation on tetraflat.obj
|
||||
// Java: EuclideanLayoutTest.testDoLayout
|
||||
//
|
||||
// Java-Test:
|
||||
// Vector u = new SparseVector(n); // u = 0 (kein konformer Faktor)
|
||||
// Java test:
|
||||
// Vector u = new SparseVector(n); // u = 0 (no conformal factor)
|
||||
// EuclideanLayout.doLayout(hds, fun, u);
|
||||
// for (CoEdge e : hds.getEdges())
|
||||
// assertEquals(Pn.distanceBetween(s.P, t.P), Pn.distanceBetween(s.T, t.T), 1E-11);
|
||||
//
|
||||
// Bedeutung: Mit u=0 ist der konforme Faktor 0, also ℓ̃ = ℓ (keine Verformung).
|
||||
// Das Layout muss die ursprünglichen 3D-Kantenlängen exakt reproduzieren.
|
||||
// Meaning: with u=0 the conformal factor is 0, so ℓ̃ = ℓ (no deformation).
|
||||
// The layout must reproduce the original 3D edge lengths exactly.
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(EuclideanLayout, DoLayout_TetraFlat_EdgeLengthsPreserved)
|
||||
@@ -414,18 +414,18 @@ TEST(EuclideanLayout, DoLayout_TetraFlat_EdgeLengthsPreserved)
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 10 — EuclideanCyclicConvergenceTest: Newton auf cathead.obj
|
||||
// Java: EuclideanLayoutTest.testLayout02 (130-Werte-Regression auf cathead.heml)
|
||||
// Test 10 — EuclideanCyclicConvergenceTest: Newton on cathead.obj
|
||||
// Java: EuclideanLayoutTest.testLayout02 (130-value regression on cathead.heml)
|
||||
// EuclideanCyclicConvergenceTest.testEuclideanConvergence
|
||||
//
|
||||
// Java-Test:
|
||||
// Java test:
|
||||
// EuclideanLayout.doLayout(hdsCat, fun, uCat);
|
||||
// for (CoVertex v : interior vertices)
|
||||
// assertEquals(2*PI, calculateAngleSum(v), 1E-6);
|
||||
// for (CoEdge e : positiveEdges)
|
||||
// assertEquals(fun.getNewLength(e, u), tLength, 1E-6);
|
||||
//
|
||||
// C++-Äquivalent: Newton converges on cathead.obj; interior angle sums ≈ 2π.
|
||||
// C++ equivalent: Newton converges on cathead.obj; interior angle sums ≈ 2π.
|
||||
// The 130-value u-vector from the Java test is cathead-topology-specific and
|
||||
// depends on vertex ordering in the Java CoHDS — not portable directly.
|
||||
// Instead we verify the same mathematical invariant: convergence + angle sums.
|
||||
@@ -468,18 +468,18 @@ TEST(EuclideanLayout, CatHead_NewtonConverges_AngleSumsTwoPi)
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Test 11 — SphericalConvergenceTest: Newton auf Oktaeder
|
||||
// Test 11 — SphericalConvergenceTest: Newton on octahedron
|
||||
// Java: SphericalConvergenceTest.testSphericalConvergence
|
||||
//
|
||||
// Java-Test:
|
||||
// Java test:
|
||||
// FunctionalTest.createOctahedron(hds, aSet);
|
||||
// // randomly perturb vertex radii (seed=1)
|
||||
// prepareInvariantDataHyperbolicAndSpherical(functional, hds, aSet, u);
|
||||
// optimizer.minimize(u, opt);
|
||||
// for (CoVertex v) assertEquals(2*PI, sum of angles at v, 1E-8);
|
||||
//
|
||||
// C++: regulärer Oktaeder (alle Knoten auf S², keine Störung), sphärischer Newton,
|
||||
// prüft Konvergenz + Restgradienten (≡ Winkeldefekt = 0 nach Konvergenz).
|
||||
// C++: regular octahedron (all vertices on S², no perturbation), spherical Newton,
|
||||
// checks convergence + residual gradients (≡ angle deficit = 0 after convergence).
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(SphericalLayout, SphericalTetrahedron_NewtonConverges_AngleSumsTwoPi)
|
||||
|
||||
@@ -28,22 +28,22 @@ Java reference implementation: [github.com/varylab/conformallab](https://github.
|
||||
|
||||
## geometry-central cross-reference *(optional comparison track)*
|
||||
|
||||
> Diese Referenzen beziehen sich auf eine alternative Implementierung desselben
|
||||
> mathematischen Problems. Sie sind keine Voraussetzung für conformallab++,
|
||||
> aber relevant für Kreuz-Validierung und mögliche algorithmische Adoptionen
|
||||
> (→ GC-1/2/3 im Phasen-Roadmap, → Abschnitt 9 in `validation.md`).
|
||||
> These references relate to an alternative implementation of the same
|
||||
> mathematical problem. They are not prerequisites for conformallab++,
|
||||
> but are relevant for cross-validation and possible algorithmic adoptions
|
||||
> (→ GC-1/2/3 in the phase roadmap, → Section 9 in `validation.md`).
|
||||
|
||||
| Reference | Relevanz |
|
||||
| Reference | Relevance |
|
||||
|---|---|
|
||||
| **Gillespie, Springborn, Crane** — *Discrete Conformal Equivalence of Polyhedral Surfaces*, ACM SIGGRAPH 2021. DOI: [10.1145/3450626.3459763](https://doi.org/10.1145/3450626.3459763) | Implementiert in **geometry-central**. Erweitert Springborn 2020 um intrinsische Triangulierungen und Ptolemäische Flips. Löst dasselbe DCE-Problem wie conformallab++, aber mit anderem Algorithmus. |
|
||||
| **Sharp, Soliman, Crane** — *Navigating Intrinsic Triangulations*, ACM SIGGRAPH 2019 | Algorithmische Grundlage für `SignpostIntrinsicTriangulation` in geometry-central — relevant für GC-2 (optionales Pre-Conditioning). |
|
||||
| **Gillespie, Springborn, Crane** — *Discrete Conformal Equivalence of Polyhedral Surfaces*, ACM SIGGRAPH 2021. DOI: [10.1145/3450626.3459763](https://doi.org/10.1145/3450626.3459763) | Implemented in **geometry-central**. Extends Springborn 2020 with intrinsic triangulations and Ptolemaic flips. Solves the same DCE problem as conformallab++, but with a different algorithm. |
|
||||
| **Sharp, Soliman, Crane** — *Navigating Intrinsic Triangulations*, ACM SIGGRAPH 2019 | Algorithmic basis for `SignpostIntrinsicTriangulation` in geometry-central — relevant for GC-2 (optional pre-conditioning). |
|
||||
|
||||
**Hinweis zu Springborn 2020:**
|
||||
Das Papier *"Ideal Hyperbolic Polyhedra and Discrete Uniformization"*
|
||||
(Springborn, Discrete & Computational Geometry 2020) ist **in conformallab++
|
||||
bereits implementiert** — es ist die direkte Referenz für den HyperIdeal-Geometriemodus
|
||||
(`hyper_ideal_geometry.hpp`). Die geometry-central Implementierung (Gillespie 2021)
|
||||
baut auf diesem Papier auf und ergänzt es um Ptolemäische Flips.
|
||||
**Note on Springborn 2020:**
|
||||
The paper *"Ideal Hyperbolic Polyhedra and Discrete Uniformization"*
|
||||
(Springborn, Discrete & Computational Geometry 2020) is **already implemented in
|
||||
conformallab++** — it is the direct reference for the HyperIdeal geometry mode
|
||||
(`hyper_ideal_geometry.hpp`). The geometry-central implementation (Gillespie 2021)
|
||||
builds on this paper and augments it with Ptolemaic flips.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -193,66 +193,58 @@ These are the **holonomy consistency** checks implemented in `test_phase7.cpp`
|
||||
|
||||
## 9 — Cross-validation with geometry-central *(optional / hypothetical)*
|
||||
|
||||
> **Hinweis:** Dieser Abschnitt beschreibt eine mögliche externe Kreuz-Validierung,
|
||||
> die keine Voraussetzung für die Korrektheit der Implementierung ist.
|
||||
> Sie ist interessant, weil geometry-central denselben mathematischen Kern
|
||||
> implementiert (Gillespie, Springborn, Crane — SIGGRAPH 2021, aufbauend auf
|
||||
> Springborn 2020), aber mit einer anderen algorithmischen Strategie
|
||||
> (Ptolemäische Flips + intrinsische Triangulierungen statt Newton auf der
|
||||
> Original-Triangulierung).
|
||||
> **Note:** This section describes a possible external cross-validation that is not
|
||||
> a prerequisite for the correctness of the implementation.
|
||||
> It is of interest because geometry-central implements the same mathematical core
|
||||
> (Gillespie, Springborn, Crane — SIGGRAPH 2021, building on
|
||||
> Springborn 2020), but with a different algorithmic strategy
|
||||
> (Ptolemaic flips + intrinsic triangulations instead of Newton on the
|
||||
> original triangulation).
|
||||
|
||||
### Welche Outputs sind vergleichbar?
|
||||
### Which outputs are comparable?
|
||||
|
||||
| Output | conformallab++ | geometry-central | Vergleichbar? |
|
||||
| Output | conformallab++ | geometry-central | Comparable? |
|
||||
|---|---|---|---|
|
||||
| u-Vektor (Skalierungsparameter) | `res.x` | `u` nach Yamabe flow | ✓ nach Normalisierung |
|
||||
| UV-Koordinaten | `layout.uv[v]` | konforme Parametrisierung | ✓ bis auf Möbius-Transformation |
|
||||
| Gauss-Bonnet Defekt | `gauss_bonnet_sum()` | implizit via Krümmungsfluss | ✓ (analytisch identisch) |
|
||||
| Anzahl Newton-Iterationen | `res.iterations` | Yamabe-Schritte | ~ (anderer Algorithmus) |
|
||||
| Period-Matrix τ | `pd.tau_reduced` | **nicht vorhanden** | ✗ |
|
||||
| Möbius-Holonomie | `hol.T_a, T_b` | **nicht vorhanden** | ✗ |
|
||||
| u-vector (scale parameters) | `res.x` | `u` after Yamabe flow | ✓ after normalisation |
|
||||
| UV coordinates | `layout.uv[v]` | conformal parameterisation | ✓ up to Möbius transformation |
|
||||
| Gauss-Bonnet deficit | `gauss_bonnet_sum()` | implicit via curvature flow | ✓ (analytically identical) |
|
||||
| Number of Newton iterations | `res.iterations` | Yamabe steps | ~ (different algorithm) |
|
||||
| Period matrix τ | `pd.tau_reduced` | **not available** | ✗ |
|
||||
| Möbius holonomy | `hol.T_a, T_b` | **not available** | ✗ |
|
||||
|
||||
### Normalisierungsabgleich
|
||||
### Normalisation alignment
|
||||
|
||||
Der u-Vektor in conformallab++ hat einen Freiheitsgrad (globale additive Konstante —
|
||||
Eichfreiheit nach Pin-Fixierung). geometry-central kann eine andere Konvention nutzen.
|
||||
Vor dem Vergleich normalisieren:
|
||||
The u-vector in conformallab++ has one degree of freedom (global additive constant —
|
||||
gauge freedom after pin-fixing). geometry-central may use a different convention.
|
||||
Normalise before comparing:
|
||||
|
||||
```cpp
|
||||
// conformallab++: u zentrieren
|
||||
// conformallab++: centre u
|
||||
double mean_u = std::accumulate(x.begin(), x.end(), 0.0) / x.size();
|
||||
std::vector<double> x_norm(x.size());
|
||||
for (int i = 0; i < x.size(); ++i) x_norm[i] = x[i] - mean_u;
|
||||
|
||||
// Dann mit geometry-central u-Vektor (ebenfalls zentriert) vergleichen:
|
||||
// max|x_norm[i] - gc_u[i]| < 1e-8 → identischer Konvergenzpunkt
|
||||
// Then compare with the geometry-central u-vector (also centred):
|
||||
// max|x_norm[i] - gc_u[i]| < 1e-8 → identical convergence point
|
||||
```
|
||||
|
||||
### Wann ist der Vergleich sinnvoll?
|
||||
### When is the comparison useful?
|
||||
|
||||
| Zeitpunkt | Was ist möglich |
|
||||
| Point in time | What is possible |
|
||||
|---|---|
|
||||
| **Jetzt (Phase 7)** | Manueller Vergleich mit denselben `.off`/`.obj` Testnetzen |
|
||||
| **Nach Phase 8** | Automatisiertes Vergleichsskript (Python oder separates C++-Binary) |
|
||||
| **Phase 10 (Forschung)** | Algorithmus-Vergleich: Newton vs. Ptolemäische Flips auf schwierigen Netzen |
|
||||
| **Now (Phase 7)** | Manual comparison using the same `.off`/`.obj` test meshes |
|
||||
| **After Phase 8** | Automated comparison script (Python or separate C++ binary) |
|
||||
| **Phase 10 (research)** | Algorithm comparison: Newton vs. Ptolemaic flips on difficult meshes |
|
||||
|
||||
### Voraussetzungen für einen fairen Vergleich
|
||||
### Connection to the literature
|
||||
|
||||
1. Identische Eingabenetze (OFF/OBJ, gleiche Vertex-Orientierung)
|
||||
2. Gleiche Gauss-Bonnet-Zielkrümmungen (Θᵥ = 2π für alle v, geschlossene Fläche)
|
||||
3. u-Normalisierung abgeglichen (zentriert, gleiche Eichfixierung)
|
||||
4. Konvergenztoleranz synchronisiert (max. Gradientnorm < 1e-8)
|
||||
|
||||
### Verbindung zur Literatur
|
||||
|
||||
Das Springborn 2020-Papier ("Ideal Hyperbolic Polyhedra and Discrete Uniformization")
|
||||
ist **in conformallab++ bereits implementiert** — es ist die mathematische Grundlage
|
||||
für den HyperIdeal-Geometriemodus (Phase 2/3). Die geometry-central Implementierung
|
||||
basiert auf der Weiterentwicklung von Gillespie, Springborn & Crane (2021), die
|
||||
denselben Variationsprinzip von Bobenko–Springborn 2004 verwendet, aber zusätzlich
|
||||
Ptolemäische Flips einsetzt, um die Triangulierung während der Optimierung zu
|
||||
verbessern — eine Idee, die in conformallab++ noch nicht implementiert ist (→ GC-2
|
||||
im Phasen-Roadmap).
|
||||
The Springborn 2020 paper ("Ideal Hyperbolic Polyhedra and Discrete Uniformization")
|
||||
is **already implemented in conformallab++** — it is the mathematical foundation
|
||||
for the HyperIdeal geometry mode (Phase 2/3). The geometry-central implementation
|
||||
is based on the extension by Gillespie, Springborn & Crane (2021), which uses the
|
||||
same variational principle of Bobenko–Springborn 2004 but additionally applies
|
||||
Ptolemaic flips to improve the triangulation during optimisation — an idea not yet
|
||||
implemented in conformallab++ (→ GC-2 in the phase roadmap).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -97,58 +97,57 @@ Java features from `de.varylab.discreteconformal` not yet in C++:
|
||||
|
||||
## ◼ Optional / Hypothetical — geometry-central Cross-Comparison
|
||||
|
||||
> **Status: keine geplante Phase — rein explorativ.**
|
||||
> Diese Punkte sind keine Voraussetzung für Phase 8–10. Sie sind
|
||||
> interessant, weil geometry-central (Keenan Crane, CMU) auf denselben
|
||||
> mathematischen Grundlagen wie conformallab++ aufbaut — insbesondere auf
|
||||
> **Springborn 2020** und der direkten Weiterentwicklung durch
|
||||
> **Status: no planned phase — purely exploratory.**
|
||||
> These items are not prerequisites for Phase 8–10. They are
|
||||
> of interest because geometry-central (Keenan Crane, CMU) is built on the same
|
||||
> mathematical foundations as conformallab++ — in particular
|
||||
> **Springborn 2020** and its direct extension by
|
||||
> **Gillespie, Springborn & Crane (SIGGRAPH 2021)**.
|
||||
> Der entscheidende Unterschied: geometry-central löst dasselbe Problem
|
||||
> (diskrete konforme Äquivalenz) mit **intrinsischen Triangulierungen +
|
||||
> Ptolemäischen Flips**, während conformallab++ **Newton auf der
|
||||
> Original-Triangulierung** anwendet.
|
||||
> The key difference: geometry-central solves the same problem
|
||||
> (discrete conformal equivalence) using **intrinsic triangulations +
|
||||
> Ptolemaic flips**, while conformallab++ applies **Newton on the
|
||||
> original triangulation**.
|
||||
|
||||
```
|
||||
GC-1 [optional, jetzt möglich]
|
||||
Mathematischer Output-Vergleich
|
||||
→ gleiche Testnetze (cathead.obj, brezel.obj, torus_4x4.off) in
|
||||
beide Bibliotheken laden
|
||||
→ UV-Koordinaten, u-Vektor, Residualnorm vergleichen
|
||||
→ Normalisierungskonventionen abgleichen (u-Mittelwert, Skalierung)
|
||||
Ziel: unabhängige Kreuz-Validierung der Konvergenzpunkte.
|
||||
Aufwand: kleines Python/C++ Vergleichsskript, kein Bibliotheks-Umbau.
|
||||
GC-1 [optional, possible now]
|
||||
Mathematical output comparison
|
||||
→ load the same test meshes (cathead.obj, brezel.obj, torus_4x4.off) into
|
||||
both libraries
|
||||
→ compare UV coordinates, u-vector, residual norm
|
||||
→ align normalisation conventions (u mean, scaling)
|
||||
Goal: independent cross-validation of convergence points.
|
||||
Effort: small Python/C++ comparison script, no library restructuring.
|
||||
|
||||
GC-2 [optional, sinnvoll nach Phase 8]
|
||||
Intrinsic Delaunay Pre-Conditioning
|
||||
→ Vor dem Newton-Solver: geometry-central SignpostIntrinsicTriangulation
|
||||
auf die Eingabe anwenden
|
||||
→ Ptolemäische Flips konditionieren die Hessian-Matrix vor
|
||||
→ Hypothese: weniger Newton-Iterationen auf nicht-Delaunay-Eingaben
|
||||
→ Implementierbar als optionaler cmake-Flag: -DWITH_GC_PRECOND=ON
|
||||
Abhängigkeit: geometry-central als optionale externe Abhängigkeit
|
||||
(header-only Teile genügen für den Flip-Algorithmus).
|
||||
GC-2 [optional, useful after Phase 8]
|
||||
Intrinsic Delaunay pre-conditioning
|
||||
→ before the Newton solver: apply geometry-central SignpostIntrinsicTriangulation
|
||||
to the input
|
||||
→ Ptolemaic flips pre-condition the Hessian matrix
|
||||
→ hypothesis: fewer Newton iterations on non-Delaunay inputs
|
||||
→ implementable as an optional cmake flag: -DWITH_GC_PRECOND=ON
|
||||
Dependency: geometry-central as an optional external dependency
|
||||
(header-only parts suffice for the flip algorithm).
|
||||
|
||||
GC-3 [hypothetisch, Phase 10+ Forschung]
|
||||
Ptolemäische Flip-basierter Solver als alternativer Backend
|
||||
→ Statt Newton: Ptolemäische Flips + penultimate-step Normalisierung
|
||||
(Gillespie–Springborn–Crane 2021 Algorithmus)
|
||||
→ Vergleich: Konvergenzradius, Robustheit auf pathologischen Netzen,
|
||||
numerische Stabilität auf hohen Genus-Flächen
|
||||
→ Für conformallab++ interessant, weil der Newton-Ansatz auf
|
||||
stark nicht-Delaunay Netzen (z.B. nach Remeshing) instabil
|
||||
werden kann.
|
||||
Keine Implementierung geplant — Konzeptnotiz für Phase 10-Forschung.
|
||||
GC-3 [hypothetical, Phase 10+ research]
|
||||
Ptolemaic flip-based solver as an alternative backend
|
||||
→ instead of Newton: Ptolemaic flips + penultimate-step normalisation
|
||||
(Gillespie–Springborn–Crane 2021 algorithm)
|
||||
→ comparison: convergence radius, robustness on pathological meshes,
|
||||
numerical stability on high-genus surfaces
|
||||
→ relevant for conformallab++ because the Newton approach can become
|
||||
unstable on strongly non-Delaunay meshes (e.g. after remeshing).
|
||||
No implementation planned — conceptual note for Phase 10 research.
|
||||
```
|
||||
|
||||
**Verbindung zur Literatur:**
|
||||
Das Springborn 2020-Papier ("Ideal Hyperbolic Polyhedra and Discrete
|
||||
Uniformization") ist in conformallab++ als HyperIdeal-Geometriemodus
|
||||
bereits implementiert (Phase 2/3). Die Gillespie–Springborn–Crane
|
||||
2021-Erweiterung — die geometry-central implementiert — ergänzt dies um
|
||||
intrinsische Triangulierungen und macht den Algorithmus robust gegen
|
||||
schlechte Eingangs-Triangulierungen. Beide teilen denselben
|
||||
mathematischen Kern (diskrete konforme Äquivalenz, Gauss–Bonnet,
|
||||
Variationsprinzip von Bobenko–Springborn 2004).
|
||||
**Connection to the literature:**
|
||||
The Springborn 2020 paper ("Ideal Hyperbolic Polyhedra and Discrete
|
||||
Uniformization") is already implemented in conformallab++ as the HyperIdeal
|
||||
geometry mode (Phase 2/3). The Gillespie–Springborn–Crane
|
||||
2021 extension — implemented in geometry-central — augments this with
|
||||
intrinsic triangulations and makes the algorithm robust against
|
||||
poor input triangulations. Both share the same
|
||||
mathematical core (discrete conformal equivalence, Gauss–Bonnet,
|
||||
variational principle of Bobenko–Springborn 2004).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user