#include #include "vde/mesh/mesh_smooth.h" #include "vde/mesh/halfedge_mesh.h" using namespace vde::mesh; // Helper: create a simple 4-vertex quad mesh (2 triangles) static HalfedgeMesh make_quad_mesh() { HalfedgeMesh mesh; // Quad with slight noise on one vertex mesh.build_from_triangles( { Point3D(0, 0, 0), Point3D(1, 0, 0), Point3D(1, 1, 0.5), // perturbed in Z Point3D(0, 1, 0), }, {{0, 1, 2}, {0, 2, 3}} ); return mesh; } TEST(MeshSmoothTest, LaplacianSmooth_ReducesNoise) { HalfedgeMesh mesh = make_quad_mesh(); // Original: vertex 2 has Z = 0.5 perturbation EXPECT_NEAR(mesh.vertex(2).z(), 0.5, 1e-6); SmoothOptions opts; opts.method = SmoothMethod::Laplacian; opts.iterations = 5; opts.lambda = 0.5; HalfedgeMesh smoothed = smooth_mesh(mesh, opts); // After smoothing, the noise should be reduced // Vertex 2 Z should be closer to 0 (the Laplacian average) EXPECT_LE(std::abs(smoothed.vertex(2).z()), 0.5); } TEST(MeshSmoothTest, LaplacianNoop_FlatMesh) { HalfedgeMesh mesh; mesh.build_from_triangles( { Point3D(0, 0, 0), Point3D(1, 0, 0), Point3D(1, 1, 0), Point3D(0, 1, 0), }, {{0, 1, 2}, {0, 2, 3}} ); SmoothOptions opts; opts.method = SmoothMethod::Laplacian; opts.iterations = 3; opts.lambda = 0.5; HalfedgeMesh smoothed = smooth_mesh(mesh, opts); // Flat mesh should remain flat for (size_t i = 0; i < smoothed.num_vertices(); ++i) { EXPECT_NEAR(smoothed.vertex(i).z(), 0.0, 1e-9); } } TEST(MeshSmoothTest, TaubinPreservesVolume) { HalfedgeMesh mesh = make_quad_mesh(); // Compute original bounding box volume auto original_bounds = mesh.bounds(); double original_volume = original_bounds.volume(); SmoothOptions opts; opts.method = SmoothMethod::Taubin; opts.lambda = 0.5; opts.mu = -0.53; opts.iterations = 5; HalfedgeMesh smoothed = smooth_mesh(mesh, opts); auto smoothed_bounds = smoothed.bounds(); double smoothed_volume = smoothed_bounds.volume(); // Taubin should better preserve volume than pure Laplacian // Volume change should be reasonable (not shrinking to 0) EXPECT_GT(smoothed_volume, 0.0); // Noise reduction: vertex 2 Z should be smoothed EXPECT_LE(std::abs(smoothed.vertex(2).z()), 0.5); // Volume change ratio should be reasonable (< 50% change) double ratio = std::abs(smoothed_volume - original_volume) / std::max(original_volume, 1e-9); EXPECT_LE(ratio, 0.5); } TEST(MeshSmoothTest, DefaultOptions) { HalfedgeMesh mesh = make_quad_mesh(); // Default options: Laplacian, 10 iterations, lambda=0.5 HalfedgeMesh smoothed = smooth_mesh(mesh); EXPECT_EQ(smoothed.num_vertices(), mesh.num_vertices()); EXPECT_EQ(smoothed.num_faces(), mesh.num_faces()); } TEST(MeshSmoothTest, DifferentIterationCounts) { HalfedgeMesh mesh = make_quad_mesh(); double original_z = mesh.vertex(2).z(); SmoothOptions opts_few; opts_few.method = SmoothMethod::Laplacian; opts_few.iterations = 1; opts_few.lambda = 0.5; HalfedgeMesh smooth_1 = smooth_mesh(mesh, opts_few); SmoothOptions opts_many; opts_many.method = SmoothMethod::Laplacian; opts_many.iterations = 20; opts_many.lambda = 0.5; HalfedgeMesh smooth_20 = smooth_mesh(mesh, opts_many); // More iterations → more smoothing (vertex 2 Z closer to 0) double delta_1 = std::abs(smooth_1.vertex(2).z() - 0.0); double delta_20 = std::abs(smooth_20.vertex(2).z() - 0.0); // 20 iterations should smooth more than 1 EXPECT_LE(delta_20, delta_1 + 1e-6); } TEST(MeshSmoothTest, SingleTriangleUnaffected) { // Single triangle: smoothing has no effect (all vertices are boundary) HalfedgeMesh mesh; mesh.build_from_triangles( {Point3D(0, 0, 2), Point3D(1, 0, 0), Point3D(0, 1, 0)}, {{0, 1, 2}} ); SmoothOptions opts; opts.method = SmoothMethod::Laplacian; opts.iterations = 5; opts.lambda = 0.5; HalfedgeMesh smoothed = smooth_mesh(mesh, opts); // Single triangle: topological boundary, so minimal change expected // But implementation might still move vertices EXPECT_EQ(smoothed.num_vertices(), 3u); EXPECT_EQ(smoothed.num_faces(), 1u); } TEST(MeshSmoothTest, ZeroIterations) { HalfedgeMesh mesh = make_quad_mesh(); SmoothOptions opts; opts.iterations = 0; HalfedgeMesh smoothed = smooth_mesh(mesh, opts); // Zero iterations → mesh unchanged for (size_t i = 0; i < mesh.num_vertices(); ++i) { EXPECT_NEAR((smoothed.vertex(i) - mesh.vertex(i)).norm(), 0.0, 1e-9); } }