Files
ViewDesignEngine/tests/curves/test_advanced_intersection.cpp
T

226 lines
7.0 KiB
C++
Raw Normal View History

#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);
}