From b0ab03bb37641934b2381b9a1eaa6ea05b1a92d8 Mon Sep 17 00:00:00 2001 From: Erik Broberg Date: Tue, 5 Apr 2016 19:14:50 -0400 Subject: [PATCH] Added ChunkNode class --- modules/globebrowsing/CMakeLists.txt | 22 +++--- .../{quadtree.h => chunknode.h} | 61 ++++++++++++++-- .../{quadtree.cpp => chunknode.inl} | 71 ++++++++++++++++++- tests/main.cpp | 2 +- .../{test_quadtree.inl => test_chunknode.inl} | 40 +++++++++-- 5 files changed, 171 insertions(+), 25 deletions(-) rename modules/globebrowsing/datastructures/{quadtree.h => chunknode.h} (74%) rename modules/globebrowsing/datastructures/{quadtree.cpp => chunknode.inl} (53%) rename tests/{test_quadtree.inl => test_chunknode.inl} (62%) diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 692ed65599..67e7f01350 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -25,13 +25,15 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableglobe.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/distanceswitch.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/geometry.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gridgeometry.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/globemesh.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableglobe.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/distanceswitch.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/geometry.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gridgeometry.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/globemesh.h + + ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/chunknode.h + ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/chunknode.inl - ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/quadtree.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -42,7 +44,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gridgeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/globemesh.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/quadtree.cpp + ) source_group("Source Files" FILES ${SOURCE_FILES}) @@ -52,7 +54,7 @@ set(SHADER_FILES source_group("Shader Files" FILES ${SHADER_FILES}) create_new_module( - "GlobeBrowsing" - globebrowsing_module - ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} + "GlobeBrowsing" + globebrowsing_module + ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) diff --git a/modules/globebrowsing/datastructures/quadtree.h b/modules/globebrowsing/datastructures/chunknode.h similarity index 74% rename from modules/globebrowsing/datastructures/quadtree.h rename to modules/globebrowsing/datastructures/chunknode.h index 0b23c92f68..4563d4e16c 100644 --- a/modules/globebrowsing/datastructures/quadtree.h +++ b/modules/globebrowsing/datastructures/chunknode.h @@ -25,16 +25,67 @@ #ifndef __QUADTREE_H__ #define __QUADTREE_H__ +#include +#include +#include +#include + +// Using double precision +typedef double Scalar; +typedef glm::dvec2 Vec2; namespace openspace { -class Quadtree { -public: - Quadtree(); - - +enum Quad { + NORTH_WEST, + NORTH_EAST, + SOUTH_WEST, + SOUTH_EAST }; + + +struct BoundingRect { + BoundingRect(Scalar, Scalar, Scalar, Scalar); + BoundingRect(const Vec2& center, const Vec2& halfSize); + Vec2 center; + Vec2 halfSize; +}; + + + + + +class ChunkNode { +public: + ChunkNode(const BoundingRect&, ChunkNode* parent = nullptr); + ~ChunkNode(); + + + void split(); + void merge(); + + bool isRoot() const; + bool isLeaf() const; + + + const ChunkNode& getChild(Quad quad) const; + const BoundingRect bounds; + +private: + + + ChunkNode* _parent; + std::unique_ptr _children[4]; + +}; + + + } // namespace openspace + +#include + + #endif // __QUADTREE_H__ diff --git a/modules/globebrowsing/datastructures/quadtree.cpp b/modules/globebrowsing/datastructures/chunknode.inl similarity index 53% rename from modules/globebrowsing/datastructures/quadtree.cpp rename to modules/globebrowsing/datastructures/chunknode.inl index c93951c40d..fe1e5abce3 100644 --- a/modules/globebrowsing/datastructures/quadtree.cpp +++ b/modules/globebrowsing/datastructures/chunknode.inl @@ -22,13 +22,78 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include + namespace openspace { -Quadtree::Quadtree() { +BoundingRect::BoundingRect(Scalar cx, Scalar cy, Scalar hsx, Scalar hsy) + : center(Vec2(cx, cy)), halfSize(Vec2(hsx, hsy)) { } +BoundingRect::BoundingRect(const Vec2& center, const Vec2& halfSize) + :center(center), halfSize(halfSize) { } + + + + +ChunkNode::ChunkNode(const BoundingRect& bounds, ChunkNode* parent) +: bounds(bounds), _parent(parent) +{ + _children[0] = nullptr; + _children[1] = nullptr; + _children[2] = nullptr; + _children[3] = nullptr; +} + +ChunkNode::~ChunkNode() { + +} + +bool ChunkNode::isRoot() const { + return _parent == nullptr; +} + +bool ChunkNode::isLeaf() const { + return _children[0] == nullptr; } -} // namespace openspace \ No newline at end of file +void ChunkNode::split() { + // Defining short handles for center, halfSize and quarterSize + const Vec2& c = bounds.center; + const Vec2& hs =bounds.halfSize; + Vec2 qs = 0.5 * bounds.halfSize; + + // Subdivide bounds + BoundingRect nwBounds = BoundingRect(c + Vec2(-qs.x, -qs.y), qs); + BoundingRect neBounds = BoundingRect(c + Vec2(+qs.x, -qs.y), qs); + BoundingRect swBounds = BoundingRect(c + Vec2(-qs.x, +qs.y), qs); + BoundingRect seBounds = BoundingRect(c + Vec2(+qs.x, +qs.y), qs); + + // Create new chunk nodes + _children[Quad::NORTH_WEST] = std::unique_ptr(new ChunkNode(nwBounds, this)); + _children[Quad::NORTH_EAST] = std::unique_ptr(new ChunkNode(neBounds, this)); + _children[Quad::SOUTH_WEST] = std::unique_ptr(new ChunkNode(swBounds, this)); + _children[Quad::SOUTH_EAST] = std::unique_ptr(new ChunkNode(seBounds, this)); +} + + +void ChunkNode::merge() { + for (int i = 0; i < 4; ++i) { + if (_children[i] != nullptr) { + _children[i]->merge(); + } + _children[i] = nullptr; + } +} + + +const ChunkNode& ChunkNode::getChild(Quad quad) const { + return *_children[quad]; +} + + + + + +} // namespace openspace diff --git a/tests/main.cpp b/tests/main.cpp index 1a53c80947..cd9815caee 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -33,7 +33,7 @@ #include //#include //#include -#include +#include //#include //#include #include diff --git a/tests/test_quadtree.inl b/tests/test_chunknode.inl similarity index 62% rename from tests/test_quadtree.inl rename to tests/test_chunknode.inl index df8960b6d4..e5e87ef7f7 100644 --- a/tests/test_quadtree.inl +++ b/tests/test_chunknode.inl @@ -25,16 +25,44 @@ #include "gtest/gtest.h" #include -#include +#include #include - -class QuadtreeTest : public testing::Test {}; +#include using namespace openspace; -TEST_F(QuadtreeTest, ConstructorTest) { - Quadtree t; - EXPECT_TRUE(&t != nullptr) << "Quadtree was constructed"; +class ChunkNodeTest : public testing::Test {}; + +TEST_F(ChunkNodeTest, Split) { + BoundingRect bounds(Vec2(2, 2), Vec2(2, 2)); + auto cn = std::shared_ptr(new ChunkNode(bounds)); + ASSERT_TRUE(cn->isRoot()) << "Chunk node is root"; + ASSERT_TRUE(cn->isLeaf()) << "Chunk node is leaf"; + + cn->split(); + ASSERT_TRUE(cn->isRoot()) << "Chunk node is root"; + ASSERT_FALSE(cn->isLeaf()) << "Chunk node is not leaf"; + + ASSERT_EQ(cn->bounds.center.x, cn->getChild(Quad::NORTH_WEST).bounds.center.x * 2); + ASSERT_EQ(cn->bounds.center.x, cn->getChild(Quad::NORTH_EAST).bounds.center.x * 2/3); + + ASSERT_EQ(cn->bounds.halfSize.x, cn->getChild(Quad::NORTH_WEST).bounds.halfSize.x * 2); + ASSERT_EQ(cn->bounds.halfSize.y, cn->getChild(Quad::NORTH_WEST).bounds.halfSize.y * 2); } +TEST_F(ChunkNodeTest, Merge) { + BoundingRect bounds(Vec2(2, 2), Vec2(2, 2)); + ChunkNode cn(bounds); + ASSERT_TRUE(cn.isRoot()) << "Chunk node is root"; + ASSERT_TRUE(cn.isLeaf()) << "Chunk node is leaf"; + + cn.split(); + ASSERT_TRUE(cn.isRoot()) << "Chunk node is root"; + ASSERT_FALSE(cn.isLeaf()) << "Chunk node is not leaf"; + + cn.merge(); + ASSERT_TRUE(cn.isRoot()) << "Chunk node is root"; + ASSERT_TRUE(cn.isLeaf()) << "Chunk node is leaf"; + +} \ No newline at end of file