#include #include "vde/brep/tolerance.h" #include "vde/brep/modeling.h" using namespace vde::brep; using namespace vde::core; TEST(ToleranceTest, FuzzyEqual_Exact) { EXPECT_TRUE(fuzzy_equal(1.0, 1.0)); } TEST(ToleranceTest, FuzzyEqual_WithinTol) { EXPECT_TRUE(fuzzy_equal(1.0, 1.0 + 1e-10)); } TEST(ToleranceTest, FuzzyEqual_OutsideTol) { EXPECT_FALSE(fuzzy_equal(1.0, 1.0 + 1e-3, 1e-6)); } TEST(ToleranceTest, FuzzyZero) { EXPECT_TRUE(fuzzy_zero(0.0)); EXPECT_TRUE(fuzzy_zero(1e-10)); EXPECT_FALSE(fuzzy_zero(1e-3, 1e-6)); } TEST(ToleranceTest, FuzzyVec) { Vector3D a(1, 2, 3); Vector3D b(1 + 1e-10, 2, 3 - 1e-10); EXPECT_TRUE(fuzzy_equal_vec(a, b, 1e-8)); } TEST(ToleranceTest, FuzzyPoint) { Point3D a(0, 0, 0); Point3D b(1e-10, 0, 0); EXPECT_TRUE(fuzzy_equal_point(a, b, 1e-8)); } TEST(ToleranceTest, FuzzyParallel) { Vector3D a(1, 0, 0); Vector3D b(1, 1e-11, 0); EXPECT_TRUE(fuzzy_parallel(a, b)); } TEST(ToleranceTest, FuzzyPerpendicular) { Vector3D a(1, 0, 0); Vector3D b(0, 1, 0); EXPECT_TRUE(fuzzy_perpendicular(a, b)); } TEST(ToleranceTest, AdaptiveTolerance) { double t1 = adaptive_tolerance(1.0); // 1mm model double t2 = adaptive_tolerance(1000.0); // 1m model EXPECT_GE(t2, t1); // larger model → larger tolerance } TEST(ToleranceTest, ModelTolerance_Box) { auto box = make_box(100, 100, 100); double t = model_tolerance(box); EXPECT_GT(t, 0.0); } TEST(ToleranceTest, GlobalConfig) { auto& cfg = ToleranceConfig::global(); EXPECT_GT(cfg.vertex_merge, 0.0); ToleranceConfig custom; custom.vertex_merge = 1e-4; ToleranceConfig::set_global(custom); EXPECT_EQ(ToleranceConfig::global().vertex_merge, 1e-4); // Reset ToleranceConfig::set_global(ToleranceConfig{}); } TEST(ToleranceTest, FuzzyGTE) { EXPECT_TRUE(fuzzy_gte(1.0, 1.0 - 1e-10)); EXPECT_TRUE(fuzzy_gte(1.0, 1.0)); EXPECT_FALSE(fuzzy_gte(1.0, 1.1, 1e-6)); } TEST(ToleranceTest, FuzzyLTE) { EXPECT_TRUE(fuzzy_lte(1.0, 1.0 + 1e-10)); EXPECT_TRUE(fuzzy_lte(1.0, 1.0)); EXPECT_FALSE(fuzzy_lte(1.0, 0.9, 1e-6)); } TEST(ToleranceTest, ToleranceConfig_AllDefaultPositive) { ToleranceConfig cfg; EXPECT_GT(cfg.vertex_merge, 0); EXPECT_GT(cfg.edge_merge, 0); EXPECT_GT(cfg.boolean, 0); EXPECT_GT(cfg.angular, 0); } // ── ToleranceChain tests ── TEST(ToleranceChainTest, EmptyChain) { ToleranceChain chain; EXPECT_EQ(chain.depth(), 0u); EXPECT_EQ(chain.cumulative(), 0.0); EXPECT_EQ(chain.max_step(), 0.0); } TEST(ToleranceChainTest, SingleStep) { ToleranceChain chain; chain.push("intersect", 1e-6); EXPECT_EQ(chain.depth(), 1u); EXPECT_DOUBLE_EQ(chain.cumulative(), 1e-6); EXPECT_DOUBLE_EQ(chain.max_step(), 1e-6); } TEST(ToleranceChainTest, MultiStepRSS) { ToleranceChain chain; chain.push("a", 3e-6); chain.push("b", 4e-6); // RSS: sqrt(3² + 4²) * 1e-6 = 5e-6 EXPECT_DOUBLE_EQ(chain.cumulative(), 5e-6); } TEST(ToleranceChainTest, MaxStep) { ToleranceChain chain; chain.push("small", 1e-8); chain.push("large", 1e-4); chain.push("med", 1e-6); EXPECT_DOUBLE_EQ(chain.max_step(), 1e-4); } TEST(ToleranceChainTest, ClearResets) { ToleranceChain chain; chain.push("x", 1e-6); chain.clear(); EXPECT_EQ(chain.depth(), 0u); EXPECT_EQ(chain.cumulative(), 0.0); } TEST(ToleranceChainTest, StepsAccess) { ToleranceChain chain; chain.push("op1", 1e-9); chain.push("op2", 2e-9); auto& steps = chain.steps(); ASSERT_EQ(steps.size(), 2u); EXPECT_EQ(steps[0].first, "op1"); EXPECT_DOUBLE_EQ(steps[0].second, 1e-9); EXPECT_EQ(steps[1].first, "op2"); EXPECT_DOUBLE_EQ(steps[1].second, 2e-9); } TEST(ToleranceChainTest, BooleanChainSimulation) { ToleranceChain chain; chain.push("intersect", 1e-6); chain.push("split", 1e-6); chain.push("classify", 1e-7); chain.push("sew", 1e-5); // Cumulative should be dominated by the sewer step double cum = chain.cumulative(); EXPECT_GT(cum, 1e-5); EXPECT_LT(cum, 1.5e-5); }