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)
189 lines
6.5 KiB
C++
189 lines
6.5 KiB
C++
/// @file regression_large_model.cpp
|
||
/// @brief 大面数回归测试(1000+ 面模型)
|
||
///
|
||
/// 覆盖场景:
|
||
/// 1. 通过高细分球体/圆柱产生 1000+ 面的模型
|
||
/// 2. 大面数模型的布尔运算
|
||
/// 3. 大面数模型的验证(validate)
|
||
/// 4. 大面数模型的修复
|
||
///
|
||
/// 每个测试:构造大面数体 → 布尔/修复/验证 → 断言不崩溃
|
||
|
||
#include <gtest/gtest.h>
|
||
#include "vde/brep/brep.h"
|
||
#include "vde/brep/modeling.h"
|
||
#include "vde/brep/brep_boolean.h"
|
||
#include "vde/brep/brep_validate.h"
|
||
#include "vde/brep/brep_heal.h"
|
||
#include "vde/core/point.h"
|
||
#include <cmath>
|
||
|
||
using namespace vde::brep;
|
||
using namespace vde::core;
|
||
|
||
/// 生成一个高面数的球体
|
||
/// seg_u × seg_v 段 → 大约 2 * seg_u * seg_v 个面
|
||
/// 例如 seg_u=50, seg_v=50 → 约 5000 面
|
||
static BrepModel make_highres_sphere(double radius, int seg_u, int seg_v) {
|
||
return make_sphere(radius, seg_u, seg_v);
|
||
}
|
||
|
||
/// 生成一个高面数的圆柱体
|
||
/// segments 段 → 侧面有 segments * 1 个面,加上顶/底面
|
||
static BrepModel make_highres_cylinder(double radius, double height, int segments) {
|
||
return make_cylinder(radius, height, segments);
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 1000+ 面模型 - 球体
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Sphere_1000PlusFaces) {
|
||
// seg_u=25, seg_v=20 → 2*25*20 = 1000 faces
|
||
EXPECT_NO_THROW({
|
||
auto sphere = make_sphere(10.0, 25, 20);
|
||
EXPECT_TRUE(sphere.is_valid());
|
||
EXPECT_GE(sphere.num_faces(), 800u); // 至少 800 面
|
||
|
||
// 验证
|
||
auto result = validate(sphere);
|
||
(void)result;
|
||
|
||
// 导出网格
|
||
auto mesh = sphere.to_mesh(0.05);
|
||
(void)mesh;
|
||
});
|
||
}
|
||
|
||
TEST(RegressionLargeModel, Sphere_5000PlusFaces) {
|
||
// seg_u=55, seg_v=50 → 2*55*50 = 5500 faces
|
||
EXPECT_NO_THROW({
|
||
auto sphere = make_sphere(5.0, 55, 50);
|
||
EXPECT_TRUE(sphere.is_valid());
|
||
EXPECT_GE(sphere.num_faces(), 4000u);
|
||
|
||
auto result = validate(sphere);
|
||
(void)result;
|
||
|
||
auto mesh = sphere.to_mesh(0.01);
|
||
(void)mesh;
|
||
});
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 1000+ 面模型 - 圆柱体
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Cylinder_1000PlusFaces) {
|
||
// segments=1000 → 侧面有很多面
|
||
EXPECT_NO_THROW({
|
||
auto cyl = make_cylinder(5.0, 10.0, 1000);
|
||
EXPECT_TRUE(cyl.is_valid());
|
||
// seg=1000 时侧面有 1000 个面 + 上下各 1(或更多)面
|
||
EXPECT_GE(cyl.num_faces(), 900u);
|
||
|
||
auto result = validate(cyl);
|
||
(void)result;
|
||
|
||
auto mesh = cyl.to_mesh();
|
||
(void)mesh;
|
||
});
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 大面数模型布尔运算
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Boolean_LargeSphereUnion) {
|
||
auto s1 = make_sphere(5.0, 30, 24); // ~1440 faces
|
||
auto s2 = make_sphere(3.0, 20, 16); // ~640 faces
|
||
|
||
EXPECT_NO_THROW({
|
||
auto u = brep_union(s1, s2);
|
||
EXPECT_TRUE(u.is_valid());
|
||
auto result = validate(u);
|
||
(void)result;
|
||
});
|
||
}
|
||
|
||
TEST(RegressionLargeModel, Boolean_LargeSphereIntersection) {
|
||
auto s1 = make_sphere(5.0, 30, 24);
|
||
auto s2 = make_sphere(3.0, 24, 20);
|
||
|
||
EXPECT_NO_THROW({
|
||
auto i = brep_intersection(s1, s2);
|
||
EXPECT_TRUE(i.is_valid());
|
||
});
|
||
}
|
||
|
||
TEST(RegressionLargeModel, Boolean_LargeCylinders) {
|
||
// 高分辨率圆柱布尔运算
|
||
auto c1 = make_cylinder(3.0, 10.0, 500);
|
||
auto c2 = make_cylinder(2.0, 8.0, 300);
|
||
|
||
EXPECT_NO_THROW({
|
||
auto u = brep_union(c1, c2);
|
||
EXPECT_TRUE(u.is_valid());
|
||
auto d = brep_difference(c1, c2);
|
||
EXPECT_TRUE(d.is_valid());
|
||
});
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 大面数模型修复
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Heal_LargeModel) {
|
||
auto sphere = make_sphere(10.0, 30, 24);
|
||
EXPECT_GE(sphere.num_faces(), 1000u);
|
||
|
||
EXPECT_NO_THROW({
|
||
// 修复大面数模型
|
||
heal_gaps(sphere, 1e-6);
|
||
heal_slivers(sphere);
|
||
bool ok = heal_topology(sphere, 1e-4);
|
||
(void)ok;
|
||
});
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 多体布尔链式操作(压力测试)
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Stress_ChainedBooleans) {
|
||
auto box = make_box(10.0, 10.0, 10.0);
|
||
auto cyl = make_cylinder(0.5, 15.0, 128);
|
||
|
||
// 连续执行多次布尔运算,最终模型可能包含大量面
|
||
EXPECT_NO_THROW({
|
||
auto u = brep_union(box, cyl);
|
||
for (int i = 0; i < 3; ++i) {
|
||
auto d = brep_difference(u, make_sphere(0.3 + i * 0.1, 16, 8));
|
||
u = d; // chain
|
||
}
|
||
EXPECT_TRUE(u.is_valid());
|
||
|
||
auto result = validate(u);
|
||
(void)result;
|
||
|
||
auto mesh = u.to_mesh(0.05);
|
||
(void)mesh;
|
||
});
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 大面数模型导出
|
||
// ═══════════════════════════════════════════════
|
||
|
||
TEST(RegressionLargeModel, Export_LargeMesh) {
|
||
auto sphere = make_sphere(10.0, 40, 32); // ~2560 faces
|
||
EXPECT_GE(sphere.num_faces(), 2000u);
|
||
|
||
EXPECT_NO_THROW({
|
||
// 导出为精细网格
|
||
auto mesh = sphere.to_mesh(0.001);
|
||
(void)mesh.num_vertices();
|
||
(void)mesh.num_faces();
|
||
});
|
||
}
|