/// @file bench_boolean_perf.cpp /// @brief 布尔性能基准测试 /// /// 测试不同面数模型的 union / intersect / difference 性能。 /// 结果输出到 stdout,由 CI 汇总后写入 docs/benchmark-report.md #include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/brep_boolean.h" #include #include #include #include #include using namespace vde::brep; using namespace std::chrono; // ── 计时辅助 ── struct BenchmarkResult { std::string name; double time_ms; size_t faces_a; size_t faces_b; size_t faces_result; }; static std::vector g_results; static double measure_ms(std::function fn, int iterations = 3) { double best = 1e18; for (int i = 0; i < iterations; ++i) { auto start = high_resolution_clock::now(); fn(); auto end = high_resolution_clock::now(); double ms = duration_cast(end - start).count() / 1000.0; if (ms < best) best = ms; } return best; } static void record(const std::string& name, double ms, size_t fa, size_t fb, size_t fr) { g_results.push_back({name, ms, fa, fb, fr}); std::cout << " [BENCH] " << std::left << std::setw(40) << name << std::right << std::setw(10) << std::fixed << std::setprecision(2) << ms << " ms" << " (faces: " << fa << " + " << fb << " → " << fr << ")" << std::endl; } // ═══════════════════════════════════════════════ // 布尔并集基准 // ═══════════════════════════════════════════════ TEST(BenchmarkBoolean, Union_SmallModels) { // 小面数:两个低分辨率球体 auto a = make_sphere(1.0, 8, 4); auto b = make_sphere(0.8, 8, 4); double ms = measure_ms([&]() { auto u = brep_union(a, b); (void)u.num_faces(); }, 5); auto result = brep_union(a, b); record("Boolean.Union/Small", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Union_MediumModels) { // 中面数:两个中等细分球体 auto a = make_sphere(2.0, 16, 8); auto b = make_sphere(1.5, 16, 8); double ms = measure_ms([&]() { auto u = brep_union(a, b); (void)u.num_faces(); }, 3); auto result = brep_union(a, b); record("Boolean.Union/Medium", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Union_LargeModels) { // 大面数:两个高细分球体 auto a = make_sphere(3.0, 24, 16); auto b = make_sphere(2.5, 24, 16); double ms = measure_ms([&]() { auto u = brep_union(a, b); (void)u.num_faces(); }, 3); auto result = brep_union(a, b); record("Boolean.Union/Large", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } // ═══════════════════════════════════════════════ // 布尔交集基准 // ═══════════════════════════════════════════════ TEST(BenchmarkBoolean, Intersection_Small) { auto a = make_sphere(1.0, 8, 4); auto b = make_box(1.2, 1.2, 1.2); double ms = measure_ms([&]() { auto i = brep_intersection(a, b); (void)i.num_faces(); }, 5); auto result = brep_intersection(a, b); record("Boolean.Intersection/Small", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Intersection_Medium) { auto a = make_sphere(2.0, 16, 8); auto b = make_cylinder(1.5, 4.0, 32); double ms = measure_ms([&]() { auto i = brep_intersection(a, b); (void)i.num_faces(); }, 3); auto result = brep_intersection(a, b); record("Boolean.Intersection/Medium", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Intersection_Large) { auto a = make_sphere(3.0, 24, 16); auto b = make_cylinder(2.0, 6.0, 64); double ms = measure_ms([&]() { auto i = brep_intersection(a, b); (void)i.num_faces(); }, 3); auto result = brep_intersection(a, b); record("Boolean.Intersection/Large", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } // ═══════════════════════════════════════════════ // 布尔差集基准 // ═══════════════════════════════════════════════ TEST(BenchmarkBoolean, Difference_Small) { auto a = make_box(2.0, 2.0, 2.0); auto b = make_sphere(0.8, 8, 4); double ms = measure_ms([&]() { auto d = brep_difference(a, b); (void)d.num_faces(); }, 5); auto result = brep_difference(a, b); record("Boolean.Difference/Small", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Difference_Medium) { auto a = make_box(4.0, 4.0, 4.0); auto b = make_sphere(1.5, 16, 8); double ms = measure_ms([&]() { auto d = brep_difference(a, b); (void)d.num_faces(); }, 3); auto result = brep_difference(a, b); record("Boolean.Difference/Medium", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); } TEST(BenchmarkBoolean, Difference_Large) { auto a = make_box(6.0, 6.0, 6.0); auto b = make_sphere(2.0, 24, 16); double ms = measure_ms([&]() { auto d = brep_difference(a, b); (void)d.num_faces(); }, 3); auto result = brep_difference(a, b); record("Boolean.Difference/Large", ms, a.num_faces(), b.num_faces(), result.num_faces()); EXPECT_TRUE(result.is_valid()); }