Add unit tests for Dynamic AABB tree
This commit is contained in:
parent
315c701f34
commit
59b237e992
|
@ -29,10 +29,53 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "Test.h"
|
#include "Test.h"
|
||||||
#include "collision/broadphase/DynamicAABBTree.h"
|
#include "collision/broadphase/DynamicAABBTree.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
/// Reactphysics3D namespace
|
/// Reactphysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
class OverlapCallback : public DynamicAABBTreeOverlapCallback {
|
||||||
|
|
||||||
|
public :
|
||||||
|
|
||||||
|
std::vector<int> mOverlapNodes;
|
||||||
|
|
||||||
|
// Called when a overlapping node has been found during the call to
|
||||||
|
// DynamicAABBTree:reportAllShapesOverlappingWithAABB()
|
||||||
|
virtual void notifyOverlappingNode(int nodeId) {
|
||||||
|
mOverlapNodes.push_back(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
mOverlapNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOverlapping(int nodeId) const {
|
||||||
|
return std::find(mOverlapNodes.begin(), mOverlapNodes.end(), nodeId) != mOverlapNodes.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DynamicTreeRaycastCallback : public DynamicAABBTreeRaycastCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::vector<int> mHitNodes;
|
||||||
|
|
||||||
|
// Called when the AABB of a leaf node is hit by a ray
|
||||||
|
virtual decimal raycastBroadPhaseShape(int32 nodeId, const Ray& ray) {
|
||||||
|
mHitNodes.push_back(nodeId);
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
mHitNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isHit(int nodeId) const {
|
||||||
|
return std::find(mHitNodes.begin(), mHitNodes.end(), nodeId) != mHitNodes.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Class TestDynamicAABBTree
|
// Class TestDynamicAABBTree
|
||||||
/**
|
/**
|
||||||
* Unit test for the dynamic AABB tree
|
* Unit test for the dynamic AABB tree
|
||||||
|
@ -46,19 +89,241 @@ class TestDynamicAABBTree : public Test {
|
||||||
// Dynamic AABB Tree
|
// Dynamic AABB Tree
|
||||||
DynamicAABBTree mTree;
|
DynamicAABBTree mTree;
|
||||||
|
|
||||||
|
AABB mAABB1;
|
||||||
|
AABB mAABB2;
|
||||||
|
AABB mAABB3;
|
||||||
|
AABB mAABB4;
|
||||||
|
|
||||||
|
OverlapCallback mOverlapCallback;
|
||||||
|
DynamicTreeRaycastCallback mRaycastCallback;
|
||||||
|
|
||||||
|
int mObject1Id;
|
||||||
|
int mObject2Id;
|
||||||
|
int mObject3Id;
|
||||||
|
int mObject4Id;
|
||||||
|
|
||||||
|
int mObject1Data = 56;
|
||||||
|
int mObject2Data = 23;
|
||||||
|
int mObject3Data = 13;
|
||||||
|
int mObject4Data = 7;
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// ---------- Methods ---------- //
|
// ---------- Methods ---------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
TestDynamicAABBTree(const std::string& name): Test(name) {}
|
TestDynamicAABBTree(const std::string& name): Test(name) {
|
||||||
|
|
||||||
|
// First object
|
||||||
|
mAABB1 = AABB(Vector3(-6, 4, -3), Vector3(4, 8, 3));
|
||||||
|
mObject1Id = mTree.addObject(mAABB1, &mObject1Data);
|
||||||
|
|
||||||
|
// Second object
|
||||||
|
mAABB2 = AABB(Vector3(5, 2, -3), Vector3(10, 7, 3));
|
||||||
|
mObject2Id = mTree.addObject(mAABB2, &mObject2Data);
|
||||||
|
|
||||||
|
// Third object
|
||||||
|
mAABB3 = AABB(Vector3(-5, 1, -3), Vector3(-2, 3, 3));
|
||||||
|
mObject3Id = mTree.addObject(mAABB3, &mObject3Data);
|
||||||
|
|
||||||
|
// Fourth object
|
||||||
|
mAABB4 = AABB(Vector3(0, -4, -3), Vector3(3, -2, 3));
|
||||||
|
mObject4Id = mTree.addObject(mAABB4, &mObject4Data);
|
||||||
|
}
|
||||||
|
|
||||||
/// Run the tests
|
/// Run the tests
|
||||||
void run() {
|
void run() {
|
||||||
|
|
||||||
// TODO : Implement tests here
|
testBasicsMethods();
|
||||||
|
testOverlapping();
|
||||||
|
testRaycast();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testBasicsMethods() {
|
||||||
|
|
||||||
|
// Test data stored at the nodes of the tree
|
||||||
|
test(*(int*)(mTree.getNodeDataPointer(mObject1Id)) == mObject1Data);
|
||||||
|
test(*(int*)(mTree.getNodeDataPointer(mObject2Id)) == mObject2Data);
|
||||||
|
test(*(int*)(mTree.getNodeDataPointer(mObject3Id)) == mObject3Data);
|
||||||
|
test(*(int*)(mTree.getNodeDataPointer(mObject4Id)) == mObject4Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testOverlapping() {
|
||||||
|
|
||||||
|
// AABB overlapping nothing
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-10, 12, -4), Vector3(10, 50, 4)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping everything
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-15, -15, -4), Vector3(15, 15, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 1 and 3
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-4, 2, -4), Vector3(-1, 7, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 3 and 4
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-6, -5, -2), Vector3(2, 2, 0)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 2
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(5, -10, -2), Vector3(7, 10, 9)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// ---- Update the object AABBs with the initial AABBs (no reinsertion) ----- //
|
||||||
|
|
||||||
|
mTree.updateObject(mObject1Id, mAABB1, Vector3::zero(), false);
|
||||||
|
mTree.updateObject(mObject2Id, mAABB2, Vector3::zero(), false);
|
||||||
|
mTree.updateObject(mObject3Id, mAABB3, Vector3::zero(), false);
|
||||||
|
mTree.updateObject(mObject4Id, mAABB4, Vector3::zero(), false);
|
||||||
|
|
||||||
|
// AABB overlapping nothing
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-10, 12, -4), Vector3(10, 50, 4)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping everything
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-15, -15, -4), Vector3(15, 15, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 1 and 3
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-4, 2, -4), Vector3(-1, 7, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 3 and 4
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-6, -5, -2), Vector3(2, 2, 0)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 2
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(5, -10, -2), Vector3(7, 10, 9)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// ---- Update the object AABBs with the initial AABBs (with reinsertion) ----- //
|
||||||
|
|
||||||
|
mTree.updateObject(mObject1Id, mAABB1, Vector3::zero(), true);
|
||||||
|
mTree.updateObject(mObject2Id, mAABB2, Vector3::zero(), true);
|
||||||
|
mTree.updateObject(mObject3Id, mAABB3, Vector3::zero(), true);
|
||||||
|
mTree.updateObject(mObject4Id, mAABB4, Vector3::zero(), true);
|
||||||
|
|
||||||
|
// AABB overlapping nothing
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-10, 12, -4), Vector3(10, 50, 4)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping everything
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-15, -15, -4), Vector3(15, 15, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 1 and 3
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-4, 2, -4), Vector3(-1, 7, 4)), mOverlapCallback);
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 3 and 4
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(-6, -5, -2), Vector3(2, 2, 0)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
|
||||||
|
// AABB overlapping object 2
|
||||||
|
mOverlapCallback.reset();
|
||||||
|
mTree.reportAllShapesOverlappingWithAABB(AABB(Vector3(5, -10, -2), Vector3(7, 10, 9)), mOverlapCallback);
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject1Id));
|
||||||
|
test(mOverlapCallback.isOverlapping(mObject2Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject3Id));
|
||||||
|
test(!mOverlapCallback.isOverlapping(mObject4Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRaycast() {
|
||||||
|
|
||||||
|
// Ray with no hits
|
||||||
|
mRaycastCallback.reset();
|
||||||
|
Ray ray1(Vector3(4.5, -10, -5), Vector3(4.5, 10, -5));
|
||||||
|
mTree.raycast(ray1, mRaycastCallback);
|
||||||
|
test(!mRaycastCallback.isHit(mObject1Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject2Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject3Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject4Id));
|
||||||
|
|
||||||
|
// Ray that hits object 1
|
||||||
|
mRaycastCallback.reset();
|
||||||
|
Ray ray2(Vector3(-1, -20, -2), Vector3(-1, 20, -2));
|
||||||
|
mTree.raycast(ray2, mRaycastCallback);
|
||||||
|
test(mRaycastCallback.isHit(mObject1Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject2Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject3Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject4Id));
|
||||||
|
|
||||||
|
// Ray that hits object 1 and 2
|
||||||
|
mRaycastCallback.reset();
|
||||||
|
Ray ray3(Vector3(-7, 6, -2), Vector3(8, 6, -2));
|
||||||
|
mTree.raycast(ray3, mRaycastCallback);
|
||||||
|
test(mRaycastCallback.isHit(mObject1Id));
|
||||||
|
test(mRaycastCallback.isHit(mObject2Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject3Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject4Id));
|
||||||
|
|
||||||
|
// Ray that hits object 3
|
||||||
|
mRaycastCallback.reset();
|
||||||
|
Ray ray4(Vector3(-7, 2, 0), Vector3(-1, 2, 0));
|
||||||
|
mTree.raycast(ray4, mRaycastCallback);
|
||||||
|
test(!mRaycastCallback.isHit(mObject1Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject2Id));
|
||||||
|
test(mRaycastCallback.isHit(mObject3Id));
|
||||||
|
test(!mRaycastCallback.isHit(mObject4Id));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user