#include #include "vde/brep/assembly.h" #include "vde/brep/modeling.h" using namespace vde::brep; using namespace vde::core; using namespace vde::mesh; // ═══════════════════════════════════════════════ // 已有测试(VDE-022 / Assembly 基础) // ═══════════════════════════════════════════════ TEST(AssemblyTest, CreateEmpty) { Assembly assy("test"); EXPECT_EQ(assy.name, "test"); EXPECT_EQ(assy.part_count(), 0u); } TEST(AssemblyTest, AddPart) { Assembly assy("test"); auto box = make_box(2, 2, 2); assy.root.add_part("box1", box); EXPECT_EQ(assy.part_count(), 1u); EXPECT_EQ(assy.node_count(), 2u); // root + box } TEST(AssemblyTest, NestedHierarchy) { Assembly assy("robot"); assy.root.add_part("base", make_box(10, 5, 2)); auto* arm = assy.root.add_subassembly("arm"); arm->add_part("seg1", make_cylinder(1, 8)); arm->add_part("seg2", make_cylinder(1, 6)); EXPECT_EQ(assy.part_count(), 3u); EXPECT_EQ(assy.node_count(), 5u); // root + arm + seg1 + seg2 } TEST(AssemblyTest, VisitPartsWithTransform) { Assembly assy("test"); assy.root.add_part("p1", make_box(1, 1, 1)); size_t visited = 0; assy.visit_parts([&visited](const std::string& name, const BrepModel&, const Transform3D& xform) { EXPECT_EQ(name, "p1"); EXPECT_TRUE(xform.isApprox(Transform3D::Identity())); visited++; }); EXPECT_EQ(visited, 1u); } // ═══════════════════════════════════════════════ // VDE-025: MeshData→Assembly 批量构建 API 测试 // ═══════════════════════════════════════════════ /// 辅助:创建一个简单的三角网格(四面体) static HalfedgeMesh make_tetrahedron_mesh() { HalfedgeMesh mesh; // 四面体顶点 int v0 = mesh.add_vertex(Point3D(0, 0, 0)); int v1 = mesh.add_vertex(Point3D(1, 0, 0)); int v2 = mesh.add_vertex(Point3D(0.5, 0.866, 0)); int v3 = mesh.add_vertex(Point3D(0.5, 0.289, 0.816)); // 四个三角面 mesh.add_face({v0, v1, v2}); // 底面 mesh.add_face({v0, v3, v1}); mesh.add_face({v1, v3, v2}); mesh.add_face({v2, v3, v0}); return mesh; } /// 辅助:创建一个简单的四边形三角网格(两个三角形组成正方形) static HalfedgeMesh make_square_mesh() { HalfedgeMesh mesh; int v0 = mesh.add_vertex(Point3D(0, 0, 0)); int v1 = mesh.add_vertex(Point3D(1, 0, 0)); int v2 = mesh.add_vertex(Point3D(1, 1, 0)); int v3 = mesh.add_vertex(Point3D(0, 1, 0)); mesh.add_face({v0, v1, v2}); mesh.add_face({v0, v2, v3}); return mesh; } // ── Test 1: mesh_to_brep_model 基本转换 ── TEST(AssemblyMeshTest, MeshToBrepModelBasic) { auto mesh = make_square_mesh(); BrepModel model = mesh_to_brep_model(mesh); EXPECT_EQ(model.num_faces(), 2u); EXPECT_GT(model.num_vertices(), 0u); EXPECT_GT(model.num_edges(), 0u); EXPECT_EQ(model.num_bodies(), 1u); EXPECT_TRUE(model.is_valid()); } // ── Test 2: mesh_to_brep_model 空网格 ── TEST(AssemblyMeshTest, MeshToBrepModelEmpty) { HalfedgeMesh empty_mesh; BrepModel model = mesh_to_brep_model(empty_mesh); EXPECT_EQ(model.num_faces(), 0u); EXPECT_EQ(model.num_vertices(), 0u); EXPECT_EQ(model.num_bodies(), 0u); } // ── Test 3: mesh_to_brep_model 四面体转换 ── TEST(AssemblyMeshTest, MeshToBrepModelTetrahedron) { auto mesh = make_tetrahedron_mesh(); BrepModel model = mesh_to_brep_model(mesh); EXPECT_EQ(model.num_faces(), 4u); EXPECT_EQ(model.num_bodies(), 1u); // 验证包围盒合理 auto bb = model.bounds(); EXPECT_GT(bb.extent().norm(), 0.0); } // ── Test 4: build_assembly_from_meshes 单零件 ── TEST(AssemblyMeshTest, BuildAssemblySinglePart) { auto mesh = make_square_mesh(); std::vector inputs = { {"plate", mesh, Transform3D::Identity()} }; Assembly assy = build_assembly_from_meshes(inputs); EXPECT_EQ(assy.name, "mesh_assembly"); EXPECT_EQ(assy.part_count(), 1u); EXPECT_EQ(assy.node_count(), 2u); // root + plate } // ── Test 5: build_assembly_from_meshes 多零件带变换 ── TEST(AssemblyMeshTest, BuildAssemblyMultiPartWithTransform) { auto mesh1 = make_square_mesh(); auto mesh2 = make_tetrahedron_mesh(); std::vector inputs = { {"base", mesh1, Transform3D::Identity()}, {"top", mesh2, translate(0, 0, 2)} }; Assembly assy = build_assembly_from_meshes(inputs); EXPECT_EQ(assy.part_count(), 2u); EXPECT_EQ(assy.node_count(), 3u); // root + base + top // 验证变换被正确传递 size_t visited = 0; assy.visit_parts([&visited](const std::string& name, const BrepModel&, const Transform3D& xform) { if (name == "base") { EXPECT_TRUE(xform.isApprox(Transform3D::Identity())); } else if (name == "top") { EXPECT_NEAR(xform.translation().z(), 2.0, 1e-9); } visited++; }); EXPECT_EQ(visited, 2u); } // ── Test 6: build_assembly_from_meshes 空输入 ── TEST(AssemblyMeshTest, BuildAssemblyEmptyInput) { std::vector inputs; Assembly assy = build_assembly_from_meshes(inputs); EXPECT_EQ(assy.name, "mesh_assembly"); EXPECT_EQ(assy.part_count(), 0u); EXPECT_EQ(assy.node_count(), 1u); // only root } // ── Test 7: build_assembly_from_meshes 批量构建后模型可序列化验证 ── TEST(AssemblyMeshTest, BuildAssemblyLargeBatch) { constexpr size_t N = 20; std::vector inputs; inputs.reserve(N); for (size_t i = 0; i < N; ++i) { auto mesh = make_square_mesh(); inputs.push_back({ "part_" + std::to_string(i), mesh, translate(static_cast(i), 0, 0) }); } Assembly assy = build_assembly_from_meshes(inputs); EXPECT_EQ(assy.part_count(), N); EXPECT_EQ(assy.node_count(), N + 1); // root + N parts // 验证每个零件都有有效的模型 assy.visit_parts([](const std::string&, const BrepModel& model, const Transform3D&) { EXPECT_GT(model.num_faces(), 0u); EXPECT_TRUE(model.is_valid()); }); }