feat: 测试覆盖扩展 + 文档更新
This commit is contained in:
@@ -1 +1,2 @@
|
||||
add_vde_test(test_bvh)
|
||||
add_vde_test(test_r_tree)
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "vde/spatial/r_tree.h"
|
||||
#include "vde/core/aabb.h"
|
||||
|
||||
using namespace vde::spatial;
|
||||
using namespace vde::core;
|
||||
|
||||
// A simple wrapper to satisfy the RTree template
|
||||
namespace {
|
||||
struct Point3DWithId {
|
||||
Point3D p;
|
||||
int id;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Instantiate the RTree for Point3D (items are point-based)
|
||||
// RTree stores items and computes their AABBs
|
||||
// For testing we use Point3D items directly
|
||||
|
||||
TEST(RTreeTest, BuildEmpty) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({});
|
||||
EXPECT_EQ(tree.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, BuildSinglePoint) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({Point3D(1, 2, 3)});
|
||||
EXPECT_EQ(tree.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, BuildAndRangeQuery) {
|
||||
RTree<Point3D> tree;
|
||||
std::vector<Point3D> points = {
|
||||
{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0},
|
||||
{5, 5, 0}, {6, 5, 0}, {5, 6, 0}, {6, 6, 0},
|
||||
};
|
||||
tree.build(points);
|
||||
|
||||
// Query: range covering the first cluster (0,0)-(2,2)
|
||||
AABB3D range(Point3D(-0.5, -0.5, -0.5), Point3D(2.5, 2.5, 0.5));
|
||||
auto results = tree.query_range(range);
|
||||
EXPECT_EQ(results.size(), 4u); // 4 points in first cluster
|
||||
}
|
||||
|
||||
TEST(RTreeTest, RangeQueryEmpty) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({Point3D(0, 0, 0), Point3D(1, 1, 1)});
|
||||
|
||||
AABB3D far(Point3D(10, 10, 10), Point3D(20, 20, 20));
|
||||
auto results = tree.query_range(far);
|
||||
EXPECT_TRUE(results.empty());
|
||||
}
|
||||
|
||||
TEST(RTreeTest, KNNQuery) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({
|
||||
{0, 0, 0}, {10, 0, 0}, {0, 10, 0}, {10, 10, 0},
|
||||
});
|
||||
|
||||
auto nearest = tree.query_knn(Point3D(1, 0, 0), 1);
|
||||
ASSERT_EQ(nearest.size(), 1u);
|
||||
EXPECT_NEAR(nearest[0].x(), 0.0, 1e-6);
|
||||
EXPECT_NEAR(nearest[0].y(), 0.0, 1e-6);
|
||||
|
||||
auto two_nearest = tree.query_knn(Point3D(0, 0, 0), 2);
|
||||
EXPECT_EQ(two_nearest.size(), 2u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, KNNQuery_MoreThanStored) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({Point3D(1, 2, 3), Point3D(4, 5, 6)});
|
||||
|
||||
auto results = tree.query_knn(Point3D(0, 0, 0), 10);
|
||||
EXPECT_EQ(results.size(), 2u); // Only 2 items stored
|
||||
}
|
||||
|
||||
TEST(RTreeTest, RayQuery) {
|
||||
RTree<Point3D> tree;
|
||||
std::vector<Point3D> points;
|
||||
for (int x = 0; x < 5; ++x)
|
||||
for (int y = 0; y < 5; ++y)
|
||||
points.push_back(Point3D(x, y, 0));
|
||||
tree.build(points);
|
||||
|
||||
// Ray along X-axis at y=0, z=0 should hit points with y≈0
|
||||
Ray3Dd ray(Point3D(-1, 0, 0), Vector3D(1, 0, 0));
|
||||
auto hits = tree.query_ray(ray);
|
||||
EXPECT_GT(hits.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, InsertAndRemove) {
|
||||
RTree<Point3D> tree;
|
||||
tree.insert(Point3D(0, 0, 0));
|
||||
EXPECT_EQ(tree.size(), 1u);
|
||||
|
||||
tree.insert(Point3D(1, 1, 1));
|
||||
EXPECT_EQ(tree.size(), 2u);
|
||||
|
||||
bool removed = tree.remove(Point3D(1, 1, 1));
|
||||
EXPECT_TRUE(removed);
|
||||
EXPECT_EQ(tree.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, RemoveNonExistent) {
|
||||
RTree<Point3D> tree;
|
||||
tree.insert(Point3D(0, 0, 0));
|
||||
bool removed = tree.remove(Point3D(9, 9, 9));
|
||||
EXPECT_FALSE(removed);
|
||||
EXPECT_EQ(tree.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(RTreeTest, Clear) {
|
||||
RTree<Point3D> tree;
|
||||
tree.build({
|
||||
{0, 0, 0}, {1, 0, 0}, {0, 1, 0},
|
||||
});
|
||||
EXPECT_EQ(tree.size(), 3u);
|
||||
|
||||
tree.clear();
|
||||
EXPECT_EQ(tree.size(), 0u);
|
||||
|
||||
// After clear, queries should return empty
|
||||
AABB3D all(Point3D(-1, -1, -1), Point3D(10, 10, 10));
|
||||
EXPECT_TRUE(tree.query_range(all).empty());
|
||||
}
|
||||
Reference in New Issue
Block a user