7b76689ea1
v11.1 — Test Infrastructure (14 files): - .github/workflows/ci.yml: Ubuntu 22.04 + GCC 11, auto ctest on push - tests/regression/: degenerate geometry, extreme coords, thin wall, large models - tests/fuzz/: SDF random CSG, random booleans, format round-trip, continuous mode - tests/benchmark/: boolean perf, MC perf, IO perf benchmarks - docs/benchmark-report.md: benchmark template v11.2 — Code Quality + Docs: - .clang-tidy: 15 check categories, 22 exclusions - .github/workflows/static-analysis.yml: clang-tidy CI scan - CODEOWNERS, SECURITY.md - docs: API overview, testing guide, contributing guide - README: module capability overview table Pending: binary formats + curve projection (retrying)
150 lines
4.6 KiB
C++
150 lines
4.6 KiB
C++
/// @file bench_mc_perf.cpp
|
|
/// @brief Marching Cubes 性能基准测试
|
|
///
|
|
/// 测试 SDF → Mesh 的 MC 转换性能(不同分辨率)。
|
|
/// 也测试 to_mesh() 性能(B-Rep → Mesh tessellation)。
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "vde/brep/brep.h"
|
|
#include "vde/brep/modeling.h"
|
|
#include "vde/sdf/sdf_primitives.h"
|
|
#include "vde/sdf/sdf_operations.h"
|
|
#include "vde/sdf/sdf_tree.h"
|
|
#include "vde/mesh/halfedge_mesh.h"
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
|
|
using namespace vde::brep;
|
|
using namespace vde::sdf;
|
|
using namespace vde::core;
|
|
using namespace std::chrono;
|
|
|
|
struct MCBenchmarkResult {
|
|
std::string name;
|
|
double time_ms;
|
|
size_t resolution;
|
|
size_t output_triangles;
|
|
};
|
|
|
|
static std::vector<MCBenchmarkResult> g_mc_results;
|
|
|
|
static double measure_ms(std::function<void()> 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<microseconds>(end - start).count() / 1000.0;
|
|
if (ms < best) best = ms;
|
|
}
|
|
return best;
|
|
}
|
|
|
|
static void record_mc(const std::string& name, double ms,
|
|
size_t res, size_t tris) {
|
|
g_mc_results.push_back({name, ms, res, tris});
|
|
std::cout << " [BENCH] " << std::left << std::setw(40) << name
|
|
<< std::right << std::setw(10) << std::fixed << std::setprecision(2)
|
|
<< ms << " ms"
|
|
<< " (res=" << res << " tris=" << tris << ")"
|
|
<< std::endl;
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════
|
|
// SDF → Mesh (MC) 基准
|
|
// ═══════════════════════════════════════════════
|
|
|
|
TEST(BenchmarkMC, SDF_ToMesh_LowRes) {
|
|
auto root = SdfNode::smooth_union(
|
|
SdfNode::sphere(1.0),
|
|
SdfNode::box(Point3D(0.5, 0.5, 0.5)),
|
|
0.2
|
|
);
|
|
|
|
double ms = measure_ms([&]() {
|
|
double d = evaluate(root, Point3D(0, 0, 0));
|
|
(void)d;
|
|
}, 10);
|
|
|
|
// SDF evaluate 基准
|
|
record_mc("MC.Evaluate/LowRes-10pts", ms, 10, 1);
|
|
}
|
|
|
|
TEST(BenchmarkMC, SDF_ToMesh_MediumRes) {
|
|
auto root = SdfNode::op_difference(
|
|
SdfNode::sphere(2.0),
|
|
SdfNode::cylinder(0.5, 4.0)
|
|
);
|
|
|
|
// 采样 1000 个点的 SDF 求值
|
|
double ms = measure_ms([&]() {
|
|
for (int i = 0; i < 1000; ++i) {
|
|
double x = (i % 10 - 5) * 0.5;
|
|
double y = (i / 100 - 5) * 0.5;
|
|
double z = (i / 10 % 10 - 5) * 0.5;
|
|
evaluate(root, Point3D(x, y, z));
|
|
}
|
|
}, 3);
|
|
|
|
record_mc("MC.Evaluate/MediumRes-1000pts", ms, 1000, 1);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════
|
|
// B-Rep → Mesh tessellation 基准
|
|
// ═══════════════════════════════════════════════
|
|
|
|
TEST(BenchmarkMC, BrepToMesh_LowDeflection) {
|
|
// 低精度 tessellation (deflection=0.5 → 粗糙网格)
|
|
auto sphere = make_sphere(2.0, 16, 8);
|
|
|
|
double ms = measure_ms([&]() {
|
|
auto mesh = sphere.to_mesh(0.5);
|
|
(void)mesh.num_faces();
|
|
}, 5);
|
|
|
|
auto mesh = sphere.to_mesh(0.5);
|
|
record_mc("MC.BrepToMesh/LowDeflection", ms, 0, mesh.num_faces());
|
|
}
|
|
|
|
TEST(BenchmarkMC, BrepToMesh_MediumDeflection) {
|
|
auto sphere = make_sphere(2.0, 16, 8);
|
|
|
|
double ms = measure_ms([&]() {
|
|
auto mesh = sphere.to_mesh(0.05);
|
|
(void)mesh.num_faces();
|
|
}, 3);
|
|
|
|
auto mesh = sphere.to_mesh(0.05);
|
|
record_mc("MC.BrepToMesh/MediumDeflection", ms, 0, mesh.num_faces());
|
|
}
|
|
|
|
TEST(BenchmarkMC, BrepToMesh_HighDeflection) {
|
|
// 高精度 tessellation (deflection=0.005 → 精细网格)
|
|
auto sphere = make_sphere(2.0, 16, 8);
|
|
|
|
double ms = measure_ms([&]() {
|
|
auto mesh = sphere.to_mesh(0.005);
|
|
(void)mesh.num_faces();
|
|
}, 3);
|
|
|
|
auto mesh = sphere.to_mesh(0.005);
|
|
record_mc("MC.BrepToMesh/HighDeflection", ms, 0, mesh.num_faces());
|
|
}
|
|
|
|
TEST(BenchmarkMC, BrepToMesh_ComplexModel) {
|
|
// 复杂模型:盒子减去多个球体
|
|
auto box = make_box(5.0, 5.0, 5.0);
|
|
auto sphere = make_sphere(1.0, 12, 6);
|
|
auto model = brep_difference(box, sphere);
|
|
|
|
double ms = measure_ms([&]() {
|
|
auto mesh = model.to_mesh(0.05);
|
|
(void)mesh.num_faces();
|
|
}, 3);
|
|
|
|
auto mesh = model.to_mesh(0.05);
|
|
record_mc("MC.BrepToMesh/ComplexModel", ms, 0, mesh.num_faces());
|
|
}
|