Files
ViewDesignEngine/tests/brep/test_incremental_mesh.cpp
茂之钳 a5facc84f6
Build & Test / build-and-test (push) Waiting to run
Build & Test / python-bindings (push) Blocked by required conditions
CI / Build & Test (push) Failing after 48s
CI / Release Build (push) Failing after 31s
feat(v4.5): add tests + CMake integration for all 3 new modules
Tests (48 new test cases total):
- test_draft_analysis.cpp: 18 tests (draft angle, classification, report, distribution)
- test_incremental_mesh.cpp: 15 tests (rebuild, invalidate, cache, merge, memory)
- test_kinematic_chain.cpp: 27 tests (Grashof, Freudenstein, gear ratio, 5 cam motions)

Build system:
- src/CMakeLists.txt: +draft_analysis, +incremental_mesh, +kinematic_chain
- tests/brep/CMakeLists.txt: +3 new test targets

Docs:
- 剩余路线图: v4.5 → 🚧
2026-07-26 17:14:03 +08:00

184 lines
6.1 KiB
C++

#include <gtest/gtest.h>
#include "vde/brep/brep.h"
#include "vde/brep/modeling.h"
#include "vde/brep/incremental_mesh.h"
#include <cmath>
using namespace vde::brep;
using namespace vde::core;
// ═══════════════════════════════════════════════════════════
// Basic Operations
// ═══════════════════════════════════════════════════════════
TEST(IncrementalMeshTest, EmptyMesher) {
IncrementalMesher mesher;
EXPECT_EQ(mesher.dirty_count(), 0);
EXPECT_EQ(mesher.total_faces(), 0);
EXPECT_EQ(mesher.hit_rate(), 0.0);
EXPECT_EQ(mesher.memory_estimate(), 0u);
}
TEST(IncrementalMeshTest, RebuildAll_UnitBox) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
int count = mesher.rebuild_all(box, 0.01);
EXPECT_GT(count, 0);
EXPECT_EQ(mesher.dirty_count(), 0);
}
TEST(IncrementalMeshTest, RebuildAll_Cylinder) {
auto cyl = make_cylinder(2, 6, 32);
IncrementalMesher mesher;
int count = mesher.rebuild_all(cyl);
EXPECT_GT(count, 0);
}
// ═══════════════════════════════════════════════════════════
// Invalidate & Incremental Rebuild
// ═══════════════════════════════════════════════════════════
TEST(IncrementalMeshTest, InvalidateFace_MarksDirty) {
IncrementalMesher mesher;
mesher.invalidate_face(0);
EXPECT_EQ(mesher.dirty_count(), 1);
}
TEST(IncrementalMeshTest, InvalidateFace_ThenRebuild) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
// Full rebuild first
mesher.rebuild_all(box);
// Invalidate one face
mesher.invalidate_face(0);
EXPECT_EQ(mesher.dirty_count(), 1);
// Rebuild only dirty
int count = mesher.rebuild_dirty(box);
EXPECT_GT(count, 0);
EXPECT_EQ(mesher.dirty_count(), 0);
}
TEST(IncrementalMeshTest, RebuildDirty_Empty) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
// No faces marked dirty → rebuild_dirty should do nothing
int count = mesher.rebuild_dirty(box);
EXPECT_EQ(count, 0);
}
TEST(IncrementalMeshTest, MultipleInvalidates) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
mesher.invalidate_face(0);
mesher.invalidate_face(1);
mesher.invalidate_face(0); // duplicate — should still be 2 dirty
EXPECT_EQ(mesher.dirty_count(), 2);
int count = mesher.rebuild_dirty(box);
EXPECT_GE(count, 2);
EXPECT_EQ(mesher.dirty_count(), 0);
}
// ═══════════════════════════════════════════════════════════
// Cache
// ═══════════════════════════════════════════════════════════
TEST(IncrementalMeshTest, GetMesh_AfterRebuild) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
const auto* mesh = mesher.get_mesh(0);
EXPECT_TRUE(mesh != nullptr);
EXPECT_GT(mesher.cache_hits(), 0);
}
TEST(IncrementalMeshTest, GetMesh_AfterInvalidate) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
mesher.invalidate_face(0);
const auto* mesh = mesher.get_mesh(0);
EXPECT_TRUE(mesh == nullptr); // dirty face → cache miss
EXPECT_GT(mesher.cache_misses(), 0);
}
TEST(IncrementalMeshTest, GetMesh_InvalidFaceId) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
const auto* mesh = mesher.get_mesh(999);
EXPECT_TRUE(mesh == nullptr);
}
TEST(IncrementalMeshTest, HitRate_AfterRebuild) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
// Access a cached mesh → hit
mesher.get_mesh(0);
EXPECT_GT(mesher.hit_rate(), 0.0);
}
// ═══════════════════════════════════════════════════════════
// Merged Mesh
// ═══════════════════════════════════════════════════════════
TEST(IncrementalMeshTest, MergedMesh_AfterFullRebuild) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
auto merged = mesher.merged_mesh();
EXPECT_GT(merged.num_vertices(), 0u);
EXPECT_GT(merged.num_faces(), 0u);
}
TEST(IncrementalMeshTest, MergedMesh_AfterPartialInvalidate) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
// Invalidate one face → merged mesh should miss it
mesher.invalidate_face(0);
auto merged = mesher.merged_mesh();
// Still should produce a valid (but partial) mesh
EXPECT_GE(merged.num_vertices(), 0u);
}
// ═══════════════════════════════════════════════════════════
// Clear & Memory
// ═══════════════════════════════════════════════════════════
TEST(IncrementalMeshTest, ClearAll) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
EXPECT_GT(mesher.total_faces(), 0);
mesher.clear_all();
EXPECT_EQ(mesher.total_faces(), 0);
EXPECT_EQ(mesher.dirty_count(), 0);
EXPECT_EQ(mesher.hit_rate(), 0.0);
}
TEST(IncrementalMeshTest, MemoryEstimate) {
auto box = make_box(2, 2, 2);
IncrementalMesher mesher;
mesher.rebuild_all(box);
size_t mem = mesher.memory_estimate();
EXPECT_GT(mem, 0u);
}