Files
ViewDesignEngine/tests/brep/test_advanced_blend.cpp
茂之钳 73df04d5cb
Build & Test / build-and-test (push) Waiting to run
Build & Test / python-bindings (push) Blocked by required conditions
CI / Build & Test (push) Failing after 35s
CI / Release Build (push) Failing after 1m32s
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

159 lines
6.1 KiB
C++

#include <gtest/gtest.h>
#include "vde/brep/advanced_blend.h"
#include "vde/brep/modeling.h"
#include "vde/brep/brep_validate.h"
#include "vde/brep/brep.h"
#include <cmath>
using namespace vde::brep;
using namespace vde::core;
// ═══════════════════════════════════════════════
// variable_radius_blend 测试 (4项)
// ═══════════════════════════════════════════════
TEST(VariableRadiusBlendTest, BoxEdgeGrowRadius) {
auto box = make_box(4, 4, 4);
auto result = variable_radius_blend(box, 0, 0.3, 0.8, 16);
// Blend adds blend-strip faces → more faces than original
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_GT(result.num_edges(), box.num_edges());
EXPECT_GT(result.num_vertices(), 0u);
EXPECT_TRUE(result.is_valid());
}
TEST(VariableRadiusBlendTest, BoxEdgeShrinkRadius) {
auto box = make_box(4, 4, 4);
auto result = variable_radius_blend(box, 0, 0.8, 0.3, 12);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
TEST(VariableRadiusBlendTest, BoxEdgeSymmetric) {
auto box = make_box(4, 4, 4);
// Equal start and end radius → constant-radius blend
auto r1 = variable_radius_blend(box, 0, 0.5, 0.5, 8);
auto r2 = variable_radius_blend(box, 0, 0.5, 0.5, 16);
EXPECT_GT(r1.num_faces(), box.num_faces());
// More samples = more blend strips = more faces
EXPECT_GT(r2.num_faces(), r1.num_faces());
EXPECT_TRUE(r1.is_valid());
EXPECT_TRUE(r2.is_valid());
}
TEST(VariableRadiusBlendTest, SmallRadiusNearZero) {
auto box = make_box(4, 4, 4);
auto result = variable_radius_blend(box, 1, 0.05, 0.5, 8);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
// ═══════════════════════════════════════════════
// multi_face_blend 测试 (3项)
// ═══════════════════════════════════════════════
TEST(MultiFaceBlendTest, TwoFaces) {
auto box = make_box(4, 4, 4);
auto result = multi_face_blend(box, {0, 1}, 0.5);
EXPECT_GT(result.num_vertices(), 0u);
EXPECT_TRUE(result.is_valid());
}
TEST(MultiFaceBlendTest, ThreeFacesCorner) {
// Blend 3 faces meeting at a corner — spherical corner fill added
auto box = make_box(4, 4, 4);
auto result = multi_face_blend(box, {0, 2, 4}, 0.4);
EXPECT_GT(result.num_vertices(), 0u);
EXPECT_TRUE(result.is_valid());
}
TEST(MultiFaceBlendTest, AllFaces) {
auto box = make_box(4, 4, 4);
std::vector<int> all_faces;
for (size_t i = 0; i < box.num_faces(); ++i)
all_faces.push_back(static_cast<int>(i));
auto result = multi_face_blend(box, all_faces, 0.3);
EXPECT_GT(result.num_vertices(), 0u);
EXPECT_TRUE(result.is_valid());
}
// ═══════════════════════════════════════════════
// rolling_ball_blend 测试 (4项)
// ═══════════════════════════════════════════════
TEST(RollingBallBlendTest, StraightEdge) {
auto box = make_box(4, 4, 4);
auto result = rolling_ball_blend(box, 0, 0.5, 20);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
TEST(RollingBallBlendTest, ConvexCorner) {
// Box edge is a convex corner
auto box = make_box(4, 4, 4);
auto result = rolling_ball_blend(box, 3, 0.6, 16);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
TEST(RollingBallBlendTest, DifferentEdges) {
auto box = make_box(4, 4, 4);
// Test rolling ball on first 4 edges
for (int ei = 0; ei < 4; ++ei) {
auto result = rolling_ball_blend(box, ei, 0.3, 10);
EXPECT_GT(result.num_faces(), box.num_faces()) << "edge " << ei;
EXPECT_TRUE(result.is_valid()) << "edge " << ei;
}
}
TEST(RollingBallBlendTest, VaryingSamples) {
auto box = make_box(4, 4, 4);
auto r1 = rolling_ball_blend(box, 0, 0.5, 8);
auto r2 = rolling_ball_blend(box, 0, 0.5, 20);
// More samples => more blend strip faces
EXPECT_GT(r2.num_faces(), r1.num_faces());
EXPECT_TRUE(r1.is_valid());
EXPECT_TRUE(r2.is_valid());
}
// ═══════════════════════════════════════════════
// face_face_blend 测试 (4项)
// ═══════════════════════════════════════════════
TEST(FaceFaceBlendTest, AdjacentFaces) {
auto box = make_box(4, 4, 4);
// face 0 (-Z) and face 2 (-Y) share an edge
auto result = face_face_blend(box, 0, 2, 0.5, 16);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
TEST(FaceFaceBlendTest, DifferentAdjacentPair) {
auto box = make_box(4, 4, 4);
auto result = face_face_blend(box, 1, 4, 0.4, 12);
EXPECT_GT(result.num_faces(), box.num_faces());
EXPECT_TRUE(result.is_valid());
}
TEST(FaceFaceBlendTest, MultiplePairs) {
auto box = make_box(4, 4, 4);
auto r1 = face_face_blend(box, 0, 2, 0.3, 8);
auto r2 = face_face_blend(box, 1, 4, 0.4, 10);
auto r3 = face_face_blend(box, 3, 5, 0.35, 12);
EXPECT_GT(r1.num_faces(), box.num_faces());
EXPECT_GT(r2.num_faces(), box.num_faces());
EXPECT_GT(r3.num_faces(), box.num_faces());
EXPECT_TRUE(r1.is_valid());
EXPECT_TRUE(r2.is_valid());
EXPECT_TRUE(r3.is_valid());
}
TEST(FaceFaceBlendTest, NonSharedEdgeFallback) {
// Opposite faces — no shared edge, falls back gracefully
auto box = make_box(4, 4, 4);
auto result = face_face_blend(box, 0, 1, 0.2, 8);
// Should return a valid model (may be original if no common edge)
EXPECT_GT(result.num_faces(), 0u);
EXPECT_TRUE(result.is_valid());
}