#include #include "vde/brep/gdt.h" #include "vde/brep/modeling.h" #include using namespace vde::brep; using namespace vde::core; // ═══════════════════════════════════════════════════════════ // GDTFeature — symbol and string // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Symbol_FlatnessNotEmpty) { GDTFeature f; f.type = GDTType::Flatness; EXPECT_FALSE(f.symbol().empty()); } TEST(GDTTest, Symbol_AllTypesNonEmpty) { std::vector types = { GDTType::Flatness, GDTType::Straightness, GDTType::Circularity, GDTType::Cylindricity, GDTType::Parallelism, GDTType::Perpendicularity, GDTType::Angularity, GDTType::Position, GDTType::Concentricity, GDTType::Symmetry, GDTType::ProfileOfLine, GDTType::ProfileOfSurface, GDTType::CircularRunout, GDTType::TotalRunout }; for (auto t : types) { GDTFeature f; f.type = t; EXPECT_FALSE(f.symbol().empty()) << "Type " << static_cast(t); } } TEST(GDTTest, ToString_ContainsTolerance) { GDTFeature f; f.type = GDTType::Position; f.tolerance_value = 0.05; f.zone_shape = GDTFeature::ZoneShape::Cylindrical; auto s = f.to_string(); EXPECT_NE(s.find("0.05"), std::string::npos); EXPECT_NE(s.find("Ø"), std::string::npos); } TEST(GDTTest, ToString_MMCModifier) { GDTFeature f; f.type = GDTType::Position; f.tolerance_value = 0.1; f.mmc = true; auto s = f.to_string(); EXPECT_NE(s.find("M"), std::string::npos); } TEST(GDTTest, ToString_DatumReferences) { GDTFeature f; f.type = GDTType::Parallelism; f.tolerance_value = 0.02; f.datums.push_back({"A", 0, true}); auto s = f.to_string(); EXPECT_NE(s.find("A"), std::string::npos); } TEST(GDTTest, ToString_ProjectedTolerance) { GDTFeature f; f.type = GDTType::Position; f.tolerance_value = 0.1; f.projected = true; f.projected_height = 15.0; auto s = f.to_string(); EXPECT_NE(s.find("P"), std::string::npos); } // ═══════════════════════════════════════════════════════════ // Flatness // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Flatness_BoxFace_ReturnsNonNegative) { auto box = make_box(10, 10, 10); double flatness = compute_flatness(box, 0); EXPECT_GE(flatness, 0.0); // A flat box face should have very low flatness EXPECT_LT(flatness, 0.1); } TEST(GDTTest, Flatness_CylinderEnd_ReturnsNonNegative) { auto cyl = make_cylinder(3.0, 10.0); double flatness = compute_flatness(cyl, 0); // bottom face EXPECT_GE(flatness, 0.0); } // ═══════════════════════════════════════════════════════════ // Parallelism // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Parallelism_ParallelFaces_LowDeviation) { auto box = make_box(5, 5, 10); // 5×5×10, Z is long axis // Face 0 (z=-5) and Face 1 (z=+5) should be parallel double dev = compute_parallelism(box, 0, 1); EXPECT_GE(dev, 0.0); EXPECT_LT(dev, 0.1); } // ═══════════════════════════════════════════════════════════ // Perpendicularity // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Perpendicularity_PerpendicularFaces_LowDeviation) { auto box = make_box(5, 5, 10); // Face 0 (z=-5) and Face 2 (y=-5) should be perpendicular double dev = compute_perpendicularity(box, 0, 2); EXPECT_GE(dev, 0.0); EXPECT_LT(dev, 0.1); } // ═══════════════════════════════════════════════════════════ // Concentricity // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Concentricity_CoaxialCylinders_LowDeviation) { auto cyl = make_cylinder(3.0, 10.0); // Bottom and top faces should be concentric double dev = compute_concentricity(cyl, 0, 1); EXPECT_GE(dev, 0.0); EXPECT_LT(dev, 0.1); } // ═══════════════════════════════════════════════════════════ // Position // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Position_BoxFace_ReturnsNonNegative) { auto box = make_box(10, 10, 10); double dev = compute_position(box, 0, Point3D(0, 0, -5)); EXPECT_GE(dev, 0.0); } // ═══════════════════════════════════════════════════════════ // validate_gdt // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Validate_Flatness_PassesLargeTolerance) { auto box = make_box(10, 10, 10); GDTFeature f; f.type = GDTType::Flatness; f.target_face_id = 0; f.tolerance_value = 1.0; // very loose tolerance auto result = validate_gdt(box, f); EXPECT_TRUE(result.pass); EXPECT_FALSE(result.description.empty()); } TEST(GDTTest, Validate_Flatness_FailsTightTolerance) { auto box = make_box(100, 100, 100); GDTFeature f; f.type = GDTType::Flatness; f.target_face_id = 0; f.tolerance_value = 1e-9; // impossibly tight auto result = validate_gdt(box, f); // Large face sampled from polygon may have slight deviation // Just verify it runs without error EXPECT_GE(result.actual_deviation, 0.0); } TEST(GDTTest, Validate_Parallelism_DatumRequired) { auto box = make_box(5, 5, 10); GDTFeature f; f.type = GDTType::Parallelism; f.target_face_id = 0; f.datums.push_back({"A", 1, true}); f.tolerance_value = 0.5; auto result = validate_gdt(box, f); EXPECT_GE(result.actual_deviation, 0.0); } TEST(GDTTest, Validate_Concentricity) { auto cyl = make_cylinder(3.0, 10.0); GDTFeature f; f.type = GDTType::Concentricity; f.target_face_id = 0; f.datums.push_back({"A", 1, true}); f.tolerance_value = 1.0; auto result = validate_gdt(cyl, f); EXPECT_GE(result.actual_deviation, 0.0); } TEST(GDTTest, Validate_Position) { auto box = make_box(10, 10, 10); GDTFeature f; f.type = GDTType::Position; f.target_face_id = 0; f.tolerance_value = 5.0; auto result = validate_gdt(box, f); EXPECT_GE(result.actual_deviation, 0.0); } // ═══════════════════════════════════════════════════════════ // DXF export // ═══════════════════════════════════════════════════════════ TEST(GDTTest, ExportDxf_ProducesValidSections) { std::vector annotations; GDTAnnotation ann; ann.feature.type = GDTType::Flatness; ann.feature.tolerance_value = 0.1; ann.frame_position = Point3D(10, 20, 0); ann.leader_point = Point3D(15, 25, 0); annotations.push_back(ann); auto dxf = export_gdt_annotations_dxf(annotations); EXPECT_NE(dxf.find("SECTION"), std::string::npos); EXPECT_NE(dxf.find("ENTITIES"), std::string::npos); EXPECT_NE(dxf.find("MTEXT"), std::string::npos); EXPECT_NE(dxf.find("EOF"), std::string::npos); } TEST(GDTTest, ExportDxf_EmptyAnnotations_ProducesStructure) { std::vector empty; auto dxf = export_gdt_annotations_dxf(empty); EXPECT_NE(dxf.find("EOF"), std::string::npos); } // ═══════════════════════════════════════════════════════════ // GDTAnnotation // ═══════════════════════════════════════════════════════════ TEST(GDTTest, Annotation_DxfText_ContainsPosition) { GDTAnnotation ann; ann.feature.type = GDTType::Flatness; ann.feature.tolerance_value = 0.05; ann.frame_position = Point3D(10, 20, 0); ann.leader_point = Point3D(15, 25, 0); ann.view_name = "TOP"; auto text = ann.to_dxf_text(); EXPECT_NE(text.find("10"), std::string::npos); EXPECT_NE(text.find("20"), std::string::npos); } TEST(GDTTest, Feature_ZoneShapeToString) { GDTFeature f; f.type = GDTType::Position; f.tolerance_value = 0.1; f.zone_shape = GDTFeature::ZoneShape::Spherical; auto s = f.to_string(); EXPECT_NE(s.find("SØ"), std::string::npos); } TEST(GDTTest, Feature_LMCModifier) { GDTFeature f; f.type = GDTType::Position; f.tolerance_value = 0.1; f.lmc = true; auto s = f.to_string(); EXPECT_NE(s.find("L"), std::string::npos); }