From d9522e40bec9704aabc2955419a280b0a94a7534 Mon Sep 17 00:00:00 2001 From: dmatetelki Date: Fri, 15 Apr 2016 15:23:09 +0200 Subject: [PATCH] Quadtree finished --- lib/graph/quad_tree.hpp | 28 ++-------- test/graph/test_quad_tree.cpp | 96 +++++++++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 33 deletions(-) diff --git a/lib/graph/quad_tree.hpp b/lib/graph/quad_tree.hpp index 2d0a3bc..b95f980 100644 --- a/lib/graph/quad_tree.hpp +++ b/lib/graph/quad_tree.hpp @@ -4,7 +4,7 @@ #include #include // move #include -#include // abs +#include // std::fabs // From wikipedia: http://en.wikipedia.org/wiki/Quadtree#Pseudo_code @@ -32,31 +32,13 @@ struct AABB , m_halfDimension(halfDimension) {} bool containsPoint(const P& p) const { - return p.x >= m_center.x - m_halfDimension && - p.x <= m_center.x + m_halfDimension && - p.y >= m_center.y - m_halfDimension && - p.y <= m_center.y + m_halfDimension; - -// return (abs(p.x - m_center.x) <= m_halfDimension) && -// (abs(p.y - m_center.y) <= m_halfDimension); - + return (std::fabs(m_center.x - p.x) <= m_halfDimension) && + (std::fabs(m_center.y - p.y) <= m_halfDimension); } bool intersectsAABB(const AABB& other) const { -// return containsPoint(P(other.m_center.x - other.m_halfDimension, other.m_center.y - other.m_halfDimension)) || -// containsPoint(P(other.m_center.x - other.m_halfDimension, other.m_center.y + other.m_halfDimension)) || -// containsPoint(P(other.m_center.x + other.m_halfDimension, other.m_center.y - other.m_halfDimension)) || -// containsPoint(P(other.m_center.x + other.m_halfDimension, other.m_center.y + other.m_halfDimension)); - -// return (abs(m_center.x - other.m_center.x) <= m_halfDimension + other.m_halfDimension) && -// (abs(m_center.y - other.m_center.y) <= m_halfDimension + other.m_halfDimension); - -// return dist(m_center, other.m_center) < m_halfDimension + other.m_halfDimension; - - return other.m_center.x + other.m_center.x >= m_center.x - m_halfDimension && - other.m_center.x - other.m_center.x <= m_center.x + m_halfDimension && - other.m_center.y + other.m_center.y >= m_center.y - m_halfDimension && - other.m_center.y - other.m_center.y <= m_center.y + m_halfDimension; + return (std::fabs(m_center.x - other.m_center.x) <= m_halfDimension + other.m_halfDimension) && + (std::fabs(m_center.y - other.m_center.y) <= m_halfDimension + other.m_halfDimension); } }; diff --git a/test/graph/test_quad_tree.cpp b/test/graph/test_quad_tree.cpp index 26cebb6..9530d03 100644 --- a/test/graph/test_quad_tree.cpp +++ b/test/graph/test_quad_tree.cpp @@ -4,7 +4,85 @@ #include "fixture.hpp" +#include +TEST_CASE( "Quad tree, AABB", "[quad_tree][data_structure][AABB]" ) { + + const float2 center(0, 0); + constexpr float halfDimension(10); + const AABB boundary(center, halfDimension); + + SECTION("containsPoint in") { + REQUIRE ( boundary.containsPoint(center) == true ); + + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension, center.y)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension, center.y)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y - halfDimension)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y + halfDimension)) == true ); + + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension, center.y - halfDimension)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension, center.y + halfDimension)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension, center.y - halfDimension)) == true ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension, center.y + halfDimension)) == true ); + } + + SECTION("containsPoint out") { + constexpr float halfDimension_1 = halfDimension + 1.0; + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y + halfDimension_1)) == false ); + + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y + halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y + halfDimension_1)) == false ); + } + + SECTION("containsPoint invalid") { + + constexpr float halfDimension_1 = halfDimension + 1.0; + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x, center.y + halfDimension_1)) == false ); + + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x - halfDimension_1, center.y + halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y - halfDimension_1)) == false ); + REQUIRE ( boundary.containsPoint(float2(center.x + halfDimension_1, center.y + halfDimension_1)) == false ); + } + + SECTION("intersectsAABB") { + + constexpr float halfDimension_1 = halfDimension + 1.0; + REQUIRE( boundary.intersectsAABB(AABB(center, 1.0)) == true); + REQUIRE( boundary.intersectsAABB(AABB(center, halfDimension)) == true); + REQUIRE( boundary.intersectsAABB(AABB(center, halfDimension_1)) == true); + + const float2 center2(center.x + halfDimension, center.y); + REQUIRE( boundary.intersectsAABB(AABB(center2, 0.0)) == true); + REQUIRE( boundary.intersectsAABB(AABB(center2, halfDimension)) == true); + REQUIRE( boundary.intersectsAABB(AABB(center2, halfDimension_1)) == true); + + const float2 center3(center.x + halfDimension * 2, center.y); + REQUIRE( boundary.intersectsAABB(AABB(center3, 0.0)) == false); + REQUIRE( boundary.intersectsAABB(AABB(center3, halfDimension)) == true); + REQUIRE( boundary.intersectsAABB(AABB(center3, halfDimension_1)) == true); + + const float2 center4(center.x + halfDimension_1 * 2, center.y); + REQUIRE( boundary.intersectsAABB(AABB(center4, 0.0)) == false); + REQUIRE( boundary.intersectsAABB(AABB(center4, halfDimension)) == false); + REQUIRE( boundary.intersectsAABB(AABB(center4, halfDimension_1)) == false); + } + + SECTION("special") { + + // std::fabs instead of std::abs, which would turn float->int + const AABB boundary2(float2(-3.75, -8.75), 1.25); + REQUIRE( boundary2.containsPoint(float2(-2, -8)) == false); + } +} TEST_CASE( "Quad tree", "[quad_tree][data_structure]" ) { @@ -82,10 +160,10 @@ TEST_CASE( "Quad tree", "[quad_tree][data_structure]" ) { const float2 topLeft(-halfDimension, -halfDimension); const std::vector points = t.queryRange(AABB(topLeft, halfDimension/2)); - REQUIRE ( points.size() == 25); - for (int c = -halfDimension; c < halfDimension/2; ++c) - for (int r = -halfDimension; r < halfDimension/2; ++r) - REQUIRE ( std::find(points.begin(), points.end(), float2(r, c)) != points.end() ); + REQUIRE ( points.size() == 36); + for (int c = -halfDimension; c < -halfDimension/2; ++c) + for (int r = -halfDimension; r < -halfDimension/2; ++r) + REQUIRE ( std::find(points.begin(), points.end(), float2(center.x + r, center.y + c)) != points.end() ); } SECTION("Query many points inside") { @@ -93,13 +171,11 @@ TEST_CASE( "Quad tree", "[quad_tree][data_structure]" ) { for (int r = -halfDimension; r < halfDimension; ++r) REQUIRE ( t.insert(float2(center.x + r, center.y + c)) == true ); - const float2 right(0, halfDimension/2); + const float2 right(halfDimension/2, 0); const std::vector points = t.queryRange(AABB(right, halfDimension/4)); - REQUIRE ( points.size() == 25); - const float2 range_topleft(halfDimension/4, -halfDimension/4); - for (int c = 0; c < halfDimension/2; ++c) - for (int r = 0; r < halfDimension/2; ++r) - REQUIRE ( std::find(points.begin(), points.end(), float2(range_topleft.x + r, range_topleft.y + c)) != points.end() ); + for (int c = -halfDimension/4; c < halfDimension/4; ++c) + for (int r = std::ceil(halfDimension/4); r < halfDimension*0.75; ++r) + REQUIRE ( std::find(points.begin(), points.end(), float2(center.x + r, center.y + c)) != points.end() ); } }