226 lines
5.7 KiB
C++
226 lines
5.7 KiB
C++
|
|
/// @file regression_extreme.cpp
|
|||
|
|
/// @brief 极端坐标回归测试
|
|||
|
|
///
|
|||
|
|
/// 覆盖场景:
|
|||
|
|
/// 1. 极小坐标(1e-15)
|
|||
|
|
/// 2. 极大坐标(1e15)
|
|||
|
|
/// 3. NaN 输入
|
|||
|
|
/// 4. Inf 输入
|
|||
|
|
///
|
|||
|
|
/// 每个测试:构造极端体 → 布尔/修复/验证 → 断言不崩溃
|
|||
|
|
|
|||
|
|
#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>
|
|||
|
|
#include <limits>
|
|||
|
|
|
|||
|
|
using namespace vde::brep;
|
|||
|
|
using namespace vde::core;
|
|||
|
|
|
|||
|
|
// ── 极小坐标测试 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, TinyCoordinates_1eMinus15) {
|
|||
|
|
// 极小的盒子:尺寸为 1e-15
|
|||
|
|
double s = 1e-15;
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto tiny = make_box(s, s, s);
|
|||
|
|
// 验证合法性
|
|||
|
|
EXPECT_TRUE(tiny.is_valid());
|
|||
|
|
|
|||
|
|
// 布尔运算:与正常盒子
|
|||
|
|
auto box = make_box(1.0, 1.0, 1.0);
|
|||
|
|
auto u = brep_union(tiny, box);
|
|||
|
|
EXPECT_TRUE(u.is_valid());
|
|||
|
|
auto i = brep_intersection(tiny, box);
|
|||
|
|
EXPECT_TRUE(i.is_valid());
|
|||
|
|
|
|||
|
|
// 导出网格
|
|||
|
|
auto mesh = tiny.to_mesh();
|
|||
|
|
(void)mesh;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, TinyCoordinates_1eMinus10) {
|
|||
|
|
double s = 1e-10;
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto tiny = make_box(s, s, s);
|
|||
|
|
EXPECT_TRUE(tiny.is_valid());
|
|||
|
|
auto mesh = tiny.to_mesh();
|
|||
|
|
(void)mesh;
|
|||
|
|
|
|||
|
|
// 修复流水线
|
|||
|
|
BrepModel copy = tiny;
|
|||
|
|
heal_topology(copy, s * 0.1);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, TinyCoordinates_Mixed) {
|
|||
|
|
// 一个维度极小,其他正常
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto thin = make_box(1e-15, 1.0, 1.0);
|
|||
|
|
EXPECT_NO_THROW({ thin.is_valid(); });
|
|||
|
|
auto result = validate(thin);
|
|||
|
|
(void)result;
|
|||
|
|
|
|||
|
|
auto mesh = thin.to_mesh();
|
|||
|
|
(void)mesh;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── 极大坐标测试 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, HugeCoordinates_1e15) {
|
|||
|
|
double s = 1e15;
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto huge = make_box(s, s, s);
|
|||
|
|
// 基本验证不崩溃
|
|||
|
|
EXPECT_TRUE(huge.is_valid());
|
|||
|
|
|
|||
|
|
// 包围盒计算
|
|||
|
|
auto bb = huge.bounds();
|
|||
|
|
EXPECT_TRUE(std::isfinite(bb.min().x()));
|
|||
|
|
EXPECT_TRUE(std::isfinite(bb.max().x()));
|
|||
|
|
|
|||
|
|
// 布尔自交
|
|||
|
|
auto u = brep_union(huge, huge);
|
|||
|
|
EXPECT_TRUE(u.is_valid());
|
|||
|
|
|
|||
|
|
// 网格导出(大尺寸模型)
|
|||
|
|
auto mesh = huge.to_mesh(0.01 * s);
|
|||
|
|
(void)mesh;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, HugeVsTiny) {
|
|||
|
|
// 巨大体与极小体的布尔
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto huge = make_box(1e12, 1e12, 1e12);
|
|||
|
|
auto tiny = make_box(1e-12, 1e-12, 1e-12);
|
|||
|
|
|
|||
|
|
auto u = brep_union(huge, tiny);
|
|||
|
|
EXPECT_TRUE(u.is_valid());
|
|||
|
|
auto i = brep_intersection(huge, tiny);
|
|||
|
|
EXPECT_TRUE(i.is_valid());
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── NaN 输入测试 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, NaN_Handling) {
|
|||
|
|
double nan = std::numeric_limits<double>::quiet_NaN();
|
|||
|
|
|
|||
|
|
// make_box 应对 NaN 表现得优雅(返回无效体或抛出,但绝不能崩溃)
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(nan, 1.0, 1.0);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(1.0, nan, 1.0);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(1.0, 1.0, nan);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(nan, nan, nan);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, NaN_BooleanResilience) {
|
|||
|
|
// 若 NaN 产生了有效的 body,检查布尔运算不崩溃
|
|||
|
|
auto good = make_box(2.0, 2.0, 2.0);
|
|||
|
|
|
|||
|
|
// 将所有尝试包裹在 EXPECT_NO_THROW 中
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
try {
|
|||
|
|
auto bad = make_box(std::numeric_limits<double>::quiet_NaN(), 1.0, 1.0);
|
|||
|
|
auto u = brep_union(good, bad);
|
|||
|
|
(void)u;
|
|||
|
|
} catch (...) {
|
|||
|
|
// 允许抛异常但不应崩溃
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── Inf 输入测试 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, Inf_Handling) {
|
|||
|
|
double inf = std::numeric_limits<double>::infinity();
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(inf, 1.0, 1.0);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(1.0, inf, 1.0);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(1.0, 1.0, inf);
|
|||
|
|
(void)body;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── 极大值 vs 极小值布尔 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, MaxDouble_Boolean) {
|
|||
|
|
double big = 1e100;
|
|||
|
|
double small = 1e-100;
|
|||
|
|
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto a = make_box(big, 1.0, 1.0);
|
|||
|
|
auto b = make_box(small, 1.0, 1.0);
|
|||
|
|
auto u = brep_union(a, b);
|
|||
|
|
(void)u.is_valid();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── 边界值批处理 ──
|
|||
|
|
|
|||
|
|
TEST(RegressionExtreme, BoundaryValuesBatch) {
|
|||
|
|
// 一系列边界值,确保每个都不会崩溃
|
|||
|
|
double values[] = {
|
|||
|
|
0.0,
|
|||
|
|
std::numeric_limits<double>::min(),
|
|||
|
|
std::numeric_limits<double>::denorm_min(),
|
|||
|
|
std::numeric_limits<double>::epsilon(),
|
|||
|
|
1e-15, 1e-10, 1e-5,
|
|||
|
|
1.0, 10.0, 100.0,
|
|||
|
|
1e5, 1e10, 1e15,
|
|||
|
|
std::numeric_limits<double>::max() * 0.5,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
for (double v : values) {
|
|||
|
|
if (!std::isfinite(v)) continue;
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto body = make_box(v, v, v);
|
|||
|
|
body.is_valid();
|
|||
|
|
auto mesh = body.to_mesh();
|
|||
|
|
(void)mesh;
|
|||
|
|
}) << "failed at v=" << v;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 混合边界值布尔
|
|||
|
|
auto a = make_box(values[0], 1.0, 1.0);
|
|||
|
|
for (int i = 1; i < 10; ++i) {
|
|||
|
|
if (!std::isfinite(values[i])) continue;
|
|||
|
|
EXPECT_NO_THROW({
|
|||
|
|
auto b = make_box(values[i], 1.0, 1.0);
|
|||
|
|
auto u = brep_union(a, b);
|
|||
|
|
(void)u.is_valid();
|
|||
|
|
}) << "failed at i=" << i;
|
|||
|
|
}
|
|||
|
|
}
|