#include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/measure.h" #include "vde/brep/assembly.h" #include using namespace vde::brep; using namespace vde::core; // ═══════════════════════════════════════════════════════════ // Volume measurements // ═══════════════════════════════════════════════════════════ TEST(MeasureTest, Volume_UnitBox) { auto box = make_box(2, 2, 2); double vol = volume(box); EXPECT_NEAR(vol, 8.0, 0.2); } TEST(MeasureTest, Volume_LargeBox) { auto box = make_box(10, 5, 3); double vol = volume(box); EXPECT_NEAR(vol, 150.0, 1.0); } // ═══════════════════════════════════════════════════════════ // Surface area measurements // ═══════════════════════════════════════════════════════════ TEST(MeasureTest, SurfaceArea_UnitBox) { auto box = make_box(2, 2, 2); double area = surface_area(box); EXPECT_NEAR(area, 24.0, 0.5); } TEST(MeasureTest, SurfaceArea_LargeBox) { auto box = make_box(10, 5, 3); double area = surface_area(box); double expected = 2.0 * (10*5 + 10*3 + 5*3); EXPECT_NEAR(area, expected, 2.0); } // ═══════════════════════════════════════════════════════════ // Centroid measurements // ═══════════════════════════════════════════════════════════ TEST(MeasureTest, Centroid_BoxAtOrigin) { auto box = make_box(2, 2, 2); auto c = centroid(box); EXPECT_NEAR(c.x(), 0.0, 0.01); EXPECT_NEAR(c.y(), 0.0, 0.01); EXPECT_NEAR(c.z(), 0.0, 0.01); } // ═══════════════════════════════════════════════════════════ // Distance measurements // ═══════════════════════════════════════════════════════════ TEST(MeasureTest, Distance_SeparatedBoxes) { auto box1 = make_box(1, 1, 1); auto box2 = make_box(1, 1, 1); double d = distance(box1, box2); EXPECT_NEAR(d, 0.0, 0.1); } TEST(MeasureTest, Distance_OverlappingBoxes) { auto box1 = make_box(2, 2, 2); auto box2 = make_box(2, 2, 2); double d = distance(box1, box2); EXPECT_NEAR(d, 0.0, 0.1); } TEST(MeasureTest, Volume_NonNegative) { auto box = make_box(2, 2, 2); EXPECT_GE(volume(box), 0.0); } TEST(MeasureTest, SurfaceArea_NonNegative) { auto box = make_box(2, 2, 2); EXPECT_GE(surface_area(box), 0.0); } TEST(MeasureTest, Distance_NonNegative) { auto box1 = make_box(1, 1, 1); auto box2 = make_box(1, 1, 1); EXPECT_GE(distance(box1, box2), 0.0); } // ═══════════════════════════════════════════════════════════ // Mass properties // ═══════════════════════════════════════════════════════════ TEST(MassPropertiesTest, Box_Volume) { auto box = make_box(2, 2, 2); auto mp = mass_properties(box); EXPECT_NEAR(mp.volume, 8.0, 1.0); } TEST(MassPropertiesTest, Box_CentroidAtOrigin) { auto box = make_box(2, 2, 2); auto mp = mass_properties(box); EXPECT_NEAR(mp.centroid.x(), 0.0, 0.3); EXPECT_NEAR(mp.centroid.y(), 0.0, 0.3); EXPECT_NEAR(mp.centroid.z(), 0.0, 0.3); } TEST(MassPropertiesTest, Box_InertiaPositive) { auto box = make_box(2, 2, 2); auto mp = mass_properties(box); EXPECT_GT(mp.inertia(0,0), 0.0); EXPECT_GT(mp.inertia(1,1), 0.0); EXPECT_GT(mp.inertia(2,2), 0.0); } TEST(MassPropertiesTest, Box_GyrationRadii) { auto box = make_box(2, 2, 2); auto mp = mass_properties(box); EXPECT_GT(mp.gyration_radii.x(), 0.0); EXPECT_GT(mp.gyration_radii.y(), 0.0); EXPECT_GT(mp.gyration_radii.z(), 0.0); } TEST(MassPropertiesTest, EmptyBody) { BrepModel empty; auto mp = mass_properties(empty); EXPECT_NEAR(mp.volume, 0.0, 1e-10); } // ═══════════════════════════════════════════════════════════ // Clearance (gap analysis) // ═══════════════════════════════════════════════════════════ TEST(ClearanceTest, SeparatedBoxes) { auto box1 = make_box(1, 1, 1); auto box2 = make_box(1, 1, 1); double c = clearance(box1, box2); EXPECT_GE(c, 0.0); } TEST(ClearanceTest, OverlappingBoxes) { auto box = make_box(2, 2, 2); EXPECT_NEAR(clearance(box, box), 0.0, 1e-6); } // ═══════════════════════════════════════════════════════════ // Assembly mass properties // ═══════════════════════════════════════════════════════════ TEST(AssemblyMassTest, SinglePart) { Assembly assy("test"); assy.root.add_part("box", make_box(2, 2, 2)); auto mp = assembly_mass_properties(assy.root); EXPECT_NEAR(mp.volume, 8.0, 1.0); } TEST(AssemblyMassTest, TwoPartsCombined) { Assembly assy("test"); assy.root.add_part("box1", make_box(2, 2, 2)); assy.root.add_part("box2", make_box(2, 2, 2)); auto mp = assembly_mass_properties(assy.root); EXPECT_NEAR(mp.volume, 16.0, 2.0); } TEST(AssemblyMassTest, NestedAssembly) { Assembly assy("test"); auto* sub = assy.root.add_subassembly("sub"); sub->add_part("box", make_box(2, 2, 2)); assy.root.add_part("box2", make_box(2, 2, 2)); auto mp = assembly_mass_properties(assy.root); EXPECT_NEAR(mp.volume, 16.0, 2.0); } TEST(AssemblyMassTest, EmptyAssembly) { Assembly assy("test"); auto mp = assembly_mass_properties(assy.root); EXPECT_NEAR(mp.volume, 0.0, 1e-10); } // ═══════════════════════════════════════════════════════════ // BOM (Bill of Materials) // ═══════════════════════════════════════════════════════════ TEST(BomTest, SinglePart) { Assembly assy("test"); assy.root.add_part("bracket", make_box(2, 2, 2)); auto bom = generate_bom(assy.root); ASSERT_EQ(bom.size(), 1u); EXPECT_EQ(bom[0].name, "bracket"); EXPECT_EQ(bom[0].quantity, 1); } TEST(BomTest, MultipleSameParts) { Assembly assy("test"); assy.root.add_part("bolt", make_box(1, 1, 1)); assy.root.add_part("bolt", make_box(1, 1, 1)); assy.root.add_part("bolt", make_box(1, 1, 1)); auto bom = generate_bom(assy.root); ASSERT_EQ(bom.size(), 1u); EXPECT_EQ(bom[0].quantity, 3); } TEST(BomTest, DifferentParts) { Assembly assy("test"); assy.root.add_part("base", make_box(4, 4, 1)); assy.root.add_part("pillar", make_cylinder(1, 8)); assy.root.add_part("top", make_box(4, 4, 1)); auto bom = generate_bom(assy.root); ASSERT_EQ(bom.size(), 3u); } TEST(BomTest, NestedBom) { Assembly assy("test"); auto* sub = assy.root.add_subassembly("sub_assy"); sub->add_part("pin", make_cylinder(0.5, 2)); sub->add_part("pin", make_cylinder(0.5, 2)); assy.root.add_part("frame", make_box(5, 5, 1)); auto bom = generate_bom(assy.root); EXPECT_GE(bom.size(), 2u); } TEST(BomTest, EmptyAssembly) { Assembly assy("test"); auto bom = generate_bom(assy.root); EXPECT_TRUE(bom.empty()); } // ═══════════════════════════════════════════════════════════ // Wall thickness analysis // ═══════════════════════════════════════════════════════════ TEST(WallThicknessTest, Box) { auto box = make_box(4, 4, 4); // 4×4×4 box auto result = analyze_wall_thickness(box, 3); // For a 4×4×4 box, wall thickness ~4.0 (opposite face distance) EXPECT_GT(result.min_thickness, 0.0); EXPECT_GT(result.max_thickness, 0.0); EXPECT_GT(result.avg_thickness, 0.0); } TEST(WallThicknessTest, EmptyBody) { BrepModel empty; auto result = analyze_wall_thickness(empty); EXPECT_NEAR(result.min_thickness, 0.0, 1e-10); } TEST(WallThicknessTest, ThinWallDetection) { // 4×4×0.5 thin plate auto plate = make_box(4, 4, 0.5); auto result = analyze_wall_thickness(plate, 3); EXPECT_GT(result.min_thickness, 0.0); EXPECT_LT(result.min_thickness, 1.0); // thin }