Files
ViewDesignEngine/tests/brep/test_gdt.cpp
T

266 lines
9.9 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include "vde/brep/gdt.h"
#include "vde/brep/modeling.h"
#include <cmath>
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<GDTType> 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<int>(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<GDTAnnotation> 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<GDTAnnotation> 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(""), 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);
}