#include #include "vde/curves/surface_analysis.h" #include "vde/curves/nurbs_curve.h" #include "vde/curves/nurbs_surface.h" #include "vde/brep/modeling.h" #include using namespace vde::curves; using namespace vde::core; using namespace vde::brep; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- /// Create a planar NURBS surface on XY plane over [0,1]×[0,1] static NurbsSurface plane_surface() { std::vector> grid = { {Point3D(0,0,0), Point3D(0,1,0)}, {Point3D(1,0,0), Point3D(1,1,0)} }; return NurbsSurface(grid, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1); } /// Create a simple NURBS curve (line) static NurbsCurve line(const Point3D& a, const Point3D& b) { return NurbsCurve({a, b}, {0, 0, 1, 1}, {1, 1}, 1); } /// Create a cubic NURBS curve (parabola-like) static NurbsCurve cubic_curve() { return NurbsCurve( {Point3D(0,0,0), Point3D(1,2,0), Point3D(2,1,0), Point3D(3,0,0)}, {0,0,0,0,1,1,1,1}, {1,1,1,1}, 3); } // --------------------------------------------------------------------------- // Test: CurvatureMap // --------------------------------------------------------------------------- TEST(SurfaceAnalysisTest, CurvatureMap_PlaneIsDevelopable) { auto surf = plane_surface(); auto cm = curvature_map(surf, 20, 20); EXPECT_EQ(21, static_cast(cm.grid.size())); EXPECT_EQ(21, static_cast(cm.grid[0].size())); // Plane: Gaussian curvature ≈ 0, Mean curvature ≈ 0 EXPECT_NEAR(cm.min_gaussian, 0.0, 1e-9); EXPECT_NEAR(cm.max_gaussian, 0.0, 1e-9); EXPECT_NEAR(cm.min_mean, 0.0, 1e-9); EXPECT_NEAR(cm.max_mean, 0.0, 1e-9); EXPECT_TRUE(cm.is_developable()); } TEST(SurfaceAnalysisTest, CurvatureMap_GridDimensions) { auto surf = plane_surface(); auto cm = curvature_map(surf, 5, 8); EXPECT_EQ(6, static_cast(cm.grid.size())); // res_u+1 EXPECT_EQ(9, static_cast(cm.grid[0].size())); // res_v+1 EXPECT_EQ(5, cm.res_u); EXPECT_EQ(8, cm.res_v); } // --------------------------------------------------------------------------- // Test: Zebra Stripe // --------------------------------------------------------------------------- TEST(SurfaceAnalysisTest, ZebraStripe_OutputDimensions) { auto surf = plane_surface(); auto zs = zebra_stripe(surf, Vector3D(1, 0, 0), 15, 10); EXPECT_EQ(16, static_cast(zs.intensity.size())); EXPECT_EQ(11, static_cast(zs.intensity[0].size())); EXPECT_EQ(15, zs.res_u); EXPECT_EQ(10, zs.res_v); // Check light direction is normalized EXPECT_NEAR(zs.light_direction.norm(), 1.0, 1e-12); } TEST(SurfaceAnalysisTest, ZebraStripe_IntensityRange) { auto surf = plane_surface(); auto zs = zebra_stripe(surf, Vector3D(0, 0, 1), 10, 10); for (size_t i = 0; i < zs.intensity.size(); ++i) { for (size_t j = 0; j < zs.intensity[i].size(); ++j) { double val = zs.intensity[i][j]; EXPECT_GE(val, 0.0); EXPECT_LE(val, 1.0); } } } // --------------------------------------------------------------------------- // Test: Curvature Comb // --------------------------------------------------------------------------- TEST(SurfaceAnalysisTest, CurvatureComb_StraightLine) { auto c = line(Point3D(0, 0, 0), Point3D(10, 0, 0)); auto comb = curvature_comb(c, 20); EXPECT_EQ(21, static_cast(comb.points.size())); // Straight line has zero curvature EXPECT_NEAR(comb.min_curvature, 0.0, 1e-12); EXPECT_NEAR(comb.max_curvature, 0.0, 1e-12); } TEST(SurfaceAnalysisTest, CurvatureComb_NonzeroCurvature) { auto c = cubic_curve(); auto comb = curvature_comb(c, 100); EXPECT_EQ(101, static_cast(comb.points.size())); // Cubic curve has non-zero curvature EXPECT_GT(comb.max_curvature, 0.0); // Scale should be auto-computed EXPECT_GT(comb.scale, 0.0); } // --------------------------------------------------------------------------- // Test: Deviation Analysis // --------------------------------------------------------------------------- TEST(SurfaceAnalysisTest, DeviationAnalysis_IdenticalPlanes) { auto s1 = plane_surface(); auto s2 = plane_surface(); auto result = deviation_analysis(s1, s2, 10); EXPECT_EQ(100u, result.sample_count); // Identical planes: deviation ≈ 0 EXPECT_NEAR(result.rms, 0.0, 1e-6); EXPECT_NEAR(result.mean_absolute, 0.0, 1e-6); } TEST(SurfaceAnalysisTest, DeviationAnalysis_OffsetPlanes) { auto s1 = plane_surface(); // Same plane shifted up by 1 in Z std::vector> grid2 = { {Point3D(0,0,1), Point3D(0,1,1)}, {Point3D(1,0,1), Point3D(1,1,1)} }; auto s2 = NurbsSurface(grid2, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1); auto result = deviation_analysis(s1, s2, 10); EXPECT_NEAR(result.max_positive, 1.0, 0.05); EXPECT_NEAR(result.rms, 1.0, 0.05); } // --------------------------------------------------------------------------- // Test: Draft Face Angle // --------------------------------------------------------------------------- TEST(SurfaceAnalysisTest, DraftAngle_HorizontalPlaneVerticalPull) { auto surf = plane_surface(); // Horizontal plane (normal = +Z), vertical pull (+Z) → angle = -π/2 // (face normal parallel to pull: face is perpendicular to opening) double angle = draft_face_angle(surf, 0.5, 0.5, Vector3D(0, 0, 1)); EXPECT_NEAR(angle, -M_PI_2, 1e-6); } TEST(SurfaceAnalysisTest, DraftAngle_PullPerpendicularToNormal) { auto surf = plane_surface(); // Horizontal plane (normal = +Z), pull in X → face parallel to pull → angle ≈ 0 double angle = draft_face_angle(surf, 0.5, 0.5, Vector3D(1, 0, 0)); EXPECT_NEAR(angle, 0.0, 1e-6); } TEST(SurfaceAnalysisTest, DraftAngle_BrepModel) { auto box = make_box(10, 10, 10); // Top face has normal ≈ +Z, pull +Z → angle ≈ -π/2 double angle = draft_face_angle(box, 0, Vector3D(0, 0, 1), 5); EXPECT_NEAR(std::abs(angle), M_PI_2, 0.01); }