63fba5389a
v10.1 — Tolerant Modeling (对标 Parasolid): - tolerant_modeling.h/.cpp: TolerantVertex/Edge, merge_within_tolerance (BFS) - gap_bridging (free edge detection → triangle filling) - overlap_resolution (normal+centroid+AABB detection) - tolerant_boolean (heal→degenerate detect→boolean→heal) + BooleanDiagnostic - import_heal_pipeline (STEP one-shot repair) - ssi_boolean enhanced: coplanar/collinear/tangent detection, GMP on all classify paths - step_import enhanced: broken file recovery, non-standard entity mapping, diagnostic report - 30 tests, 4112 total lines v10.2 — Class-A Deep + Hex Mesh (对标 CGM + ANSYS): - class_a_surfacing enhanced: g3_blend_with_constraints, surface_energy_minimization - curvature_continuity_optimization, reflection_line_discontinuity (+720 lines) - fea_mesh enhanced: mapped_hex, submapped_hex, multi_block_hex (TFI), hex_quality_optimization (+522 lines) - 22 tests v10.3 — Constraint Solver + Drawing Standards (对标 D-Cubed + AutoCAD): - constraint_solver enhanced: DOFAnalyzer, RedundancyDetector, ConstraintPropagator, KinematicChainSolver - drawing_standards.h/.cpp: IsoStandard (ISO 128/129), AnsiStandard (ASME Y14.5), JisStandard (JIS B 0001) - 12 tests 12 files, ~5000 lines, 64 tests. Target: 87% → 93%
550 lines
17 KiB
C++
550 lines
17 KiB
C++
#include <gtest/gtest.h>
|
||
#include "vde/curves/class_a_surfacing.h"
|
||
#include "vde/curves/nurbs_curve.h"
|
||
#include "vde/curves/nurbs_surface.h"
|
||
#include <cmath>
|
||
|
||
using namespace vde::curves;
|
||
using namespace vde::core;
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Helpers
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/// 创建平面 NURBS 曲面(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 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);
|
||
}
|
||
|
||
/// 创建圆柱面
|
||
static NurbsSurface cylinder_surface() {
|
||
double R = 1.0;
|
||
std::vector<std::vector<Point3D>> grid(5, std::vector<Point3D>(3));
|
||
for (int i = 0; i < 5; ++i) {
|
||
double angle = i * M_PI / 2.0;
|
||
double x = R * std::cos(angle);
|
||
double y = R * std::sin(angle);
|
||
for (int j = 0; j < 3; ++j) {
|
||
grid[i][j] = Point3D(x, y, j * 0.5);
|
||
}
|
||
}
|
||
std::vector<std::vector<double>> w(5, std::vector<double>(3, 1.0));
|
||
return NurbsSurface(grid,
|
||
{0,0,0,0,0.5,1,1,1,1},
|
||
{0,0,0,1,1,1}, w, 3, 2);
|
||
}
|
||
|
||
/// 沿 Z 偏移的平面
|
||
static NurbsSurface offset_plane(double z) {
|
||
std::vector<std::vector<Point3D>> grid = {
|
||
{Point3D(0,0,z), Point3D(0,1,z)},
|
||
{Point3D(1,0,z), Point3D(1,1,z)}
|
||
};
|
||
return NurbsSurface(grid, {0,0,1,1}, {0,0,1,1}, {{1,1},{1,1}}, 1, 1);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: G3 Blend — G3 连续性过渡
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, G3Blend_IdenticalPlanes) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.0); // 重合平面
|
||
|
||
EdgeParams params;
|
||
params.edge_a = 3; // vmax of a
|
||
params.edge_b = 2; // vmin of b
|
||
params.blend_width = 0.2;
|
||
|
||
auto result = g3_blend(a, b, params);
|
||
|
||
// 过渡面应该非退化
|
||
auto [nu, nv] = result.blend_surface.num_control_points();
|
||
EXPECT_GT(nu, 0);
|
||
EXPECT_GT(nv, 0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, G3Blend_ContinuityChecks) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.0);
|
||
|
||
EdgeParams params;
|
||
params.blend_width = 0.15;
|
||
|
||
auto result = g3_blend(a, b, params);
|
||
|
||
// G0 位置连续
|
||
EXPECT_TRUE(result.g0_ok);
|
||
EXPECT_LT(result.max_position_error, 1e-3);
|
||
|
||
// G1 切平面连续
|
||
EXPECT_TRUE(result.g1_ok);
|
||
EXPECT_LT(result.max_tangent_error, 0.02);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, G3Blend_ResultHasBlendSurface) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(1.0); // 间距 1
|
||
|
||
EdgeParams params;
|
||
params.edge_a = 3;
|
||
params.edge_b = 2;
|
||
params.blend_width = 0.5;
|
||
|
||
auto result = g3_blend(a, b, params);
|
||
|
||
auto [nu, nv] = result.blend_surface.num_control_points();
|
||
// 应生成有效的过渡曲面
|
||
EXPECT_GE(nu, 2);
|
||
EXPECT_EQ(nv, 4); // G3 需要 4 排控制点
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Curvature Matching — 曲率匹配
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, CurvatureMatching_FlatPlanes) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.0);
|
||
|
||
CurvatureMatchOptions opts;
|
||
opts.samples_per_edge = 10;
|
||
opts.max_iterations = 20;
|
||
|
||
auto result = curvature_matching(a, b, opts);
|
||
|
||
// 平面曲率处处为0,匹配后应保持
|
||
EXPECT_LT(result.final_rms_curvature_diff, 1.0);
|
||
EXPECT_GT(result.iterations, 0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, CurvatureMatching_ReturnsMatchedSurface) {
|
||
auto a = quad_surface();
|
||
auto b = quad_surface();
|
||
|
||
CurvatureMatchOptions opts;
|
||
opts.max_iterations = 5;
|
||
opts.tolerance = 1e-4;
|
||
|
||
auto result = curvature_matching(a, b, opts);
|
||
|
||
auto [nu, nv] = result.matched_surface_b.num_control_points();
|
||
EXPECT_EQ(nu, 3);
|
||
EXPECT_EQ(nv, 3);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, CurvatureMatching_DisplacementVector) {
|
||
auto a = plane_surface();
|
||
auto b = quad_surface();
|
||
|
||
CurvatureMatchOptions opts;
|
||
opts.max_iterations = 3;
|
||
|
||
auto result = curvature_matching(a, b, opts);
|
||
|
||
// 应有位移向量
|
||
EXPECT_FALSE(result.displacement.empty());
|
||
EXPECT_GE(result.displacement.size(), 1u);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Highlight Lines — 高光线分析
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, HighlightLines_PlaneOutput) {
|
||
auto s = plane_surface();
|
||
std::vector<Vector3D> lights = {Vector3D(0,0,1)};
|
||
|
||
auto result = highlight_lines(s, lights, 10, 10, 6);
|
||
|
||
EXPECT_EQ(result.res_u, 10);
|
||
EXPECT_EQ(result.res_v, 10);
|
||
EXPECT_EQ(static_cast<int>(result.band_mask.size()), 1);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, HighlightLines_MultipleLights) {
|
||
auto s = quad_surface();
|
||
std::vector<Vector3D> lights = {
|
||
Vector3D(1,0,0), Vector3D(0,1,0), Vector3D(0,0,1)
|
||
};
|
||
|
||
auto result = highlight_lines(s, lights, 15, 15, 8);
|
||
|
||
EXPECT_EQ(static_cast<int>(result.band_mask.size()), 3);
|
||
EXPECT_EQ(static_cast<int>(result.continuity_scores.size()), 3);
|
||
EXPECT_GE(result.overall_score, 0.0);
|
||
EXPECT_LE(result.overall_score, 1.0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, HighlightLines_FlatPlanePerfectScore) {
|
||
auto s = plane_surface();
|
||
std::vector<Vector3D> lights = {Vector3D(1,1,1)};
|
||
|
||
auto result = highlight_lines(s, lights, 20, 20, 10);
|
||
|
||
// 平面上高光线应连续
|
||
EXPECT_GT(result.continuity_scores[0], 0.9);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Reflection Lines — 反射线分析
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, ReflectionLines_PlaneIsFair) {
|
||
auto s = plane_surface();
|
||
auto result = reflection_lines(s,
|
||
Point3D(5, 5, 5), Point3D(-5, -5, 10), 20, 20);
|
||
|
||
EXPECT_EQ(result.res_u, 20);
|
||
EXPECT_EQ(result.res_v, 20);
|
||
// 平面反射线应判定为光顺
|
||
EXPECT_TRUE(result.is_fair);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, ReflectionLines_DistortionBounds) {
|
||
auto s = quad_surface();
|
||
auto result = reflection_lines(s,
|
||
Point3D(3, 3, 5), Point3D(-3, -3, 8), 15, 15);
|
||
|
||
EXPECT_GE(result.max_distortion, 0.0);
|
||
EXPECT_GE(result.mean_distortion, 0.0);
|
||
EXPECT_LE(result.mean_distortion, result.max_distortion + 1e-9);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Iso-Photes — 等照度分析
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, IsoPhotes_OutputDimensions) {
|
||
auto s = plane_surface();
|
||
auto result = iso_photes(s, 16);
|
||
|
||
EXPECT_EQ(result.res_u, 16);
|
||
EXPECT_EQ(result.res_v, 16);
|
||
EXPECT_EQ(static_cast<int>(result.illumination.size()), 17);
|
||
EXPECT_EQ(static_cast<int>(result.illumination[0].size()), 17);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, IsoPhotes_IlluminationRange) {
|
||
auto s = plane_surface();
|
||
auto result = iso_photes(s, 10);
|
||
|
||
for (size_t i = 0; i < result.illumination.size(); ++i) {
|
||
for (size_t j = 0; j < result.illumination[i].size(); ++j) {
|
||
double val = result.illumination[i][j];
|
||
EXPECT_GE(val, -1.1);
|
||
EXPECT_LE(val, 1.1);
|
||
}
|
||
}
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, IsoPhotes_GradientAnalysis) {
|
||
auto s = quad_surface();
|
||
auto result = iso_photes(s, 20);
|
||
|
||
EXPECT_GE(result.grad_max, 0.0);
|
||
EXPECT_GE(result.grad_mean, 0.0);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Surface Diagnosis — 综合曲面诊断
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, SurfaceDiagnosis_PlaneDiagnosis) {
|
||
auto s = plane_surface();
|
||
auto report = surface_diagnosis(s);
|
||
|
||
// 平面应该达到 A 级
|
||
EXPECT_EQ(report.grade, DiagnosisGrade::A_CLASS);
|
||
EXPECT_GT(report.overall_score, 80.0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, SurfaceDiagnosis_ReportHasAllFields) {
|
||
auto s = quad_surface();
|
||
auto report = surface_diagnosis(s);
|
||
|
||
EXPECT_FALSE(report.gaussian_range.name.empty());
|
||
EXPECT_FALSE(report.mean_range.name.empty());
|
||
EXPECT_FALSE(report.highlight_score.name.empty());
|
||
EXPECT_FALSE(report.reflection_distortion.name.empty());
|
||
EXPECT_FALSE(report.isophote_gradient.name.empty());
|
||
EXPECT_FALSE(report.normal_jump.name.empty());
|
||
EXPECT_FALSE(report.recommendation.empty());
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Shape Modification — 保形修改
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, ShapeModification_SingleConstraint) {
|
||
auto s = plane_surface();
|
||
|
||
std::vector<ShapeConstraint> constraints;
|
||
ShapeConstraint c;
|
||
c.target_point = Point3D(0.5, 0.5, 0.5); // 提升0.5
|
||
c.u = 0.5;
|
||
c.v = 0.5;
|
||
c.weight = 1.0;
|
||
constraints.push_back(c);
|
||
|
||
auto result = shape_modification(s, constraints);
|
||
|
||
auto [nu, nv] = result.modified_surface.num_control_points();
|
||
EXPECT_EQ(nu, 2);
|
||
EXPECT_EQ(nv, 2);
|
||
|
||
// 控制点应有位移
|
||
EXPECT_GT(result.max_displacement, 0.0);
|
||
EXPECT_GE(result.energy_preserved_ratio, 0.0);
|
||
EXPECT_LE(result.energy_preserved_ratio, 1.1);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, ShapeModification_ConstraintPointMoves) {
|
||
auto s = plane_surface();
|
||
|
||
std::vector<ShapeConstraint> constraints;
|
||
ShapeConstraint c;
|
||
c.target_point = Point3D(0.3, 0.3, 2.0);
|
||
c.u = 0.3;
|
||
c.v = 0.3;
|
||
c.weight = 2.0;
|
||
constraints.push_back(c);
|
||
|
||
auto result = shape_modification(s, constraints);
|
||
|
||
// 修改后的曲面在约束点处应接近目标
|
||
auto pt = result.modified_surface.evaluate(0.3, 0.3);
|
||
EXPECT_GT(pt.z(), 0.1); // 应被提起
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, ShapeModification_MultipleConstraints) {
|
||
auto s = quad_surface();
|
||
|
||
std::vector<ShapeConstraint> constraints;
|
||
for (int i = 0; i < 3; ++i) {
|
||
ShapeConstraint c;
|
||
c.u = 0.25 * (i + 1);
|
||
c.v = 0.5;
|
||
c.target_point = Point3D(c.u * 2, 1.0, 1.5 + i * 0.5);
|
||
c.weight = 1.0;
|
||
constraints.push_back(c);
|
||
}
|
||
|
||
auto result = shape_modification(s, constraints);
|
||
|
||
EXPECT_GE(result.iterations, 1);
|
||
EXPECT_GT(result.max_displacement, 0.0);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: G3 Blend with Constraints — 带约束 G3 过渡 (新增)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, G3BlendWithConstraints_IdenticalPlanes) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.0);
|
||
|
||
G3ConstraintEdges edges;
|
||
edges.g0_edge.edge_a = 3;
|
||
edges.g0_edge.edge_b = 2;
|
||
edges.g0_edge.blend_width = 0.2;
|
||
edges.g1_edge = edges.g0_edge;
|
||
edges.g2_edge = edges.g0_edge;
|
||
edges.g3_edge = edges.g0_edge;
|
||
|
||
auto result = g3_blend_with_constraints(a, b, edges);
|
||
|
||
auto [nu, nv] = result.blend_surface.num_control_points();
|
||
EXPECT_GT(nu, 0);
|
||
EXPECT_GT(nv, 0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, G3BlendWithConstraints_G0G1Check) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.0);
|
||
|
||
G3ConstraintEdges edges;
|
||
edges.g0_edge.edge_a = 3;
|
||
edges.g0_edge.edge_b = 2;
|
||
edges.g0_edge.blend_width = 0.15;
|
||
edges.g1_edge = edges.g0_edge;
|
||
edges.g2_edge = edges.g0_edge;
|
||
edges.g3_edge = edges.g0_edge;
|
||
edges.enforce_g0 = true;
|
||
edges.enforce_g1 = true;
|
||
|
||
auto result = g3_blend_with_constraints(a, b, edges);
|
||
|
||
EXPECT_TRUE(result.g0_ok);
|
||
EXPECT_TRUE(result.g1_ok);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, G3BlendWithConstraints_OnlyG0Enforced) {
|
||
auto a = plane_surface();
|
||
auto b = offset_plane(0.5);
|
||
|
||
G3ConstraintEdges edges;
|
||
edges.g0_edge.edge_a = 3;
|
||
edges.g0_edge.edge_b = 2;
|
||
edges.g0_edge.blend_width = 0.3;
|
||
edges.g1_edge = edges.g0_edge;
|
||
edges.g2_edge = edges.g0_edge;
|
||
edges.g3_edge = edges.g0_edge;
|
||
edges.enforce_g0 = true;
|
||
edges.enforce_g1 = false;
|
||
edges.enforce_g2 = false;
|
||
edges.enforce_g3 = false;
|
||
|
||
auto result = g3_blend_with_constraints(a, b, edges);
|
||
|
||
EXPECT_TRUE(result.g0_ok);
|
||
EXPECT_FALSE(result.g1_ok); // G1未强制=检查默认失败
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Surface Energy Minimization — 薄板能量最小化 (新增)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, EnergyMinimization_FlatSurface) {
|
||
auto s = plane_surface();
|
||
|
||
EnergyMinimizationOptions opts;
|
||
opts.max_iterations = 20;
|
||
opts.tolerance = 1e-4;
|
||
|
||
auto result = surface_energy_minimization(s, {}, opts);
|
||
|
||
auto [nu, nv] = result.optimized_surface.num_control_points();
|
||
EXPECT_EQ(nu, 2);
|
||
EXPECT_EQ(nv, 2);
|
||
EXPECT_GE(result.final_bending_energy, 0.0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, EnergyMinimization_WithConstraint) {
|
||
auto s = quad_surface();
|
||
|
||
std::vector<ShapeConstraint> constraints;
|
||
ShapeConstraint c;
|
||
c.target_point = Point3D(1.0, 1.0, 2.0);
|
||
c.u = 0.5;
|
||
c.v = 0.5;
|
||
c.weight = 5.0;
|
||
constraints.push_back(c);
|
||
|
||
EnergyMinimizationOptions opts;
|
||
opts.max_iterations = 30;
|
||
opts.constraint_weight = 20.0;
|
||
|
||
auto result = surface_energy_minimization(s, constraints, opts);
|
||
|
||
EXPECT_GT(result.iterations, 0);
|
||
EXPECT_GT(result.max_displacement, 0.0);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, EnergyMinimization_BendingReduction) {
|
||
auto s = quad_surface();
|
||
|
||
EnergyMinimizationOptions opts;
|
||
opts.bending_weight = 5.0;
|
||
opts.membrane_weight = 0.01;
|
||
opts.max_iterations = 50;
|
||
opts.preserve_boundary = false;
|
||
|
||
auto result = surface_energy_minimization(s, {}, opts);
|
||
|
||
EXPECT_GE(result.final_bending_energy, 0.0);
|
||
EXPECT_GE(result.iterations, 1);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Curvature Continuity Optimization — 曲率连续性迭代精化 (新增)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, CurvatureContinuity_IdenticalSurfaces) {
|
||
auto a = plane_surface();
|
||
auto b = plane_surface();
|
||
|
||
CurvatureContinuityOptions opts;
|
||
opts.max_iterations = 10;
|
||
opts.boundary_samples = 15;
|
||
|
||
auto result = curvature_continuity_optimization(a, b, opts);
|
||
|
||
EXPECT_LT(result.final_g0_error, 1e-3);
|
||
EXPECT_LT(result.final_g1_error, 0.01);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, CurvatureContinuity_QuadSurfaces) {
|
||
auto a = quad_surface();
|
||
auto b = quad_surface();
|
||
|
||
CurvatureContinuityOptions opts;
|
||
opts.max_iterations = 20;
|
||
opts.boundary_samples = 20;
|
||
opts.step_size = 0.02;
|
||
|
||
auto result = curvature_continuity_optimization(a, b, opts);
|
||
|
||
auto [nu, nv] = result.optimized_b.num_control_points();
|
||
EXPECT_EQ(nu, 3);
|
||
EXPECT_EQ(nv, 3);
|
||
EXPECT_GE(result.iterations, 0);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test: Reflection Line Discontinuity — 反射线不连续检测+修复 (新增)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
TEST(ClassASurfacingTest, ReflectionDiscontinuity_PlaneIsSmooth) {
|
||
auto s = plane_surface();
|
||
|
||
ReflectionDiscontinuityParams params;
|
||
params.light_direction = Vector3D(1, 0, 0);
|
||
params.res_u = 20;
|
||
params.res_v = 20;
|
||
params.discontinuity_threshold = 0.05;
|
||
params.auto_fix = false;
|
||
|
||
auto result = reflection_line_discontinuity(s, params);
|
||
|
||
EXPECT_EQ(result.res_u, 20);
|
||
EXPECT_EQ(result.res_v, 20);
|
||
EXPECT_TRUE(result.is_smooth);
|
||
}
|
||
|
||
TEST(ClassASurfacingTest, ReflectionDiscontinuity_AutoFix) {
|
||
auto s = quad_surface();
|
||
|
||
ReflectionDiscontinuityParams params;
|
||
params.light_direction = Vector3D(1, 1, 1);
|
||
params.res_u = 15;
|
||
params.res_v = 15;
|
||
params.discontinuity_threshold = 0.1;
|
||
params.max_fix_iterations = 5;
|
||
params.fix_strength = 0.05;
|
||
params.auto_fix = true;
|
||
|
||
auto result = reflection_line_discontinuity(s, params);
|
||
|
||
auto [nu, nv] = result.fixed_surface.num_control_points();
|
||
EXPECT_GT(nu, 0);
|
||
EXPECT_GT(nv, 0);
|
||
EXPECT_GE(result.total_discontinuities, 0);
|
||
}
|