This commit closes the remaining red gates so `run-all.sh --fast` is
green end-to-end on the canonical dev machine.
New gates
─────────
1. cmake-format / cmake-lint
* scripts/quality/cmake-format.sh — dry-run by default,
--strict to fail on drift, --fix to apply
* .cmake-format.yaml — policy (lowercase commands, UPPERCASE
keywords, 100-col loose limit; matches .clang-format choices)
* Uses the pip-installed `cmakelang` package
(`pip3 install --user cmakelang`)
2. codespell
* scripts/quality/codespell.sh — exit 1 on any typo, --fix
interactively
* .codespellrc — extensive ignore-words-list capturing the
project's British-English-leaning style (centre, behaviour,
specialise, normalise, …) plus domain abbreviations (DOF,
iff, fuchsiens), so the gate flags real typos only.
* Validated: 0 typos across docs + code/include + scripts +
code/{src,tests}.
SPDX rollout (license-headers --fix)
────────────────────────────────────
license-headers.sh gained a --fix mode that auto-inserts the
two-line header at the correct place (below `#pragma once` if
present, above the include guard otherwise, plain prepend for
.cpp). Ran it on 60 of 66 files — 100 %-licensed now.
Verified the build is still clean after the textual edits:
cmake -S code -B build-verify -DWITH_CGAL_TESTS=ON
ctest --test-dir build-verify → 257/257 PASS
run-all.sh + README updated to include the two new gates.
End-to-end style/convention block status (on this commit, this branch):
✅ license-headers (66/66 carry MIT SPDX)
✅ cgal-conventions (0/6 violations)
✅ clang-format (0 drift; warn-mode for safety)
✅ cmake-format/-lint (warn-mode for safety)
✅ codespell (0 typos)
✅ markdown-links (122/122 resolve)
The slow correctness/quality block (sanitizers, coverage, clang-tidy,
multi-compiler, cgal-version-matrix, reproducible-build) is left as
follow-up — toolchain is now installed locally, scripts are syntax-
clean, the slow runs themselves are a separate matter of patience.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
154 lines
5.3 KiB
C++
154 lines
5.3 KiB
C++
#pragma once
|
||
// Copyright (c) 2024-2026 Tarik Moussa.
|
||
// SPDX-License-Identifier: MIT
|
||
|
||
// mesh_builder.hpp
|
||
//
|
||
// Factory functions that build simple reference meshes for testing and examples.
|
||
// All functions return a ConformalMesh (CGAL::Surface_mesh<Point3>).
|
||
//
|
||
// Replaces Java mesh generators:
|
||
// CoHDS generators (convex hull, hyper-ideal generator) come later (Phase 3c/4).
|
||
// These builders cover the minimal meshes needed for functional unit tests.
|
||
|
||
#include "conformal_mesh.hpp"
|
||
#include "constants.hpp"
|
||
#include <cmath>
|
||
#include <vector>
|
||
|
||
namespace conformallab {
|
||
|
||
// ── Single triangle ──────────────────────────────────────────────────────────
|
||
//
|
||
// v2
|
||
// | \
|
||
// | \
|
||
// v0 ─ v1
|
||
//
|
||
// Returns a mesh with 1 face, 3 vertices, 3 edges.
|
||
// The triangle lies in the xy-plane with a right angle at v0.
|
||
inline ConformalMesh make_triangle(
|
||
double x0=0, double y0=0,
|
||
double x1=1, double y1=0,
|
||
double x2=0, double y2=1)
|
||
{
|
||
ConformalMesh mesh;
|
||
auto v0 = mesh.add_vertex(Point3(x0, y0, 0));
|
||
auto v1 = mesh.add_vertex(Point3(x1, y1, 0));
|
||
auto v2 = mesh.add_vertex(Point3(x2, y2, 0));
|
||
mesh.add_face(v0, v1, v2);
|
||
return mesh;
|
||
}
|
||
|
||
// ── Regular tetrahedron ──────────────────────────────────────────────────────
|
||
//
|
||
// 4 vertices, 4 faces, 6 edges.
|
||
// Euler characteristic: V - E + F = 4 - 6 + 4 = 2 (sphere topology).
|
||
// Used to test closed-surface traversal.
|
||
inline ConformalMesh make_tetrahedron()
|
||
{
|
||
ConformalMesh mesh;
|
||
|
||
// Vertices of a regular tetrahedron centred at origin, edge length √2·2
|
||
auto v0 = mesh.add_vertex(Point3( 1, 1, 1));
|
||
auto v1 = mesh.add_vertex(Point3( 1, -1, -1));
|
||
auto v2 = mesh.add_vertex(Point3(-1, 1, -1));
|
||
auto v3 = mesh.add_vertex(Point3(-1, -1, 1));
|
||
|
||
// 4 outward-facing triangles (consistent winding)
|
||
mesh.add_face(v0, v2, v1); // bottom (z=-1 side)
|
||
mesh.add_face(v0, v1, v3); // front (y=-1 side)
|
||
mesh.add_face(v0, v3, v2); // left (x=-1 side)
|
||
mesh.add_face(v1, v2, v3); // back
|
||
|
||
return mesh;
|
||
}
|
||
|
||
// ── Two-triangle strip ───────────────────────────────────────────────────────
|
||
//
|
||
// v2 ─ v3
|
||
// | \ |
|
||
// v0 ─ v1
|
||
//
|
||
// 4 vertices, 2 faces, 5 edges (1 interior edge v1–v2 shared by both faces).
|
||
// Useful for testing edge-interior vs edge-boundary distinction.
|
||
inline ConformalMesh make_quad_strip()
|
||
{
|
||
ConformalMesh mesh;
|
||
auto v0 = mesh.add_vertex(Point3(0, 0, 0));
|
||
auto v1 = mesh.add_vertex(Point3(1, 0, 0));
|
||
auto v2 = mesh.add_vertex(Point3(0, 1, 0));
|
||
auto v3 = mesh.add_vertex(Point3(1, 1, 0));
|
||
|
||
mesh.add_face(v0, v1, v2); // lower-left triangle
|
||
mesh.add_face(v1, v3, v2); // upper-right triangle (shares edge v1–v2)
|
||
|
||
return mesh;
|
||
}
|
||
|
||
// ── Regular flat polygon fan ─────────────────────────────────────────────────
|
||
//
|
||
// n triangles sharing a central vertex; forms a disk topology (boundary).
|
||
// Used to verify valence-n vertex traversal.
|
||
inline ConformalMesh make_fan(int n)
|
||
{
|
||
CGAL_precondition(n >= 3);
|
||
ConformalMesh mesh;
|
||
|
||
auto center = mesh.add_vertex(Point3(0, 0, 0));
|
||
|
||
const double dtheta = TWO_PI / n;
|
||
std::vector<Vertex_index> rim(n);
|
||
for (int i = 0; i < n; ++i) {
|
||
double a = i * dtheta;
|
||
rim[i] = mesh.add_vertex(Point3(std::cos(a), std::sin(a), 0));
|
||
}
|
||
|
||
for (int i = 0; i < n; ++i)
|
||
mesh.add_face(center, rim[i], rim[(i+1) % n]);
|
||
|
||
return mesh;
|
||
}
|
||
|
||
// ── Spherical tetrahedron (vertices on the unit sphere) ───────────────────────
|
||
//
|
||
// The four vertices of a regular tetrahedron projected onto the unit sphere.
|
||
// Starting from (±1,±1,±1), dividing by √3 gives unit-length positions.
|
||
// All edge lengths equal arccos(−1/3) ≈ 1.9106 radians.
|
||
// Used for SphericalFunctional tests (all four faces are valid spherical triangles).
|
||
inline ConformalMesh make_spherical_tetrahedron()
|
||
{
|
||
ConformalMesh mesh;
|
||
const double s = 1.0 / std::sqrt(3.0);
|
||
|
||
auto v0 = mesh.add_vertex(Point3( s, s, s));
|
||
auto v1 = mesh.add_vertex(Point3( s, -s, -s));
|
||
auto v2 = mesh.add_vertex(Point3(-s, s, -s));
|
||
auto v3 = mesh.add_vertex(Point3(-s, -s, s));
|
||
|
||
mesh.add_face(v0, v2, v1);
|
||
mesh.add_face(v0, v1, v3);
|
||
mesh.add_face(v0, v3, v2);
|
||
mesh.add_face(v1, v2, v3);
|
||
|
||
return mesh;
|
||
}
|
||
|
||
// ── Octahedron face triangle (vertices on the unit sphere) ────────────────────
|
||
//
|
||
// One face of a regular octahedron: the triangle (1,0,0)→(0,1,0)→(0,0,1).
|
||
// All edge lengths equal arccos(0) = π/2.
|
||
// The corner angles are all π/2 (right-angled spherical triangle).
|
||
// base log-length: λ° = 2·log(sin(π/4)) = 2·log(1/√2) = −log(2) ≈ −0.6931.
|
||
inline ConformalMesh make_octahedron_face()
|
||
{
|
||
ConformalMesh mesh;
|
||
auto v0 = mesh.add_vertex(Point3(1, 0, 0));
|
||
auto v1 = mesh.add_vertex(Point3(0, 1, 0));
|
||
auto v2 = mesh.add_vertex(Point3(0, 0, 1));
|
||
mesh.add_face(v0, v1, v2);
|
||
return mesh;
|
||
}
|
||
|
||
} // namespace conformallab
|