226 lines
7.0 KiB
C++
226 lines
7.0 KiB
C++
|
|
#include <gtest/gtest.h>
|
|||
|
|
#include "vde/curves/advanced_intersection.h"
|
|||
|
|
#include "vde/curves/nurbs_curve.h"
|
|||
|
|
#include "vde/curves/nurbs_surface.h"
|
|||
|
|
#include <cmath>
|
|||
|
|
|
|||
|
|
using namespace vde::curves;
|
|||
|
|
using namespace vde::core;
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Helpers
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
/// 平面 XY 平面 [0,1]×[0,1]
|
|||
|
|
static NurbsSurface plane_surface() {
|
|||
|
|
std::vector<std::vector<Point3D>> grid = {
|
|||
|
|
{Point3D(0,0,0), Point3D(0,1,0)},
|
|||
|
|
{Point3D(1,0,0), Point3D(1,1,0)}
|
|||
|
|
};
|
|||
|
|
return NurbsSurface(grid, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 倾斜平面(对角线方向)
|
|||
|
|
static NurbsSurface tilted_plane() {
|
|||
|
|
std::vector<std::vector<Point3D>> grid = {
|
|||
|
|
{Point3D(0,0,0), Point3D(0,1,0.5)},
|
|||
|
|
{Point3D(1,0,0.5), Point3D(1,1,1)}
|
|||
|
|
};
|
|||
|
|
return NurbsSurface(grid, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 抛物面
|
|||
|
|
static NurbsSurface quad_surface() {
|
|||
|
|
std::vector<std::vector<Point3D>> grid = {
|
|||
|
|
{Point3D(0,0,0), Point3D(0,1,0.5), Point3D(0,2,0)},
|
|||
|
|
{Point3D(1,0,0.5), Point3D(1,1,1), Point3D(1,2,0.5)},
|
|||
|
|
{Point3D(2,0,0), Point3D(2,1,0.5), Point3D(2,2,0)}
|
|||
|
|
};
|
|||
|
|
return NurbsSurface(grid,
|
|||
|
|
{0,0,0,1,1,1}, {0,0,0,1,1,1},
|
|||
|
|
{{1,1,1},{1,1,1},{1,1,1}}, 2, 2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 构造简单 NURBS 曲线
|
|||
|
|
static NurbsCurve line(double x0, double y0, double z0, double x1, double y1, double z1) {
|
|||
|
|
return NurbsCurve(
|
|||
|
|
{Point3D(x0, y0, z0), Point3D(x1, y1, z1)},
|
|||
|
|
{0, 0, 1, 1}, {1, 1}, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 三次 NURBS 曲线
|
|||
|
|
static NurbsCurve cubic_curve() {
|
|||
|
|
return NurbsCurve(
|
|||
|
|
{Point3D(0,0,0), Point3D(1,2,0), Point3D(2,1,0), Point3D(3,0,0)},
|
|||
|
|
{0,0,0,0,1,1,1,1}, {1,1,1,1}, 3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Test: Robust SSI — 鲁棒曲面求交
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, RobustSSI_NonIntersectingPlanes) {
|
|||
|
|
auto a = plane_surface();
|
|||
|
|
// 平面在 Z=5,与 XY 平面无交
|
|||
|
|
std::vector<std::vector<Point3D>> grid2 = {
|
|||
|
|
{Point3D(0,0,5), Point3D(0,1,5)},
|
|||
|
|
{Point3D(1,0,5), Point3D(1,1,5)}
|
|||
|
|
};
|
|||
|
|
auto b = NurbsSurface(grid2, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1);
|
|||
|
|
|
|||
|
|
SSIOptions opts;
|
|||
|
|
auto result = robust_ssi(a, b, opts);
|
|||
|
|
|
|||
|
|
EXPECT_TRUE(result.success);
|
|||
|
|
EXPECT_EQ(0u, result.segments.size());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, RobustSSI_CoincidentPlanes) {
|
|||
|
|
auto a = plane_surface();
|
|||
|
|
auto b = plane_surface(); // 完全相同
|
|||
|
|
|
|||
|
|
auto result = robust_ssi(a, b);
|
|||
|
|
|
|||
|
|
EXPECT_TRUE(result.success);
|
|||
|
|
// 重合面应检测到交线(可能多个)
|
|||
|
|
EXPECT_GT(result.phase1_subdivisions, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, RobustSSI_CrossingPlanes) {
|
|||
|
|
// XY 平面
|
|||
|
|
auto a = plane_surface();
|
|||
|
|
// XZ 平面(法向量为 Y 方向)
|
|||
|
|
std::vector<std::vector<Point3D>> grid2 = {
|
|||
|
|
{Point3D(0,0.5,0), Point3D(0,0.5,1)},
|
|||
|
|
{Point3D(1,0.5,0), Point3D(1,0.5,1)}
|
|||
|
|
};
|
|||
|
|
auto b = NurbsSurface(grid2, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1);
|
|||
|
|
|
|||
|
|
auto result = robust_ssi(a, b);
|
|||
|
|
|
|||
|
|
EXPECT_TRUE(result.success);
|
|||
|
|
// 两相交平面应有交线
|
|||
|
|
EXPECT_GT(result.segments.size(), 0u);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, RobustSSI_PhaseStatistics) {
|
|||
|
|
auto a = tilted_plane();
|
|||
|
|
auto b = plane_surface();
|
|||
|
|
|
|||
|
|
auto result = robust_ssi(a, b);
|
|||
|
|
|
|||
|
|
// 阶段统计应合理
|
|||
|
|
EXPECT_GE(result.phase1_subdivisions, 0);
|
|||
|
|
EXPECT_GE(result.phase2_converged + result.phase2_diverged,
|
|||
|
|
static_cast<int>(result.segments.size()));
|
|||
|
|
EXPECT_GE(result.total_time_ms, 0.0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, RobustSSI_NewtonPrecision) {
|
|||
|
|
auto a = tilted_plane();
|
|||
|
|
auto b = plane_surface();
|
|||
|
|
|
|||
|
|
SSIOptions opts;
|
|||
|
|
opts.newton_tolerance = 1e-10;
|
|||
|
|
opts.max_newton_iter = 25;
|
|||
|
|
|
|||
|
|
auto result = robust_ssi(a, b, opts);
|
|||
|
|
|
|||
|
|
// 检查结果精度
|
|||
|
|
for (const auto& seg : result.segments) {
|
|||
|
|
for (size_t i = 0; i < seg.points.size(); ++i) {
|
|||
|
|
auto pa = a.evaluate(seg.params_a[i].first, seg.params_a[i].second);
|
|||
|
|
auto pb = b.evaluate(seg.params_b[i].first, seg.params_b[i].second);
|
|||
|
|
EXPECT_LT((pa - pb).norm(), 1e-4);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Test: Curve-Surface Intersection — 曲线-曲面求交
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, CurveSurfaceIntersection_LineThroughPlane) {
|
|||
|
|
auto surf = plane_surface();
|
|||
|
|
auto curve = line(0.5, 0.5, -1, 0.5, 0.5, 2); // 垂直穿过的线
|
|||
|
|
|
|||
|
|
auto pts = curve_surface_intersection(curve, surf);
|
|||
|
|
|
|||
|
|
// 应检测到1个交点
|
|||
|
|
EXPECT_GE(pts.size(), 1u);
|
|||
|
|
if (!pts.empty()) {
|
|||
|
|
EXPECT_NEAR(pts[0].position.z(), 0.0, 1e-4);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, CurveSurfaceIntersection_LineParallelToPlane) {
|
|||
|
|
auto surf = plane_surface();
|
|||
|
|
// 平行于 XY 平面的线(在 z=5 处)
|
|||
|
|
auto curve = line(0, 0, 5, 1, 1, 5);
|
|||
|
|
|
|||
|
|
auto pts = curve_surface_intersection(curve, surf);
|
|||
|
|
|
|||
|
|
// 平行线不应有交点(除非重合)
|
|||
|
|
for (const auto& p : pts) {
|
|||
|
|
EXPECT_NEAR(p.position.z(), 5.0, 1e-3);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, CurveSurfaceIntersection_SortedByT) {
|
|||
|
|
auto surf = quad_surface();
|
|||
|
|
// 斜穿曲面的线(应在多处相交)
|
|||
|
|
auto curve = line(0.5, 0.5, -1, 1.5, 1.5, 2);
|
|||
|
|
|
|||
|
|
auto pts = curve_surface_intersection(curve, surf);
|
|||
|
|
|
|||
|
|
// 交点应按 t 排序
|
|||
|
|
for (size_t i = 1; i < pts.size(); ++i) {
|
|||
|
|
EXPECT_GE(pts[i].t, pts[i-1].t);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, CurveSurfaceIntersection_TangentContact) {
|
|||
|
|
auto surf = plane_surface();
|
|||
|
|
// 在平面内的线
|
|||
|
|
auto curve = line(0, 0, 0, 1, 1, 0);
|
|||
|
|
|
|||
|
|
auto pts = curve_surface_intersection(curve, surf);
|
|||
|
|
|
|||
|
|
// 平面内的线可能有切线接触
|
|||
|
|
// (实现可能返回多个交点或标记为切线)
|
|||
|
|
for (const auto& p : pts) {
|
|||
|
|
EXPECT_NEAR(p.distance, 0.0, 1e-8);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Test: Self-Intersection Detection — 自交检测
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, SelfIntersection_PlaneNoSelfIntersection) {
|
|||
|
|
auto s = plane_surface();
|
|||
|
|
auto result = self_intersection_detection(s);
|
|||
|
|
|
|||
|
|
// 平面不应自交
|
|||
|
|
EXPECT_FALSE(result.has_self_intersection);
|
|||
|
|
EXPECT_EQ(0u, result.regions.size());
|
|||
|
|
EXPECT_GT(result.total_checks, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, SelfIntersection_QuadSurfaceNoSelfIntersection) {
|
|||
|
|
auto s = quad_surface();
|
|||
|
|
auto result = self_intersection_detection(s, 1e-6);
|
|||
|
|
|
|||
|
|
// 规则曲面不应自交
|
|||
|
|
EXPECT_FALSE(result.has_self_intersection);
|
|||
|
|
EXPECT_GT(result.total_checks, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(AdvancedIntersectionTest, SelfIntersection_DetectionTime) {
|
|||
|
|
auto s = quad_surface();
|
|||
|
|
auto result = self_intersection_detection(s, 1e-8);
|
|||
|
|
|
|||
|
|
EXPECT_GE(result.detection_time_ms, 0.0);
|
|||
|
|
EXPECT_GT(result.total_checks, 0);
|
|||
|
|
}
|