#include #include "vde/curves/generative_surfaces.h" #include "vde/curves/nurbs_curve.h" #include "vde/core/point.h" #include using namespace vde::curves; using namespace vde::core; // ── 辅助:创建直线 NURBS ── static NurbsCurve make_line(const Point3D& a, const Point3D& b) { return NurbsCurve({a, b}, {0, 0, 1, 1}, {1, 1}, 1); } // ── 辅助:创建圆弧 profile ── static NurbsCurve make_arc_profile() { double r = 1.0; double w = std::sqrt(2.0) / 2.0; return NurbsCurve( {Point3D(0, r, 0), Point3D(r, r, 0), Point3D(r, 0, 0)}, {0, 0, 0, 0.5, 1, 1, 1}, {1, w, 1, w, 1, w, 1}, 2 ); } // ============================================================================ // Sweep 测试 // ============================================================================ TEST(GenerativeSurfacesTest, SweepExplicit_Basic) { // 圆形 profile 沿直线扫描 → 圆柱面 NurbsCurve profile( {Point3D(0, 1, 0), Point3D(1, 1, 0), Point3D(1, 0, 0)}, {0, 0, 0, 1, 1, 1}, {1, 1, 1}, 2 ); NurbsCurve path = make_line({0, 0, 0}, {0, 0, 5}); SweepOption opt; opt.type = SweepType::Explicit; opt.samples = 8; auto surf = sweep_surface(profile, path, opt); EXPECT_EQ(surf.degree_u(), 2); EXPECT_GE(surf.num_control_points()[0], 3); EXPECT_GE(surf.num_control_points()[1], 3); // 验证曲面在参数域中点可求值 auto p = surf.evaluate(0.5, 0.5); EXPECT_GE(p.x(), 0.0); EXPECT_LE(p.z(), 5.0); } TEST(GenerativeSurfacesTest, SweepExplicit_StraightPath) { // 矩形 profile 沿 X 轴扫描 NurbsCurve profile = make_line({0, 0, 0}, {0, 0, 2}); NurbsCurve path = make_line({0, 0, 0}, {10, 0, 0}); SweepOption opt; opt.type = SweepType::Explicit; opt.samples = 4; auto surf = sweep_surface(profile, path, opt); // 验证曲面两端 auto p0 = surf.evaluate(0.0, 0.0); auto p1 = surf.evaluate(1.0, 1.0); EXPECT_NEAR(p0.x(), 0.0, 1e-6); EXPECT_NEAR(p1.x(), 10.0, 1e-6); EXPECT_GE(p1.z(), 0.0); } TEST(GenerativeSurfacesTest, SweepExplicit_VaryingSamples) { NurbsCurve profile = make_line({0, 1, 0}, {0, -1, 0}); NurbsCurve path = make_line({0, 0, 0}, {0, 0, 3}); SweepOption opt; opt.type = SweepType::Explicit; opt.samples = 16; auto surf = sweep_surface(profile, path, opt); // 控制点数量应随采样增加 int n_u = surf.num_control_points()[0]; EXPECT_GT(n_u, 4); // 曲面可正常求值 auto mid = surf.evaluate(0.5, 0.5); EXPECT_NEAR(mid.x(), 0.0, 1e-6); EXPECT_NEAR(mid.z(), 1.5, 1.0); } TEST(GenerativeSurfacesTest, SweepSpine_Basic) { // 使用独立脊线的扫描 NurbsCurve profile = make_line({0, 1, 0}, {0, -1, 0}); NurbsCurve path = make_line({0, 0, 0}, {5, 0, 0}); // 脊线偏离路径,用于扭转控制 NurbsCurve spine = make_line({0, 0, 0}, {5, 0, 2}); SweepOption opt; opt.type = SweepType::Spine; opt.spine = spine; opt.samples = 8; auto surf = sweep_surface(profile, path, opt); EXPECT_GE(surf.num_control_points()[0], 3); EXPECT_GE(surf.num_control_points()[1], 2); // 验证曲面可求值 auto p = surf.evaluate(0.5, 0.5); EXPECT_FALSE(std::isnan(p.x())); EXPECT_FALSE(std::isnan(p.y())); EXPECT_FALSE(std::isnan(p.z())); } TEST(GenerativeSurfacesTest, SweepTwoGuides_Basic) { // 双引导线扫描:两条引导线间距变化控制缩放 NurbsCurve profile = make_line({0, 1, 0}, {0, -1, 0}); NurbsCurve path = make_line({0, 0, 0}, {5, 0, 0}); // 两条引导线逐渐分开 NurbsCurve guide1 = make_line({0, 0.5, 0}, {5, 2, 0}); NurbsCurve guide2 = make_line({0, -0.5, 0}, {5, -2, 0}); SweepOption opt; opt.type = SweepType::TwoGuides; opt.guide1 = guide1; opt.guide2 = guide2; opt.samples = 8; auto surf = sweep_surface(profile, path, opt); EXPECT_GE(surf.num_control_points()[0], 3); EXPECT_GE(surf.num_control_points()[1], 2); // 曲面起点和终点宽度应不同(缩放生效) auto p_start = surf.evaluate(0.0, 0.5); auto p_end = surf.evaluate(1.0, 0.5); EXPECT_GE(std::abs(p_end.y()) - std::abs(p_start.y()), -0.5); } TEST(GenerativeSurfacesTest, Sweep_DefaultOption) { // 默认选项(Explicit 模式) NurbsCurve profile = make_line({0, 1, 0}, {0, -1, 0}); NurbsCurve path = make_line({0, 0, 0}, {3, 0, 0}); auto surf = sweep_surface(profile, path); EXPECT_GE(surf.num_control_points()[0], 3); auto p = surf.evaluate(0.5, 0.5); EXPECT_FALSE(std::isnan(p.x())); } // ============================================================================ // Loft 测试 // ============================================================================ TEST(GenerativeSurfacesTest, Loft_Basic) { // 两条平行截面放样 NurbsCurve s1 = make_line({0, 0, 0}, {2, 0, 0}); NurbsCurve s2 = make_line({0, 2, 5}, {2, 2, 5}); auto surf = loft_surface({s1, s2}); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); // 验证曲面插值首尾截面 auto p_bottom = surf.evaluate(0.5, 0.0); EXPECT_NEAR(p_bottom.z(), 0.0, 1e-6); auto p_top = surf.evaluate(0.5, 1.0); EXPECT_NEAR(p_top.z(), 5.0, 1e-6); } TEST(GenerativeSurfacesTest, Loft_ThreeSections) { NurbsCurve s1 = make_line({0, 0, 0}, {2, 0, 0}); NurbsCurve s2 = make_line({0, 1, 3}, {2, 1, 3}); NurbsCurve s3 = make_line({0, 0, 6}, {2, 0, 6}); auto surf = loft_surface({s1, s2, s3}); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); // 中间截面应偏离直线 auto p_mid = surf.evaluate(0.5, 0.5); EXPECT_NEAR(p_mid.z(), 3.0, 1.0); EXPECT_GT(p_mid.y(), 0.0); } TEST(GenerativeSurfacesTest, Loft_WithGuides) { NurbsCurve s1 = make_line({0, 0, 0}, {2, 0, 0}); NurbsCurve s2 = make_line({0, 0, 5}, {2, 0, 5}); NurbsCurve s3 = make_line({0, 0, 10}, {2, 0, 10}); // 引导线:弯曲的脊线 NurbsCurve guide( {Point3D(0, 1, 2.5), Point3D(1, 0, 5), Point3D(0, -1, 7.5)}, {0, 0, 0, 1, 1, 1}, {1, 1, 1}, 2 ); auto surf = loft_surface({s1, s2, s3}, {guide}); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); auto p = surf.evaluate(0.5, 0.5); EXPECT_FALSE(std::isnan(p.x())); } TEST(GenerativeSurfacesTest, Loft_WithTangents) { NurbsCurve s1 = make_line({0, 0, 0}, {2, 0, 0}); NurbsCurve s2 = make_line({0, 0, 5}, {2, 0, 5}); LoftConstraint cons; cons.start_tangent = Vector3D(0, 0, 1); // 垂直向上 cons.end_tangent = Vector3D(0, 0, 1); // 垂直向上 auto surf = loft_surface({s1, s2}, {}, cons); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); // 曲面应能正常求值 auto p = surf.evaluate(0.5, 0.3); EXPECT_FALSE(std::isnan(p.x())); } TEST(GenerativeSurfacesTest, Loft_InvalidInput) { // 单个截面应抛出异常 NurbsCurve s1 = make_line({0, 0, 0}, {1, 0, 0}); EXPECT_THROW((void)loft_surface({s1}), std::invalid_argument); } // ============================================================================ // Net 测试 // ============================================================================ TEST(GenerativeSurfacesTest, Net_Basic) { // 双向曲线网格:u 向和 v 向各 2 条线 NurbsCurve u0 = make_line({0, 0, 0}, {5, 0, 0}); NurbsCurve u1 = make_line({0, 2, 0}, {5, 2, 0}); NurbsCurve v0 = make_line({0, 0, 0}, {0, 2, 0}); NurbsCurve v1 = make_line({5, 0, 0}, {5, 2, 0}); auto surf = net_surface({u0, u1}, {v0, v1}); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); // 曲面应在 XY 平面内 auto p = surf.evaluate(0.5, 0.5); EXPECT_NEAR(p.z(), 0.0, 1e-6); EXPECT_GE(p.x(), 0.0); EXPECT_GE(p.y(), 0.0); } TEST(GenerativeSurfacesTest, Net_UnequalCount) { // u 向 3 条,v 向 2 条 NurbsCurve u0 = make_line({0, 0, 0}, {5, 0, 0}); NurbsCurve u1 = make_line({0, 1, 0}, {5, 1, 0}); NurbsCurve u2 = make_line({0, 2, 0}, {5, 2, 0}); NurbsCurve v0 = make_line({0, 0, 0}, {0, 2, 0}); NurbsCurve v1 = make_line({5, 0, 0}, {5, 2, 0}); auto surf = net_surface({u0, u1, u2}, {v0, v1}); EXPECT_EQ(surf.num_control_points()[0], 3); EXPECT_EQ(surf.num_control_points()[1], 2); } TEST(GenerativeSurfacesTest, Net_3DCurves) { // 三维网格曲面 NurbsCurve u0( {Point3D(0, 0, 0), Point3D(1, 0, 1), Point3D(2, 0, 0)}, {0, 0, 0, 1, 1, 1}, {1, 1, 1}, 2 ); NurbsCurve u1( {Point3D(0, 2, 0), Point3D(1, 2, 1), Point3D(2, 2, 0)}, {0, 0, 0, 1, 1, 1}, {1, 1, 1}, 2 ); NurbsCurve v0 = make_line({0, 0, 0}, {0, 2, 0}); NurbsCurve v1 = make_line({2, 0, 0}, {2, 2, 0}); auto surf = net_surface({u0, u1}, {v0, v1}); EXPECT_GE(surf.num_control_points()[0], 2); EXPECT_GE(surf.num_control_points()[1], 2); auto p = surf.evaluate(0.5, 0.5); EXPECT_FALSE(std::isnan(p.x())); EXPECT_GE(p.z(), 0.0); } TEST(GenerativeSurfacesTest, Net_InvalidInput) { NurbsCurve u0 = make_line({0, 0, 0}, {1, 0, 0}); EXPECT_THROW((void)net_surface({u0}, {u0}), std::invalid_argument); NurbsCurve v0 = make_line({0, 0, 0}, {1, 0, 0}); EXPECT_THROW((void)net_surface({u0, u0}, {v0}), std::invalid_argument); } // ============================================================================ // 集成测试:组合使用 // ============================================================================ TEST(GenerativeSurfacesTest, Integration_SweepThenEvaluate) { // 验证扫掠后曲面求值一致性 NurbsCurve profile = make_line({0, 1, 0}, {0, -1, 0}); NurbsCurve path = make_line({0, 0, 0}, {10, 0, 0}); SweepOption opt; opt.type = SweepType::Explicit; opt.samples = 10; auto surf = sweep_surface(profile, path, opt); // 曲面法向应在 XY 平面内(近似) for (double u = 0.0; u <= 1.0; u += 0.25) { for (double v = 0.0; v <= 1.0; v += 0.25) { auto pt = surf.evaluate(u, v); EXPECT_FALSE(std::isnan(pt.x())); EXPECT_FALSE(std::isnan(pt.y())); EXPECT_FALSE(std::isnan(pt.z())); } } }