feat(v8): ultimate performance + CAM full optimization + visualization/IGA/quality
v8.1 — 极致性能 (SIMD + LockFree + Transaction + NUMA): - simd_vector.h: Vec4d/Vec4f SSE/AVX/NEON auto-detect, batch AABB, SoA transpose - concurrent_data: LockFreeQueue (MPMC CAS), LockFreeStack (Treiber), ConcurrentHashMap (64-segment sharded) - transaction: Command pattern, UndoManager (infinite undo/redo), crash-recovery journal - performance_tuning: NUMA-aware, cache_line aligned, prefetch, hot/cold separation - 20 tests (concurrent + transaction), ~2600 lines v8.2 — CAM 全面优化 + 装配模式: - cam_optimization: chip_thinning, HSM, constant_engagement, trochoidal_turn_milling - tool_life_management, probing_cycle, thread_milling - cam_advanced enhanced: Mazak/Okuma/Haas/DMG post-processors (8 total) - assembly_patterns: Circular/Rectangular/Mirror/PatternDriven/fill arrays - assembly_feature enhanced: assembly-level PMI propagation, batch interference check - 28 tests, compiled 0 errors (~2800 lines) v8.3 — 可视化+压缩+IGA+质量闭环: - visualization_quality: ambient_occlusion, edge_highlighting, wireframe, normals - topology_compression: Brep compression, Edgebreaker, vertex quantization - iga_prep: knot_insertion, degree_elevation, Bezier extraction for IGA analysis - quality_feedback: design_rule_check, manufacturability, cost_estimation, quality_score (0-100) - 28 tests, ~2349 lines 27 files, ~7750 lines, 76 tests
This commit is contained in:
@@ -7,3 +7,4 @@ add_vde_test(test_mesh_lod)
|
||||
add_vde_test(test_parallel_mc)
|
||||
add_vde_test(test_reverse_engineering)
|
||||
add_vde_test(test_fea_mesh)
|
||||
add_vde_test(test_visualization)
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "vde/mesh/visualization_quality.h"
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
|
||||
using namespace vde::mesh;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Helper: create a simple cube mesh
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
static std::vector<Point3D> cube_verts() {
|
||||
return {
|
||||
Point3D(0,0,0), Point3D(1,0,0), Point3D(1,1,0), Point3D(0,1,0),
|
||||
Point3D(0,0,1), Point3D(1,0,1), Point3D(1,1,1), Point3D(0,1,1)
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::array<int,3>> cube_tris() {
|
||||
return {
|
||||
{0,1,2}, {0,2,3}, // bottom
|
||||
{4,7,6}, {4,6,5}, // top
|
||||
{0,4,5}, {0,5,1}, // front
|
||||
{1,5,6}, {1,6,2}, // right
|
||||
{2,6,7}, {2,7,3}, // back
|
||||
{3,7,4}, {3,4,0}, // left
|
||||
};
|
||||
}
|
||||
|
||||
static HalfedgeMesh make_cube_mesh() {
|
||||
HalfedgeMesh mesh;
|
||||
mesh.build_from_triangles(cube_verts(), cube_tris());
|
||||
return mesh;
|
||||
}
|
||||
|
||||
static HalfedgeMesh make_tetrahedron_mesh() {
|
||||
std::vector<Point3D> verts = {
|
||||
Point3D(0,0,0), Point3D(1,0,0),
|
||||
Point3D(0.5,0.866,0), Point3D(0.5,0.289,0.816)
|
||||
};
|
||||
std::vector<std::array<int,3>> tris = {
|
||||
{0,1,2}, {0,3,1}, {1,3,2}, {2,3,0}
|
||||
};
|
||||
HalfedgeMesh mesh;
|
||||
mesh.build_from_triangles(verts, tris);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 环境光遮蔽测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(AmbientOcclusionTest, EmptyMesh) {
|
||||
HalfedgeMesh empty;
|
||||
auto result = ambient_occlusion(empty);
|
||||
EXPECT_EQ(result.vertex_ao.size(), 0u);
|
||||
EXPECT_EQ(result.avg_ao, 1.0);
|
||||
}
|
||||
|
||||
TEST(AmbientOcclusionTest, TetrahedronBasic) {
|
||||
auto mesh = make_tetrahedron_mesh();
|
||||
auto result = ambient_occlusion(mesh, 64);
|
||||
EXPECT_EQ(result.vertex_ao.size(), mesh.num_vertices());
|
||||
EXPECT_EQ(result.samples, 64);
|
||||
for (double ao : result.vertex_ao) {
|
||||
EXPECT_GE(ao, 0.0);
|
||||
EXPECT_LE(ao, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AmbientOcclusionTest, CubeAoBounds) {
|
||||
auto mesh = make_cube_mesh();
|
||||
auto result = ambient_occlusion(mesh, 128);
|
||||
EXPECT_LE(result.min_ao, result.avg_ao);
|
||||
EXPECT_GE(result.max_ao, result.avg_ao);
|
||||
EXPECT_GE(result.min_ao, 0.0);
|
||||
EXPECT_LE(result.max_ao, 1.0);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 边高亮测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(EdgeHighlightTest, EmptyMesh) {
|
||||
HalfedgeMesh empty;
|
||||
auto result = edge_highlighting(empty);
|
||||
EXPECT_EQ(result.total_edges, 0);
|
||||
EXPECT_EQ(result.hard_count, 0);
|
||||
}
|
||||
|
||||
TEST(EdgeHighlightTest, CubeNoHardEdges) {
|
||||
auto mesh = make_cube_mesh();
|
||||
// edges on a cube are flat → all dihedral angles = 90° (π/2)
|
||||
auto result = edge_highlighting(mesh, 1.2); // threshold > π/2
|
||||
EXPECT_GT(result.total_edges, 0);
|
||||
EXPECT_EQ(result.hard_count, 0);
|
||||
}
|
||||
|
||||
TEST(EdgeHighlightTest, CubeHardEdgesLowThreshold) {
|
||||
auto mesh = make_cube_mesh();
|
||||
auto result = edge_highlighting(mesh, 0.5236); // ~30°
|
||||
EXPECT_GT(result.total_edges, 0);
|
||||
EXPECT_GT(result.hard_count, 0);
|
||||
EXPECT_EQ(result.hard_count, result.total_edges);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 线框叠加测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(WireframeOverlayTest, TetrahedronWireframe) {
|
||||
auto mesh = make_tetrahedron_mesh();
|
||||
auto result = wireframe_overlay(mesh);
|
||||
EXPECT_EQ(result.vertices.size(), 4u);
|
||||
EXPECT_EQ(result.wire_edges.size(), 6u);
|
||||
}
|
||||
|
||||
TEST(WireframeOverlayTest, CubeWireframe) {
|
||||
auto mesh = make_cube_mesh();
|
||||
auto result = wireframe_overlay(mesh);
|
||||
EXPECT_EQ(result.vertices.size(), 8u);
|
||||
EXPECT_EQ(result.wire_edges.size(), 18u);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 法线可视化测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(NormalVisualizationTest, EmptyMesh) {
|
||||
HalfedgeMesh empty;
|
||||
auto result = normal_visualization(empty);
|
||||
EXPECT_EQ(result.face_centers.size(), 0u);
|
||||
EXPECT_EQ(result.face_normals.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(NormalVisualizationTest, TetrahedronNormals) {
|
||||
auto mesh = make_tetrahedron_mesh();
|
||||
auto result = normal_visualization(mesh);
|
||||
EXPECT_EQ(result.face_centers.size(), mesh.num_faces());
|
||||
EXPECT_EQ(result.face_normals.size(), mesh.num_faces());
|
||||
EXPECT_EQ(result.vertex_positions.size(), mesh.num_vertices());
|
||||
EXPECT_EQ(result.vertex_normals.size(), mesh.num_vertices());
|
||||
|
||||
for (const auto& n : result.face_normals) {
|
||||
EXPECT_NEAR(n.norm(), 1.0, 1e-9);
|
||||
}
|
||||
for (const auto& n : result.vertex_normals) {
|
||||
EXPECT_NEAR(n.norm(), 1.0, 1e-9);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NormalVisualizationTest, CubeNormals) {
|
||||
auto mesh = make_cube_mesh();
|
||||
auto result = normal_visualization(mesh);
|
||||
EXPECT_EQ(result.face_centers.size(), mesh.num_faces());
|
||||
EXPECT_EQ(result.face_normals.size(), mesh.num_faces());
|
||||
for (const auto& n : result.face_normals) {
|
||||
EXPECT_NEAR(n.norm(), 1.0, 1e-9);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user