Files
ViewDesignEngine/tests/curves/test_surface_continuity.cpp
T
茂之钳 73df04d5cb
CI / Build & Test (push) Failing after 35s
CI / Release Build (push) Failing after 1m32s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
feat(v5-M2): G2/G3 continuity + surface analysis + extension + N-side fill + advanced blend
M2.1 — G2/G3 连续性分析 (Agent #0):
- surface_continuity.h/.cpp: G0/G1/G2/G3 curve/surface detection
- Weingarten equation for curvature, Frénet frame, zebra stripe
- surface_analysis.h/.cpp: curvature_map, deviation_analysis, curvature_comb
- 24 tests (12 continuity + 12 analysis)

M2.2 — 曲面延伸 + N边填充 (Agent #1):
- surface_extension.h/.cpp: extend_surface(G1/G2), n_sided_fill, blend_surfaces
- Coons patch generalization for N-sided holes
- 16/16 tests passed in Docker container

M2.3 — 高级过渡曲面 (Agent #2):
- advanced_blend.h/.cpp: real implementations replacing stubs
- variable_radius_blend, multi_face_blend, rolling_ball_blend, face_face_blend
- Ball-rolling envelope + corner sphere filling
- 15+ tests with validate() verification
2026-07-26 20:58:31 +08:00

196 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <gtest/gtest.h>
#include "vde/curves/surface_continuity.h"
#include "vde/curves/nurbs_curve.h"
#include "vde/curves/nurbs_surface.h"
#include <cmath>
using namespace vde::curves;
using namespace vde::core;
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/// Create a degree-1 NURBS line from a to b
static NurbsCurve line(const Point3D& a, const Point3D& b) {
return NurbsCurve({a, b}, {0, 0, 1, 1}, {1, 1}, 1);
}
/// Create a planar NURBS surface on XY plane over [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);
}
/// Create a simple NURBS surface from a 2×2 grid
static NurbsSurface simple_surface(const std::vector<std::vector<Point3D>>& grid,
int du=1, int dv=1) {
int rows = static_cast<int>(grid.size());
int cols = static_cast<int>(grid.empty() ? 0 : grid[0].size());
std::vector<double> ku(rows + du + 1, 0.0);
std::vector<double> kv(cols + dv + 1, 0.0);
for (int i = 0; i <= du; ++i) ku[i] = 0.0;
for (size_t i = du + 1; i < ku.size() - du - 1; ++i)
ku[i] = static_cast<double>(i - du) / (ku.size() - 2*du - 1);
for (size_t i = ku.size() - du - 1; i < ku.size(); ++i) ku[i] = 1.0;
for (int i = 0; i <= dv; ++i) kv[i] = 0.0;
for (size_t i = dv + 1; i < kv.size() - dv - 1; ++i)
kv[i] = static_cast<double>(i - dv) / (kv.size() - 2*dv - 1);
for (size_t i = kv.size() - dv - 1; i < kv.size(); ++i) kv[i] = 1.0;
std::vector<std::vector<double>> w(rows, std::vector<double>(cols, 1.0));
return NurbsSurface(grid, ku, kv, w, du, dv);
}
// ---------------------------------------------------------------------------
// Test: to_string
// ---------------------------------------------------------------------------
TEST(ContinuityTest, ToString) {
EXPECT_STREQ("G0", to_string(ContinuityLevel::G0));
EXPECT_STREQ("G1", to_string(ContinuityLevel::G1));
EXPECT_STREQ("G2", to_string(ContinuityLevel::G2));
EXPECT_STREQ("G3", to_string(ContinuityLevel::G3));
EXPECT_STREQ("None", to_string(ContinuityLevel::None));
}
// ---------------------------------------------------------------------------
// Test: G0 — Position continuity on lines
// ---------------------------------------------------------------------------
TEST(ContinuityTest, G0_SameCurveContinuous) {
// Two identical line segments should be G1 (same tangent direction)
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(1, 0, 0), Point3D(2, 0, 0));
auto level = continuity_type(a, b);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G1));
}
TEST(ContinuityTest, G0_EndpointsMatch) {
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(1, 0, 0), Point3D(1, 1, 0));
auto level = continuity_type(a, b);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G0));
}
TEST(ContinuityTest, G0_NoConnection) {
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(5, 5, 5), Point3D(6, 6, 6));
auto level = continuity_type(a, b);
EXPECT_EQ(ContinuityLevel::None, level);
}
// ---------------------------------------------------------------------------
// Test: G1 — Tangent continuity
// ---------------------------------------------------------------------------
TEST(ContinuityTest, G1_CollinearLines) {
// Two collinear lines → G0 position, G1 tangent
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(1, 0, 0), Point3D(2, 0, 0));
// Check at the connection point with explicit t values
auto level = continuity_type(a, 1.0, b, 0.0);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G1));
}
TEST(ContinuityTest, G1_SharpCornerG0Only) {
// Two lines meeting at a right angle → only G0
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(1, 0, 0), Point3D(1, 1, 0));
auto level = continuity_type(a, 1.0, b, 0.0);
EXPECT_EQ(ContinuityLevel::G0, level);
}
// ---------------------------------------------------------------------------
// Test: G2 — Curvature continuity on curves
// ---------------------------------------------------------------------------
TEST(ContinuityTest, G2_StraightLinesG3) {
// Two collinear straight lines have zero curvature everywhere → G3
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(1, 0, 0), Point3D(3, 0, 0));
auto level = continuity_type(a, 1.0, b, 0.0);
// Straight lines have d2=0, curvature=0, so they trivially match → G3
EXPECT_EQ(ContinuityLevel::G3, level);
}
TEST(ContinuityTest, G0_DisconnectedReturnsNone) {
auto a = line(Point3D(0, 0, 0), Point3D(1, 0, 0));
auto b = line(Point3D(10, 10, 10), Point3D(11, 11, 11));
auto level = continuity_type(a, 0.5, b, 0.5);
EXPECT_EQ(ContinuityLevel::None, level);
}
// ---------------------------------------------------------------------------
// Test: Surface Continuity
// ---------------------------------------------------------------------------
TEST(SurfaceContinuityTest, IdenticalPlanes) {
// Two identical flat planes → should be G3
auto s1 = plane_surface();
auto s2 = plane_surface();
auto level = surface_continuity(s1, s2, 10);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G3));
}
TEST(SurfaceContinuityTest, CoplanarSurfacesEdgeMatch) {
// Two adjacent coplanar surfaces sharing an edge
std::vector<std::vector<Point3D>> g1 = {
{Point3D(0,0,0), Point3D(0,1,0)},
{Point3D(1,0,0), Point3D(1,1,0)}
};
std::vector<std::vector<Point3D>> g2 = {
{Point3D(1,0,0), Point3D(1,1,0)},
{Point3D(2,0,0), Point3D(2,1,0)}
};
auto s1 = simple_surface(g1);
auto s2 = simple_surface(g2);
auto level = surface_continuity(s1, s2, 10);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G3));
}
TEST(SurfaceContinuityTest, DisconnectedSurfaces) {
std::vector<std::vector<Point3D>> g1 = {
{Point3D(0,0,0), Point3D(0,1,0)},
{Point3D(1,0,0), Point3D(1,1,0)}
};
std::vector<std::vector<Point3D>> g2 = {
{Point3D(10,0,0), Point3D(10,1,0)},
{Point3D(11,0,0), Point3D(11,1,0)}
};
auto s1 = simple_surface(g1);
auto s2 = simple_surface(g2);
auto level = surface_continuity(s1, s2, 10);
EXPECT_EQ(ContinuityLevel::None, level);
}
TEST(SurfaceContinuityTest, ContinuityReport) {
auto s1 = plane_surface();
auto s2 = plane_surface();
auto report = surface_continuity_report(s1, s2, 20);
EXPECT_GE(static_cast<int>(report.worst), static_cast<int>(ContinuityLevel::G3));
EXPECT_NEAR(report.g1_ratio, 1.0, 0.01);
EXPECT_NEAR(report.g2_ratio, 1.0, 0.01);
}
// ---------------------------------------------------------------------------
// Test: Edge parameter overload
// ---------------------------------------------------------------------------
TEST(SurfaceContinuityTest, ExplicitEdgeParametersPlane) {
auto s1 = plane_surface();
auto s2 = plane_surface();
// Same physical edge (u=1) on both identical surfaces
auto level = surface_continuity(
s1, s2,
{{1.0, 0.0}, {1.0, 1.0}}, // s1: u=1 edge, v 0→1
{{1.0, 0.0}, {1.0, 1.0}}, // s2: same u=1 edge
20);
EXPECT_GE(static_cast<int>(level), static_cast<int>(ContinuityLevel::G3));
}