├── tests ├── .clang-format ├── util.hpp ├── treeList.cpp ├── highDim.cpp ├── CMakeLists.txt ├── largeData.cpp ├── badData.cpp ├── nearestNeighbour.cpp ├── basics.cpp ├── baddata.txt └── memory.cpp ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md └── RTree.h /tests/.clang-format: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.out 3 | out/ 4 | build/ 5 | .vscode 6 | -------------------------------------------------------------------------------- /tests/util.hpp: -------------------------------------------------------------------------------- 1 | template 2 | struct RectTemplate { 3 | RectTemplate() {} 4 | 5 | RectTemplate(CoordType a_minX, CoordType a_minY, CoordType a_maxX, CoordType a_maxY) { 6 | min[0] = a_minX; 7 | min[1] = a_minY; 8 | 9 | max[0] = a_maxX; 10 | max[1] = a_maxY; 11 | } 12 | 13 | bool operator==(const RectTemplate &o) const { 14 | return min[0] == o.min[0] && min[1] == o.min[1] && max[0] == o.max[0] && 15 | max[1] == o.max[1]; 16 | } 17 | 18 | CoordType min[2]; 19 | CoordType max[2]; 20 | }; -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(RTree) 4 | 5 | add_library(RTree INTERFACE) 6 | target_include_directories(RTree INTERFACE RTree.h) 7 | 8 | option(ENABLE_TESTING ON) 9 | 10 | if (ENABLE_TESTING) 11 | # GoogleTest requires at least C++14 12 | set(CMAKE_CXX_STANDARD 14) 13 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 14 | 15 | include(FetchContent) 16 | FetchContent_Declare( 17 | googletest 18 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip 19 | DOWNLOAD_EXTRACT_TIMESTAMP false 20 | ) 21 | # For Windows: Prevent overriding the parent project's compiler/linker settings 22 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 23 | FetchContent_MakeAvailable(googletest) 24 | 25 | enable_testing() 26 | 27 | add_subdirectory(tests) 28 | endif() -------------------------------------------------------------------------------- /tests/treeList.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include "util.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace ::testing; 10 | 11 | typedef int ValueType; 12 | 13 | typedef RectTemplate Rect; 14 | 15 | Rect rects[] = { 16 | Rect(0, 0, 0, 0), Rect(1, 1, 1, 1), Rect(2, 2, 2, 2), Rect(3, 3, 3, 3), 17 | Rect(4, 4, 4, 4), Rect(5, 5, 5, 5), Rect(6, 6, 6, 6), Rect(7, 7, 7, 7), 18 | Rect(8, 8, 8, 8), Rect(9, 9, 9, 9), 19 | }; 20 | 21 | int nrects = sizeof(rects) / sizeof(rects[0]); 22 | 23 | TEST(TreeList, TreeList) { 24 | typedef RTree MyTree; 25 | MyTree tree; 26 | 27 | for (int i = 0; i < nrects; i++) { 28 | tree.Insert(rects[i].min, rects[i].max, i); 29 | } 30 | 31 | auto list = tree.ListTree(); 32 | 33 | // there are at least nrects internal rectangles, because we use at most 4 34 | // items per node 35 | EXPECT_GT(list.size(), nrects); 36 | } 37 | -------------------------------------------------------------------------------- /tests/highDim.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include "util.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::random_device rd; 10 | std::mt19937 gen(rd()); 11 | std::uniform_real_distribution<> range(0, 1); 12 | 13 | class RectND 14 | { 15 | public: 16 | RectND(int n) 17 | { 18 | for (int i = 0; i < n; i++) 19 | { 20 | m_min.push_back(range(gen)); 21 | m_max.push_back(range(gen)); 22 | } 23 | } 24 | 25 | std::vector m_min, m_max; 26 | }; 27 | 28 | using namespace ::testing; 29 | 30 | TEST(HighDim, HighDim) { 31 | constexpr uint NDIM = 100; 32 | typedef RTree MyTree; 33 | MyTree tree; 34 | 35 | int nrects = 1000; 36 | 37 | for (int i = 0; i < nrects; i++) { 38 | const RectND rect(NDIM); 39 | tree.Insert(rect.m_min.data(), rect.m_max.data(), i); 40 | } 41 | 42 | MyTree::Iterator it; 43 | int counter = 0; 44 | for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) { 45 | counter++; 46 | } 47 | 48 | ASSERT_EQ(counter, nrects); 49 | } 50 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic") 2 | 3 | add_executable( 4 | basics 5 | basics.cpp 6 | ) 7 | target_link_libraries( 8 | basics 9 | GTest::gtest_main 10 | GTest::gmock_main 11 | ) 12 | 13 | add_executable( 14 | memory 15 | memory.cpp 16 | ) 17 | target_link_libraries( 18 | memory 19 | GTest::gtest_main 20 | GTest::gmock_main 21 | ) 22 | 23 | # copy bad data input file to build folder 24 | configure_file(baddata.txt baddata.txt COPYONLY) 25 | add_executable( 26 | badData 27 | badData.cpp 28 | ) 29 | target_link_libraries( 30 | badData 31 | GTest::gtest_main 32 | GTest::gmock_main 33 | ) 34 | 35 | add_executable( 36 | largeData 37 | largeData.cpp 38 | ) 39 | target_link_libraries( 40 | largeData 41 | GTest::gtest_main 42 | GTest::gmock_main 43 | ) 44 | 45 | add_executable( 46 | treeList 47 | treeList.cpp 48 | ) 49 | target_link_libraries( 50 | treeList 51 | GTest::gtest_main 52 | GTest::gmock_main 53 | ) 54 | 55 | add_executable( 56 | nearestNeighbour 57 | nearestNeighbour.cpp 58 | ) 59 | target_link_libraries( 60 | nearestNeighbour 61 | GTest::gtest_main 62 | GTest::gmock_main 63 | ) 64 | 65 | add_executable( 66 | highDim 67 | highDim.cpp 68 | ) 69 | target_link_libraries( 70 | highDim 71 | GTest::gtest_main 72 | GTest::gmock_main 73 | ) 74 | 75 | include(GoogleTest) 76 | gtest_discover_tests(basics) 77 | gtest_discover_tests(memory) 78 | gtest_discover_tests(badData) 79 | gtest_discover_tests(largeData) 80 | gtest_discover_tests(treeList) 81 | gtest_discover_tests(nearestNeighbour) 82 | gtest_discover_tests(highDim) 83 | 84 | -------------------------------------------------------------------------------- /tests/largeData.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include "util.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace ::testing; 8 | 9 | typedef RectTemplate Rect; 10 | 11 | Rect rects1[] = 12 | { 13 | Rect(-165504234584830402149438989055033344.0f,0,0,0), 14 | Rect(0,0,0,0), 15 | Rect(0,0,0,-169601184587181609658320132097645215744.0f), 16 | Rect(-171755845806606337562467320443512553472.0f,0.000002f,-162256731624492592649732817688723456.0f,-171751221417216704981610660470219341824.0f), 17 | Rect(0,576601489791778816.0f,0,0), 18 | Rect(0,0.000007f,0,0), 19 | Rect(-4482491441084523606684867353378816.0f,0,0,0), 20 | Rect(0,0,0,-43227275904167492885693240287908855808.0f), 21 | Rect(-169908473233881734291078144928254001152.0f,0,0,-148873525386705775939391178777772949504.0f), 22 | }; 23 | 24 | Rect rects2[] = 25 | { 26 | Rect(-0.000487f,311158685411645789022377876652032.0f,0,0), 27 | Rect(-151115727451828646838272.0f,0,0,0), 28 | Rect(0,36893488147419103232.0f,0,0), 29 | Rect(0,0,36893488147419103232.0f,0), 30 | Rect(-107374176.0f,-36639756.0f,310688732424232076535519296618496.0f,0), 31 | Rect(-228296904656229410799616.0f,0,0,0), 32 | Rect(0,0,0,0), 33 | Rect(-326268824195173847682390548625982750720.0,0,311840674316413350549446522306560.0f,0), 34 | Rect(-0.453835f,303590248839277909200780151226368.0f,12.07855f,0), 35 | }; 36 | 37 | TEST(LargeData, LargeData) { 38 | RTree tree; 39 | 40 | int data = 0; 41 | for (auto rect : rects1) { 42 | tree.Insert(rect.min, rect.max, data++); 43 | } 44 | for (auto rect : rects2) { 45 | tree.Insert(rect.min, rect.max, data++); 46 | } 47 | 48 | SUCCEED(); 49 | } 50 | -------------------------------------------------------------------------------- /tests/badData.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include "util.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace ::testing; 13 | 14 | typedef int ValueType; 15 | typedef long long CoordType; 16 | 17 | typedef RectTemplate Rect; 18 | 19 | TEST(BadDataTest, BadData) { 20 | typedef std::vector RectVector; 21 | RectVector rects; 22 | std::vector values; 23 | 24 | // read the data 25 | { 26 | std::ifstream inFile("baddata.txt"); 27 | while (!inFile.eof()) { 28 | // security and robustness be damned 29 | CoordType xmin, ymin, xmax, ymax; 30 | std::string dummy; 31 | inFile >> xmin >> ymin >> xmax >> ymax; 32 | rects.push_back(Rect(xmin, ymin, xmin + xmax, ymin + ymax)); 33 | } 34 | } 35 | 36 | EXPECT_EQ(rects.size(), 174); 37 | 38 | typedef RTree MyTree; 39 | MyTree tree; 40 | 41 | unsigned int nhits; 42 | 43 | for (unsigned int i = 0; i < rects.size(); i++) { 44 | tree.Insert(rects[i].min, rects[i].max, i); 45 | values.push_back(i); 46 | } 47 | 48 | MockFunction mock_function; 49 | ON_CALL(mock_function, Call).WillByDefault(Return(true)); 50 | EXPECT_CALL(mock_function, Call(_)).Times(0); 51 | 52 | Rect search_rect(6, 4, 10, 6); 53 | nhits = tree.Search(search_rect.min, search_rect.max, mock_function.AsStdFunction()); 54 | 55 | EXPECT_EQ(nhits, 0); 56 | 57 | std::vector collectedRects = std::vector(); 58 | std::vector collectedValues = std::vector(); 59 | 60 | // Iterator test 61 | MyTree::Iterator it; 62 | for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) { 63 | int value = tree.GetAt(it); 64 | 65 | CoordType boundsMin[2] = {0, 0}; 66 | CoordType boundsMax[2] = {0, 0}; 67 | it.GetBounds(boundsMin, boundsMax); 68 | collectedRects.push_back( 69 | Rect(boundsMin[0], boundsMin[1], boundsMax[0], boundsMax[1])); 70 | collectedValues.push_back(value); 71 | } 72 | 73 | EXPECT_THAT(rects, UnorderedElementsAreArray(collectedRects)); 74 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 75 | collectedValues.clear(); 76 | 77 | // Iterator test, alternate syntax 78 | tree.GetFirst(it); 79 | while (!it.IsNull()) { 80 | CoordType value = *it; 81 | ++it; 82 | collectedValues.push_back(value); 83 | } 84 | 85 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 86 | } 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The RTree library's source code, including accompanying documentation, 2 | tests and demonstration applications, are licensed under the following 3 | conditions: 4 | 5 | The author (Yariv Barkan) explicitly disclaims copyright in all 6 | jurisdictions which recognize such a disclaimer. In such jurisdictions, 7 | this software is released into the Public Domain. 8 | 9 | In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 10 | 2024), this software is Copyright (c) 2011-2024 by Yariv Barkan, and is 11 | released under the terms of the MIT License (see below). 12 | 13 | In jurisdictions which recognize Public Domain property, the user of this 14 | software may choose to accept it either as 1) Public Domain, 2) under the 15 | conditions of the MIT License (see below), or 3) under the terms of dual 16 | Public Domain/MIT License conditions described here, as they choose. 17 | 18 | The MIT License is about as close to Public Domain as a license can get, and is 19 | described in clear, concise terms at: 20 | 21 | https://choosealicense.com/licenses/mit/ 22 | 23 | The full text of the MIT License follows: 24 | 25 | ======================================================================== 26 | Copyright (c) 2024 Yariv Barkan 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in all 36 | copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 44 | SOFTWARE. 45 | 46 | ======================================================================== 47 | (END LICENSE TEXT) 48 | 49 | The MIT license is compatible with both the GPL and commercial 50 | software, affording one all of the rights of Public Domain with the 51 | minor nuisance of being required to keep the above copyright notice 52 | and license text in the source code. Note also that by accepting the 53 | Public Domain "license" you can re-license your copy using whatever 54 | license you like. 55 | 56 | -------------------------------------------------------------------------------- /tests/nearestNeighbour.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace ::testing; 9 | 10 | struct Rect { 11 | Rect(double a_minX, double a_minY, double a_maxX, double a_maxY) 12 | : id(Rect::max_id++) { 13 | min[0] = a_minX; 14 | min[1] = a_minY; 15 | 16 | max[0] = a_maxX; 17 | max[1] = a_maxY; 18 | } 19 | 20 | static size_t max_id; 21 | size_t id; 22 | double min[2]; 23 | double max[2]; 24 | }; 25 | 26 | size_t Rect::max_id = 0; 27 | 28 | std::array rects{ 29 | // xmin, ymin, xmax, ymax 30 | Rect(0.0, 0.0, 2.0, 1.0), Rect(5.0, 5.0, 7.0, 7.0), 31 | Rect(8.0, 5.0, 9.0, 6.0), Rect(7.0, 1.0, 9.0, 2.0), 32 | Rect(4.0, 5.0, 5.0, 6.0), 33 | }; 34 | 35 | /// 36 | /// Tests that a nearest neighbor works with a flat tree 37 | /// 38 | /// 39 | /// maxNodes is larger than the number of rects. This 40 | /// ensures that the root node can fit all the entries. 41 | /// Therefore, the tree only has a single layer 42 | /// 43 | TEST(NearestNeighbour, FlatTree) { 44 | int constexpr maxNodes = 8; 45 | RTree tree; 46 | 47 | for (auto &r : rects) { 48 | tree.Insert(r.min, r.max, &r); 49 | } 50 | 51 | std::vector order; 52 | 53 | double x_min[2] = {4.0, 3.0}; 54 | double x_max[2] = {4.0, 3.0}; 55 | 56 | auto count = tree.NNSearch(x_min, x_max, [&order](Rect *r, double) { 57 | order.push_back(r->id); 58 | return true; 59 | }); 60 | 61 | EXPECT_EQ(rects.size(), count); 62 | EXPECT_EQ(rects[4].id, order[0]); 63 | EXPECT_EQ(rects[1].id, order[1]); 64 | EXPECT_EQ(rects[0].id, order[2]); 65 | EXPECT_EQ(rects[3].id, order[3]); 66 | EXPECT_EQ(rects[2].id, order[4]); 67 | } 68 | 69 | /// 70 | /// Tests that a nearest neighbor works with a deep tree 71 | /// 72 | /// 73 | /// maxNodes is smaller than the number of rects. This 74 | /// ensures that the root node cannot fit all the entries. 75 | /// Therefore, the tree must have multiple layers. 76 | /// 77 | TEST(NearestNeighbour, DeepTree) { 78 | int constexpr maxNodes = 2; 79 | RTree tree; 80 | 81 | for (auto &r : rects) { 82 | tree.Insert(r.min, r.max, &r); 83 | } 84 | 85 | std::vector order; 86 | 87 | double x_min[2] = {4.0, 3.0}; 88 | double x_max[2] = {4.0, 3.0}; 89 | 90 | auto count = tree.NNSearch(x_min, x_max, [&order](Rect *r, double) { 91 | order.push_back(r->id); 92 | return true; 93 | }); 94 | 95 | EXPECT_EQ(rects.size(), count); 96 | EXPECT_EQ(rects[4].id, order[0]); 97 | EXPECT_EQ(rects[1].id, order[1]); 98 | EXPECT_EQ(rects[0].id, order[2]); 99 | EXPECT_EQ(rects[3].id, order[3]); 100 | EXPECT_EQ(rects[2].id, order[4]); 101 | } 102 | 103 | /// 104 | /// Verifies that the search can be stopped after a 105 | /// fixed number of results are found 106 | /// 107 | TEST(NearestNeighbour, MaxNumberOfHits) { 108 | RTree tree; 109 | size_t constexpr maxHits = 2; 110 | 111 | for (auto &r : rects) { 112 | tree.Insert(r.min, r.max, &r); 113 | } 114 | 115 | std::vector order; 116 | 117 | double x_min[2] = {4.0, 3.0}; 118 | double x_max[2] = {4.0, 3.0}; 119 | 120 | auto count = tree.NNSearch(x_min, x_max, [&order](Rect *r, double) { 121 | order.push_back(r->id); 122 | return order.size() < maxHits; 123 | }); 124 | 125 | EXPECT_EQ(maxHits, count); 126 | } -------------------------------------------------------------------------------- /tests/basics.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include "util.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace ::testing; 11 | 12 | typedef int ValueType; 13 | 14 | typedef RectTemplate Rect; 15 | 16 | const std::vector rects = { 17 | Rect(0, 0, 2, 2), // xmin, ymin, xmax, ymax (for 2 dimensional RTree) 18 | Rect(5, 5, 7, 7), 19 | Rect(8, 5, 9, 6), 20 | Rect(7, 1, 9, 2), 21 | }; 22 | 23 | const std::vector values = {0, 2, 3, 5}; 24 | 25 | int nrects = rects.size(); 26 | 27 | Rect search_rect(6, 4, 10, 28 | 6); // search will find above rects that this one overlaps 29 | 30 | TEST(BasicTests, BasicTests) { 31 | typedef RTree MyTree; 32 | MyTree tree; 33 | 34 | int i, nhits; 35 | 36 | for (i = 0; i < nrects; i++) { 37 | tree.Insert( 38 | rects[i].min, rects[i].max, 39 | values[i]); // Note, all values including zero are fine in this version 40 | } 41 | 42 | MockFunction mock_function; 43 | ON_CALL(mock_function, Call).WillByDefault(Return(true)); 44 | EXPECT_CALL(mock_function, Call(_)).Times(2); 45 | 46 | nhits = tree.Search(search_rect.min, search_rect.max, 47 | mock_function.AsStdFunction()); 48 | 49 | ASSERT_EQ(nhits, 2); 50 | 51 | std::vector collectedRects = std::vector(); 52 | std::vector collectedValues = std::vector(); 53 | 54 | // Iterator test 55 | MyTree::Iterator it; 56 | for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) { 57 | int value = tree.GetAt(it); 58 | 59 | int boundsMin[2] = {0, 0}; 60 | int boundsMax[2] = {0, 0}; 61 | it.GetBounds(boundsMin, boundsMax); 62 | collectedRects.push_back( 63 | Rect(boundsMin[0], boundsMin[1], boundsMax[0], boundsMax[1])); 64 | collectedValues.push_back(value); 65 | } 66 | 67 | EXPECT_THAT(rects, UnorderedElementsAreArray(collectedRects)); 68 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 69 | collectedValues.clear(); 70 | 71 | 72 | // Iterator test, alternate syntax 73 | tree.GetFirst(it); 74 | while (!it.IsNull()) { 75 | int value = *it; 76 | ++it; 77 | collectedValues.push_back(value); 78 | } 79 | 80 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 81 | 82 | // test copy constructor 83 | MyTree copy = tree; 84 | 85 | collectedRects.clear(); 86 | collectedValues.clear(); 87 | 88 | // Iterator test 89 | for (copy.GetFirst(it); !copy.IsNull(it); copy.GetNext(it)) { 90 | int value = copy.GetAt(it); 91 | 92 | int boundsMin[2] = {0, 0}; 93 | int boundsMax[2] = {0, 0}; 94 | it.GetBounds(boundsMin, boundsMax); 95 | collectedRects.push_back( 96 | Rect(boundsMin[0], boundsMin[1], boundsMax[0], boundsMax[1])); 97 | collectedValues.push_back(value); 98 | } 99 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 100 | 101 | EXPECT_THAT(rects, UnorderedElementsAreArray(collectedRects)); 102 | 103 | collectedValues.clear(); 104 | 105 | // Iterator test, alternate syntax 106 | copy.GetFirst(it); 107 | while (!it.IsNull()) { 108 | int value = *it; 109 | ++it; 110 | collectedValues.push_back(value); 111 | } 112 | 113 | EXPECT_THAT(values, UnorderedElementsAreArray(collectedValues)); 114 | } 115 | 116 | 117 | TEST(BasicTests, RemoveTests) { 118 | typedef RTree MyTree; 119 | MyTree tree; 120 | 121 | std::vector v; 122 | 123 | for (size_t i = 0; i < 1000; i++) { 124 | const Rect rect(i, i, i, i); 125 | tree.Insert(rect.min, rect.max, i); 126 | v.push_back(i); 127 | } 128 | 129 | for (size_t i = 0; i < v.size(); i++) { 130 | tree.Remove(v.back()); 131 | 132 | std::vector collectedValues = std::vector(); 133 | MyTree::Iterator it; 134 | tree.GetFirst(it); 135 | 136 | while (!it.IsNull()) { 137 | int value = *it; 138 | ++it; 139 | collectedValues.push_back(value); 140 | } 141 | 142 | v.pop_back(); 143 | 144 | ASSERT_EQ(v.size(), collectedValues.size()); 145 | EXPECT_THAT(v, UnorderedElementsAreArray(collectedValues)); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # R-Trees: A Dynamic Index Structure for Spatial Searching 2 | 3 | ## Description 4 | 5 | A C++ templated version of [this](http://www.superliminal.com/sources/sources.htm) 6 | RTree algorithm. 7 | The code it now generally compatible with the STL and Boost C++ libraries. 8 | 9 | ## Usage 10 | 11 | Include `RTree.h`. This library is header-only. 12 | 13 | ### Inserting 14 | 15 | ```cpp 16 | #include "RTree.h" 17 | typedef RTree MyTree; 18 | 19 | MyTree tree; 20 | double min[3] = {0., 0., 0.}; 21 | double max[3] = {1., 1., 1.}; 22 | Foo* bar = new Foo(); 23 | tree.Insert(min, max, bar); 24 | ``` 25 | 26 | ### Searching 27 | 28 | ```cpp 29 | bool MySearchCallback(Foo* value) 30 | { 31 | // do something with `value`, then 32 | // return `true` to keep going, return `false` to stop 33 | return true; 34 | } 35 | 36 | // search inside [0,0,0] and [1,1,1], execute callback on each hit 37 | double min[3] = {0., 0., 0.}; 38 | double max[3] = {1., 1., 1.}; 39 | int nhits = tree.Search(min, max, MySearchCallback); 40 | ``` 41 | 42 | ### Iterating 43 | 44 | ```cpp 45 | MyTree::Iterator it; 46 | for(tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) 47 | { 48 | Foo* value = tree.GetAt(it); 49 | 50 | double boundsMin[3] = {0., 0., 0.}; 51 | double boundsMax[3] = {0., 0., 0.}; 52 | // save bounds into boundsMin/Max 53 | it.GetBounds(boundsMin, boundsMax); 54 | cout << boundsMin[0] << "," << boundsMin[1] << "," << boundsMin[2] << "," 55 | << boundsMax[0] << "," << boundsMax[1] << "," << boundsMax[2] << ")\n"; 56 | } 57 | ``` 58 | 59 | or 60 | 61 | ```cpp 62 | MyTree::Iterator it; 63 | tree.GetFirst(it); 64 | while(!it.IsNull()) 65 | { 66 | Foo* value = *it; 67 | ++it; 68 | } 69 | ``` 70 | 71 | 72 | Listing all boxes in the tree, including the parent boxes that were not inserted 73 | but form the RTree internally: 74 | 75 | ```cpp 76 | auto list = tree.ListTree(); 77 | int counter = 0; 78 | for (auto aabb : list) { 79 | cout << "TreeList [" << counter++ << "]: " 80 | << aabb.m_min[0] << ", " 81 | << aabb.m_min[1] << ", " 82 | << aabb.m_min[2] << "; " 83 | << aabb.m_max[0] << ", " 84 | << aabb.m_max[1] << ", " 85 | << aabb.m_max[2] << endl; 86 | } 87 | ``` 88 | 89 | 90 | For working examples see 91 | [the tests](https://github.com/nushoin/RTree/blob/master/tests). 92 | 93 | ## Testing 94 | 95 | This uses CMake, which download GTest. 96 | 97 | ```bash 98 | mkdir build 99 | cd build 100 | cmake -DENABLE_TESTING=ON .. 101 | make 102 | make test 103 | 104 | # or 105 | 106 | cmake -DENABLE_TESTING=ON -S . -B build 107 | cmake --build build 108 | cd build 109 | ctest 110 | ``` 111 | 112 | Or use the IDE of your choice (tested with VSCode) and run the tests. 113 | 114 | The RTree itself is a single header file and can be included without compiling. 115 | 116 | ## Authors 117 | 118 | - 1983 Original algorithm and test code by Antonin Guttman and Michael Stonebraker, UC Berkely 119 | - 1994 ANCI C ported from original test code by Melinda Green - melinda@superliminal.com 120 | - 1995 Sphere volume fix for degeneracy problem submitted by Paul Brook 121 | - 2004 Templated C++ port by Greg Douglas 122 | - 2011 Modified the container to support more data types, by Yariv Barkan 123 | - 2017 Modified Search to take C++11 function to allow lambdas and added const qualifier, by Gero Mueller 124 | 125 | ## License 126 | 127 | Original code was taken from http://www.superliminal.com/sources/sources.htm 128 | and is stored as git revision 0. This revision is entirely free for all 129 | uses. Enjoy! 130 | 131 | Due to restrictions on public domain in certain jurisdictions, code 132 | contributed by Yariv Barkan is released in these jurisdictions under the 133 | BSD, MIT or the GPL - you may choose one or more, whichever that suits you 134 | best. 135 | 136 | In jurisdictions where public domain property is recognized, the user of 137 | this software may choose to accept it either 1) as public domain, 2) under 138 | the conditions of the BSD, MIT or GPL or 3) any combination of public 139 | domain and one or more of these licenses. 140 | 141 | Thanks [Baptiste Lepilleur](http://jsoncpp.sourceforge.net/LICENSE) for the 142 | licensing idea. 143 | 144 | ## Recent Change Log 145 | 146 | ### 31 Jan 2018 147 | 148 | - Added copy constructor 149 | - Callback function is now `std::function` 150 | 151 | ### 05 Apr 2014 152 | 153 | - Added tests 154 | 155 | ### 02 Sep 2011 156 | 157 | - Modified the container to support more data types. The code it now generally 158 | compatible with the STL and Boost C++ libraries. 159 | 160 | ### 05 Jan 2010 161 | 162 | - Fixed Iterator GetFirst() - Previous fix was not incomplete 163 | 164 | ### 03 Dec 2009 165 | 166 | - Added Iteartor GetBounds() 167 | - Added Iterator usage to simple test 168 | - Fixed Iterator GetFirst() - Thanks Mathew Riek 169 | - Minor updates for MSVC 2005/08 compilers 170 | -------------------------------------------------------------------------------- /tests/baddata.txt: -------------------------------------------------------------------------------- 1 | 20041225182812 20041225182812 32743 32743 2 | 20050120182105 20050120182105 32743 32743 3 | 20050120181004 20050120181004 32743 32743 4 | 20050120185604 20050120185604 32743 32743 5 | 20050120191706 20050120192143 32743 32743 6 | 20050129054438 20050129054455 32743 32743 7 | 20050125004242 20050127004348 32743 32743 8 | 20050127080821 20050127080821 32743 32743 9 | 20050103232047 20050103232047 32743 32743 10 | 20050103231608 20050103231953 32743 32743 11 | 20050103232124 20050103233547 32743 32743 12 | 20050103234758 20050103234758 32743 32743 13 | 20050113072936 20050113072936 32743 32743 14 | 20050105014304 20050111225505 32743 32743 15 | 20050117025915 20050118054001 32743 32743 16 | 20050118064200 20050119020157 32743 32743 17 | 20041225182812 20041225182812 32743 32743 18 | 20041225182812 20041225182812 32743 32743 19 | 20041231081821 20041231081821 32743 32743 20 | 20041231084441 20050101210045 32743 32743 21 | 20041231053402 20041231053402 32743 32743 22 | 20041227225557 20041228062229 32743 32743 23 | 20041227003512 20041227003512 32743 32743 24 | 20041227004805 20041227074924 32743 32743 25 | 20041227080309 20041227080309 32743 32743 26 | 20041227075241 20041227075241 32743 32743 27 | 20041227000445 20041227000931 32743 32743 28 | 20041227003006 20041227003006 32743 32743 29 | 20050120181004 20050120182105 32743 32743 30 | 20050120183502 20050120183502 32743 32743 31 | 20050101213828 20050113072936 32743 32743 32 | 20050117025915 20050119020157 32743 32743 33 | 20050119201652 20050120105309 32743 32743 34 | 20050120185604 20050120185604 32743 32743 35 | 20050120191706 20050120192143 32743 32743 36 | 20050129054438 20050130172429 32743 32743 37 | 20050125004242 20050127004348 32743 32743 38 | 20050127080821 20050127080821 32743 32743 39 | 20041225182812 20041225182812 32743 32743 40 | 20041225182812 20041225182812 32743 32743 41 | 20050120182105 20050120182105 32743 32743 42 | 20050120181004 20050120181004 32743 32743 43 | 20050120185604 20050120185604 32743 32743 44 | 20050120191706 20050120192143 32743 32743 45 | 20050129054438 20050129054455 32743 32743 46 | 20050125004242 20050127004348 32743 32743 47 | 20050127080821 20050127080821 32743 32743 48 | 20050103232047 20050103232047 32743 32743 49 | 20050103231608 20050103231953 32743 32743 50 | 20050103232124 20050103233547 32743 32743 51 | 20050103234758 20050103234758 32743 32743 52 | 20050113072936 20050113072936 32743 32743 53 | 20050105014304 20050111225505 32743 32743 54 | 20050117025915 20050118054001 32743 32743 55 | 20050118064200 20050119020157 32743 32743 56 | 20041225182812 20041225182812 32743 32743 57 | 20041225182812 20041225182812 32743 32743 58 | 20041227000445 20041227080309 32743 32743 59 | 20041227225557 20050102160402 32743 32743 60 | 20050103024822 20050113072936 32743 32743 61 | 20050117025915 20050119020157 32743 32743 62 | 20050120073145 20050120181004 32743 32743 63 | 20050120182105 20050120182105 32743 32743 64 | 20050120185604 20050120192143 32743 32743 65 | 20050125004242 20050130172429 32743 32743 66 | 20041227225454 20041227225454 32743 32743 67 | 20050119201652 20050119201652 32743 32743 68 | 20050120183502 20050120183502 32743 32743 69 | 20050120212256 20050120212256 32743 32743 70 | 20050122001605 20050122001605 32743 32743 71 | 20050120182105 20050120182105 32743 32743 72 | 20050120181004 20050120181004 32743 32743 73 | 20050120185604 20050120185604 32743 32743 74 | 20050120191706 20050120192143 32743 32743 75 | 20050129054438 20050130172429 32743 32743 76 | 20050125004242 20050127004348 32743 32743 77 | 20050127080821 20050127080821 32743 32743 78 | 20041231081821 20050101210045 32743 32743 79 | 20041227225557 20041231053402 32743 32743 80 | 20041227003512 20041227074924 32743 32743 81 | 20041227075241 20041227080309 32743 32743 82 | 20041227003340 20041227003340 32743 32743 83 | 20041227000445 20041227003006 32743 32743 84 | 20050103224855 20050103234758 32743 32743 85 | 20050105014304 20050113072936 32743 32743 86 | 20050117025915 20050119020157 32743 32743 87 | 20050101213828 20050101213828 32743 32743 88 | 20050102160402 20050102160402 32743 32743 89 | 20050103024822 20050103025321 32743 32743 90 | 20041225182812 20041225182812 32743 32743 91 | 20050120105309 20050120105309 32743 32743 92 | 20050120073145 20050120073145 32743 32743 93 | 20041225182812 20041225182812 32743 32743 94 | 20050103232124 20050103232503 32743 32743 95 | 20050103232710 20050103232710 32743 32743 96 | 20050105034455 20050106034834 32743 32743 97 | 20050106215124 20050111225505 32743 32743 98 | 20050106035210 20050106035210 32743 32743 99 | 20050117213917 20050118025128 32743 32743 100 | 20050118025641 20050118025641 32743 32743 101 | 20050118065543 20050118065543 32743 32743 102 | 20050119020157 20050119020157 32743 32743 103 | 20050118064200 20050118064200 32743 32743 104 | 20050118064228 20050118064228 32743 32743 105 | 20050120181004 20050120182105 32743 32743 106 | 20050120185604 20050120192143 32743 32743 107 | 20050125004242 20050129054455 32743 32743 108 | 20041225182812 20041225182812 32743 32743 109 | 20041225182812 20041225182812 32743 32743 110 | 20041225182812 20041225182812 32743 32743 111 | 20041225182812 20041225182812 32743 32743 112 | 20050120182105 20050120182105 32743 32743 113 | 20050120181004 20050120181004 32743 32743 114 | 20050120185604 20050120185604 32743 32743 115 | 20050120191706 20050120192143 32743 32743 116 | 20050129054438 20050129054455 32743 32743 117 | 20050125004242 20050127004348 32743 32743 118 | 20050127080821 20050127080821 32743 32743 119 | 20050103232047 20050103232047 32743 32743 120 | 20050103231608 20050103231953 32743 32743 121 | 20050103232124 20050103233547 32743 32743 122 | 20050103234758 20050103234758 32743 32743 123 | 20050113072936 20050113072936 32743 32743 124 | 20050105014304 20050111225505 32743 32743 125 | 20050117025915 20050118054001 32743 32743 126 | 20050118064200 20050119020157 32743 32743 127 | 20041225182812 20041225182812 32743 32743 128 | 20041225182812 20041225182812 32743 32743 129 | 20050120191706 20050120191706 32743 32743 130 | 20050120192143 20050120192143 32743 32743 131 | 20050129054438 20050129054438 32743 32743 132 | 20050129054455 20050130172429 32743 32743 133 | 20050125004242 20050125035134 32743 32743 134 | 20050126112156 20050127004348 32743 32743 135 | 20041227225454 20050101210045 32743 32743 136 | 20041227000445 20041227080309 32743 32743 137 | 20050101213828 20050101213828 32743 32743 138 | 20050102160402 20050102160402 32743 32743 139 | 20050103224855 20050113072936 32743 32743 140 | 20050117025915 20050119020157 32743 32743 141 | 20050103024822 20050103025321 32743 32743 142 | 20050119201652 20050119201652 32743 32743 143 | 20050120073145 20050120105309 32743 32743 144 | 20041225182812 20041225182812 32743 32743 145 | 20041225182812 20041225182812 32743 32743 146 | 20050120191706 20050120191706 32743 32743 147 | 20050120192143 20050120192143 32743 32743 148 | 20050129054438 20050129054438 32743 32743 149 | 20050129054455 20050130172429 32743 32743 150 | 20050125004242 20050125035134 32743 32743 151 | 20050126112156 20050127004348 32743 32743 152 | 20041227225454 20050101210045 32743 32743 153 | 20041227000445 20041227080309 32743 32743 154 | 20050101213828 20050101213828 32743 32743 155 | 20050102160402 20050102160402 32743 32743 156 | 20050103224855 20050113072936 32743 32743 157 | 20050117025915 20050119020157 32743 32743 158 | 20050103024822 20050103025321 32743 32743 159 | 20050119201652 20050119201652 32743 32743 160 | 20050120073145 20050120105309 32743 32743 161 | 20041225182812 20041225182812 32743 32743 162 | 20041225182812 20041225182812 32743 32743 163 | 20050120191706 20050120191706 32743 32743 164 | 20050120192143 20050120192143 32743 32743 165 | 20050129054438 20050129054438 32743 32743 166 | 20050129054455 20050130172429 32743 32743 167 | 20050125004242 20050125035134 32743 32743 168 | 20050126112156 20050127004348 32743 32743 169 | 20041227225454 20050101210045 32743 32743 170 | 20041227000445 20041227080309 32743 32743 171 | 20050101213828 20050101213828 32743 32743 172 | 20050102160402 20050102160402 32743 32743 173 | 20050103224855 20050113072936 32743 32743 174 | 20050117025915 20050119020157 32743 32743 -------------------------------------------------------------------------------- /tests/memory.cpp: -------------------------------------------------------------------------------- 1 | #include "../RTree.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #ifdef WIN32 9 | #include 10 | #endif // WIN32 11 | 12 | using namespace ::testing; 13 | 14 | // Use CRT Debug facility to dump memory leaks on app exit 15 | #ifdef WIN32 16 | // These two are for MSVS 2005 security consciousness until safe std lib funcs 17 | // are available 18 | #pragma warning(disable : 4996) // Deprecated functions 19 | #define _CRT_SECURE_NO_DEPRECATE // Allow old unsecure standard library 20 | // functions, Disable some 'warning C4996 - 21 | // function was deprecated' 22 | 23 | // The following macros set and clear, respectively, given bits 24 | // of the C runtime library debug flag, as specified by a bitmask. 25 | #ifdef _DEBUG 26 | #define SET_CRT_DEBUG_FIELD(a) \ 27 | _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) 28 | #define CLEAR_CRT_DEBUG_FIELD(a) \ 29 | _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) 30 | #else 31 | #define SET_CRT_DEBUG_FIELD(a) ((void)0) 32 | #define CLEAR_CRT_DEBUG_FIELD(a) ((void)0) 33 | #endif 34 | #endif // WIN32 35 | 36 | // 37 | // Get a random float b/n two values 38 | // The returned value is >= min && < max (exclusive of max) 39 | // Note this is a low precision random value since it is generated from an int. 40 | // 41 | static float RandFloat(float a_min, float a_max) { 42 | const float ooMax = 1.0f / (float)RAND_MAX; 43 | 44 | float retValue = ((float)rand() * ooMax * (a_max - a_min) + a_min); 45 | 46 | RTREE_ASSERT(retValue >= a_min && retValue < a_max); // Paranoid check 47 | 48 | return retValue; 49 | } 50 | 51 | /// Simplify handling of 3 dimensional coordinate 52 | struct Vec3 { 53 | /// Default constructor 54 | Vec3() {} 55 | 56 | /// Construct from three elements 57 | Vec3(float a_x, float a_y, float a_z) { 58 | v[0] = a_x; 59 | v[1] = a_y; 60 | v[2] = a_z; 61 | } 62 | 63 | /// Add two vectors and return result 64 | Vec3 operator+(const Vec3 &a_other) const { 65 | return Vec3(v[0] + a_other.v[0], v[1] + a_other.v[1], v[2] + a_other.v[2]); 66 | } 67 | 68 | float v[3]; ///< 3 float components for axes or dimensions 69 | }; 70 | 71 | static bool BoxesIntersect(const Vec3 &a_boxMinA, const Vec3 &a_boxMaxA, 72 | const Vec3 &a_boxMinB, const Vec3 &a_boxMaxB) { 73 | for (int axis = 0; axis < 3; ++axis) { 74 | if (a_boxMinA.v[axis] > a_boxMaxB.v[axis] || 75 | a_boxMaxA.v[axis] < a_boxMinB.v[axis]) { 76 | return false; 77 | } 78 | } 79 | return true; 80 | } 81 | 82 | /// A user type to test with, instead of a simple type such as an 'int' 83 | struct SomeThing { 84 | SomeThing() { ++s_outstandingAllocs; } 85 | ~SomeThing() { --s_outstandingAllocs; } 86 | 87 | int m_creationCounter; ///< Just a number for identifying within test program 88 | Vec3 m_min, m_max; ///< Minimal bounding rect, values must be known and 89 | ///< constant in order to remove from RTree 90 | 91 | static int s_outstandingAllocs; ///< Count how many outstanding objects remain 92 | }; 93 | 94 | /// Init static 95 | int SomeThing::s_outstandingAllocs = 0; 96 | 97 | TEST(MemoryTest, NoLeak) { 98 | // Number of objects in test set, must be > FRAC_OBJECTS for this test 99 | const int NUM_OBJECTS = 40; 100 | const int FRAC_OBJECTS = 4; 101 | const float MAX_WORLDSIZE = 10.0f; 102 | const float FRAC_WORLDSIZE = MAX_WORLDSIZE / 2; 103 | 104 | // typedef the RTree useage just for conveniance with iteration 105 | typedef RTree SomeThingTree; 106 | 107 | EXPECT_GT(NUM_OBJECTS, FRAC_OBJECTS); 108 | 109 | int index; // general purpose counter, declared here because MSVC 6 is not 110 | // ansi compliant with 'for' loops. 111 | SomeThing 112 | *thingArray[NUM_OBJECTS * 2]; // Store objects in another container to 113 | // test with, sized larger than we need 114 | 115 | memset(thingArray, 0, 116 | sizeof(thingArray)); // Nullify array, size is known here 117 | 118 | // Create intance of RTree 119 | SomeThingTree tree; 120 | 121 | // Add some nodes 122 | int counter = 0; 123 | for (index = 0; index < NUM_OBJECTS; ++index) { 124 | SomeThing *newThing = new SomeThing; 125 | 126 | newThing->m_creationCounter = counter++; 127 | newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), 128 | RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), 129 | RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE)); 130 | Vec3 extent = 131 | Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), 132 | RandFloat(0, FRAC_WORLDSIZE)); 133 | newThing->m_max = newThing->m_min + extent; 134 | 135 | thingArray[counter - 1] = newThing; 136 | 137 | tree.Insert(newThing->m_min.v, newThing->m_max.v, newThing); 138 | } 139 | 140 | EXPECT_EQ(tree.Count(), NUM_OBJECTS); 141 | 142 | int numToDelete = NUM_OBJECTS / FRAC_OBJECTS; 143 | int numToStep = FRAC_OBJECTS; 144 | 145 | // Delete some nodes 146 | for (index = 0; index < NUM_OBJECTS; index += numToStep) { 147 | SomeThing *curThing = thingArray[index]; 148 | 149 | if (curThing) { 150 | tree.Remove(curThing->m_min.v, curThing->m_max.v, curThing); 151 | 152 | delete curThing; 153 | thingArray[index] = NULL; 154 | } 155 | } 156 | 157 | EXPECT_EQ(tree.Count(), NUM_OBJECTS - numToDelete); 158 | 159 | // Add some more nodes 160 | for (index = 0; index < numToDelete; ++index) { 161 | SomeThing *newThing = new SomeThing; 162 | 163 | newThing->m_creationCounter = counter++; 164 | newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), 165 | RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), 166 | RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE)); 167 | Vec3 extent = 168 | Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), 169 | RandFloat(0, FRAC_WORLDSIZE)); 170 | newThing->m_max = newThing->m_min + extent; 171 | 172 | thingArray[counter - 1] = newThing; 173 | 174 | tree.Insert(newThing->m_min.v, newThing->m_max.v, newThing); 175 | } 176 | 177 | EXPECT_EQ(tree.Count(), NUM_OBJECTS); 178 | 179 | MockFunction mock_function; 180 | ON_CALL(mock_function, Call).WillByDefault(Return(true)); 181 | EXPECT_CALL(mock_function, Call(_)).Times(tree.Count()); 182 | 183 | Vec3 searchMin(-MAX_WORLDSIZE, -MAX_WORLDSIZE, -MAX_WORLDSIZE); 184 | Vec3 searchMax(MAX_WORLDSIZE, MAX_WORLDSIZE, MAX_WORLDSIZE); 185 | tree.Search(searchMin.v, searchMax.v, mock_function.AsStdFunction()); 186 | 187 | // List values. Iterator is NOT delete safe 188 | int findCounter = 0; 189 | SomeThingTree::Iterator it; 190 | for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) { 191 | SomeThing *curThing = tree.GetAt(it); 192 | 193 | if (BoxesIntersect(searchMin, searchMax, curThing->m_min, 194 | curThing->m_max)) { 195 | findCounter++; 196 | } 197 | } 198 | 199 | EXPECT_EQ(tree.Count(), findCounter); 200 | 201 | // Delete our nodes, NOTE, we are NOT deleting the tree nodes, just our data 202 | // of course the tree will now contain invalid pointers that must not be used 203 | // any more. 204 | for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it)) { 205 | SomeThing *removeElem = tree.GetAt(it); 206 | if (removeElem) { 207 | delete removeElem; 208 | } 209 | } 210 | 211 | // Remove all contents (This would have happened automatically during 212 | // destructor) 213 | tree.RemoveAll(); 214 | 215 | if (SomeThing::s_outstandingAllocs > 0) { 216 | FAIL() << "Memory leak! " 217 | << "s_outstandingAllocs = " << SomeThing::s_outstandingAllocs; 218 | } 219 | 220 | #ifdef WIN32 221 | // Use CRT Debug facility to dump memory leaks on app exit 222 | SET_CRT_DEBUG_FIELD(_CRTDBG_LEAK_CHECK_DF); 223 | #endif // WIN32 224 | } 225 | -------------------------------------------------------------------------------- /RTree.h: -------------------------------------------------------------------------------- 1 | #ifndef RTREE_H 2 | #define RTREE_H 3 | 4 | // NOTE This file compiles under MSVC 6 SP5 and MSVC .Net 2003 it may not work on other compilers without modification. 5 | 6 | // NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define RTREE_ASSERT assert // RTree uses RTREE_ASSERT( condition ) 19 | #ifdef Min 20 | #define RTREE_MIN Min 21 | #else 22 | #define RTREE_MIN std::min 23 | #endif //Min 24 | #ifdef Max 25 | #define RTREE_MAX Max 26 | #else 27 | #define RTREE_MAX std::max 28 | #endif //Max 29 | 30 | // 31 | // RTree.h 32 | // 33 | 34 | #define RTREE_TEMPLATE template 35 | #define RTREE_QUAL RTree 36 | 37 | #define RTREE_DONT_USE_MEMPOOLS // This version does not contain a fixed memory allocator, fill in lines with EXAMPLE to implement one. 38 | #define RTREE_USE_SPHERICAL_VOLUME // Better split classification, may be slower on some systems 39 | 40 | // Fwd decl 41 | class RTFileStream; // File I/O helper class, look below for implementation and notes. 42 | 43 | 44 | /// \class RTree 45 | /// Implementation of RTree, a multidimensional bounding rectangle tree. 46 | /// Example usage: For a 3-dimensional tree use RTree myTree; 47 | /// 48 | /// This modified, templated C++ version by Greg Douglas at Auran (http://www.auran.com) 49 | /// 50 | /// DATATYPE Referenced data, should be int, void*, obj* etc. no larger than sizeof and simple type 51 | /// ELEMTYPE Type of element such as int or float 52 | /// NUMDIMS Number of dimensions such as 2 or 3 53 | /// ELEMTYPEREAL Type of element that allows fractional and large values such as float or double, for use in volume calcs 54 | /// 55 | /// NOTES: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle. 56 | /// This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency. 57 | /// Instead of using a callback function for returned results, I recommend and efficient pre-sized, grow-only memory 58 | /// array similar to MFC CArray or STL Vector for returning search query result. 59 | /// 60 | template 62 | class RTree 63 | { 64 | static_assert(std::numeric_limits::is_iec559, "'ELEMTYPEREAL' accepts floating-point types only"); 65 | 66 | protected: 67 | 68 | struct Node; // Fwd decl. Used by other internal structs and iterator 69 | 70 | public: 71 | 72 | // These constant must be declared after Branch and before Node struct 73 | // Stuck up here for MSVC 6 compiler. NSVC .NET 2003 is much happier. 74 | enum 75 | { 76 | MAXNODES = TMAXNODES, ///< Max elements in node 77 | MINNODES = TMINNODES, ///< Min elements in node 78 | }; 79 | 80 | public: 81 | 82 | RTree(); 83 | RTree(const RTree& other); 84 | virtual ~RTree(); 85 | 86 | /// Insert entry 87 | /// \param a_min Min of bounding rect 88 | /// \param a_max Max of bounding rect 89 | /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. 90 | void Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); 91 | 92 | /// Remove entry (traverse the whole tree and removes every occurrence) 93 | /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. 94 | void Remove(const DATATYPE& a_dataId); 95 | 96 | /// Remove entry (only if inside the given rect) 97 | /// \param a_min Min of bounding rect 98 | /// \param a_max Max of bounding rect 99 | /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. 100 | void Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); 101 | 102 | /// Find all within search rectangle 103 | /// \param a_min Min of search bounding rect 104 | /// \param a_max Max of search bounding rect 105 | /// \param a_searchResult Search result array. Caller should set grow size. Function will reset, not append to array. 106 | /// \param a_resultCallback Callback function to return result. Callback should return 'true' to continue searching 107 | /// \param a_context User context to pass as parameter to a_resultCallback 108 | /// \return Returns the number of entries found 109 | int Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], std::function callback) const; 110 | 111 | /// Find the nearest neighbors 112 | /// \param a_min Min of search bounding rect 113 | /// \param a_max Max of search bounding rect 114 | /// \param a_resultCallback Callback function to return result. The Callback takes both the resulting data point and the calculated square distance. Callback should return 'true' to continue searching 115 | /// \return Returns the number of entries found 116 | size_t NNSearch(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], std::function callback) const; 117 | 118 | 119 | /// Remove all entries from tree 120 | void RemoveAll(); 121 | 122 | /// Count the data elements in this container. This is slow as no internal counter is maintained. 123 | int Count(); 124 | 125 | /// Load tree contents from file 126 | bool Load(const char* a_fileName); 127 | /// Load tree contents from stream 128 | bool Load(RTFileStream& a_stream); 129 | 130 | 131 | /// Save tree contents to file 132 | bool Save(const char* a_fileName); 133 | /// Save tree contents to stream 134 | bool Save(RTFileStream& a_stream); 135 | 136 | /// Iterator is not remove safe. 137 | class Iterator 138 | { 139 | private: 140 | 141 | enum { MAX_STACK = 32 }; // Max stack size. Allows almost n^32 where n is number of branches in node 142 | 143 | struct StackElement 144 | { 145 | Node* m_node; 146 | int m_branchIndex; 147 | }; 148 | 149 | public: 150 | 151 | Iterator() { Init(); } 152 | 153 | ~Iterator() { } 154 | 155 | /// Is iterator invalid 156 | bool IsNull() { return (m_tos <= 0); } 157 | 158 | /// Is iterator pointing to valid data 159 | bool IsNotNull() { return (m_tos > 0); } 160 | 161 | /// Access the current data element. Caller must be sure iterator is not NULL first. 162 | DATATYPE& operator*() 163 | { 164 | RTREE_ASSERT(IsNotNull()); 165 | StackElement& curTos = m_stack[m_tos - 1]; 166 | return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; 167 | } 168 | 169 | /// Access the current data element. Caller must be sure iterator is not NULL first. 170 | const DATATYPE& operator*() const 171 | { 172 | RTREE_ASSERT(IsNotNull()); 173 | StackElement& curTos = m_stack[m_tos - 1]; 174 | return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; 175 | } 176 | 177 | /// Find the next data element 178 | bool operator++() { return FindNextData(); } 179 | 180 | /// Get the bounds for this node 181 | void GetBounds(ELEMTYPE a_min[NUMDIMS], ELEMTYPE a_max[NUMDIMS]) 182 | { 183 | RTREE_ASSERT(IsNotNull()); 184 | StackElement& curTos = m_stack[m_tos - 1]; 185 | Branch& curBranch = curTos.m_node->m_branch[curTos.m_branchIndex]; 186 | 187 | for(int index = 0; index < NUMDIMS; ++index) 188 | { 189 | a_min[index] = curBranch.m_rect.m_min[index]; 190 | a_max[index] = curBranch.m_rect.m_max[index]; 191 | } 192 | } 193 | 194 | private: 195 | 196 | /// Reset iterator 197 | void Init() { m_tos = 0; } 198 | 199 | /// Find the next data element in the tree (For internal use only) 200 | bool FindNextData() 201 | { 202 | for(;;) 203 | { 204 | if(m_tos <= 0) 205 | { 206 | return false; 207 | } 208 | StackElement curTos = Pop(); // Copy stack top cause it may change as we use it 209 | 210 | if(curTos.m_node->IsLeaf()) 211 | { 212 | // Keep walking through data while we can 213 | if(curTos.m_branchIndex+1 < curTos.m_node->m_count) 214 | { 215 | // There is more data, just point to the next one 216 | Push(curTos.m_node, curTos.m_branchIndex + 1); 217 | return true; 218 | } 219 | // No more data, so it will fall back to previous level 220 | } 221 | else 222 | { 223 | if(curTos.m_branchIndex+1 < curTos.m_node->m_count) 224 | { 225 | // Push sibling on for future tree walk 226 | // This is the 'fall back' node when we finish with the current level 227 | Push(curTos.m_node, curTos.m_branchIndex + 1); 228 | } 229 | // Since cur node is not a leaf, push first of next level to get deeper into the tree 230 | Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child; 231 | Push(nextLevelnode, 0); 232 | 233 | // If we pushed on a new leaf, exit as the data is ready at TOS 234 | if(nextLevelnode->IsLeaf()) 235 | { 236 | return true; 237 | } 238 | } 239 | } 240 | } 241 | 242 | /// Push node and branch onto iteration stack (For internal use only) 243 | void Push(Node* a_node, int a_branchIndex) 244 | { 245 | m_stack[m_tos].m_node = a_node; 246 | m_stack[m_tos].m_branchIndex = a_branchIndex; 247 | ++m_tos; 248 | RTREE_ASSERT(m_tos <= MAX_STACK); 249 | } 250 | 251 | /// Pop element off iteration stack (For internal use only) 252 | StackElement& Pop() 253 | { 254 | RTREE_ASSERT(m_tos > 0); 255 | --m_tos; 256 | return m_stack[m_tos]; 257 | } 258 | 259 | StackElement m_stack[MAX_STACK]; ///< Stack as we are doing iteration instead of recursion 260 | int m_tos; ///< Top Of Stack index 261 | 262 | friend class RTree; // Allow hiding of non-public functions while allowing manipulation by logical owner 263 | }; 264 | 265 | /// Get 'first' for iteration 266 | void GetFirst(Iterator& a_it) 267 | { 268 | a_it.Init(); 269 | Node* first = m_root; 270 | while(first) 271 | { 272 | if(first->IsInternalNode() && first->m_count > 1) 273 | { 274 | a_it.Push(first, 1); // Descend sibling branch later 275 | } 276 | else if(first->IsLeaf()) 277 | { 278 | if(first->m_count) 279 | { 280 | a_it.Push(first, 0); 281 | } 282 | break; 283 | } 284 | first = first->m_branch[0].m_child; 285 | } 286 | } 287 | 288 | /// Get Next for iteration 289 | void GetNext(Iterator& a_it) { ++a_it; } 290 | 291 | /// Is iterator NULL, or at end? 292 | bool IsNull(Iterator& a_it) { return a_it.IsNull(); } 293 | 294 | /// Get object at iterator position 295 | DATATYPE& GetAt(Iterator& a_it) { return *a_it; } 296 | 297 | protected: 298 | 299 | /// Minimal bounding rectangle (n-dimensional) 300 | struct Rect 301 | { 302 | ELEMTYPE m_min[NUMDIMS]; ///< Min dimensions of bounding box 303 | ELEMTYPE m_max[NUMDIMS]; ///< Max dimensions of bounding box 304 | }; 305 | 306 | /// May be data or may be another subtree 307 | /// The parents level determines this. 308 | /// If the parents level is 0, then this is data 309 | struct Branch 310 | { 311 | Rect m_rect; ///< Bounds 312 | Node* m_child = NULL; ///< Child node 313 | DATATYPE m_data; ///< Data Id 314 | }; 315 | 316 | /// Node for each branch level 317 | struct Node 318 | { 319 | bool IsInternalNode() { return (m_level > 0); } // Not a leaf, but a internal node 320 | bool IsLeaf() { return (m_level == 0); } // A leaf, contains data 321 | 322 | int m_count; ///< Count 323 | int m_level; ///< Leaf is zero, others positive 324 | Branch m_branch[MAXNODES]; ///< Branch 325 | }; 326 | 327 | /// A link list of nodes for reinsertion after a delete operation 328 | struct ListNode 329 | { 330 | ListNode* m_next; ///< Next in list 331 | Node* m_node; ///< Node 332 | }; 333 | 334 | /// Variables for finding a split partition 335 | struct PartitionVars 336 | { 337 | enum { NOT_TAKEN = -1 }; // indicates that position 338 | 339 | int m_partition[MAXNODES+1]; 340 | int m_total; 341 | int m_minFill; 342 | int m_count[2]; 343 | Rect m_cover[2]; 344 | ELEMTYPEREAL m_area[2]; 345 | 346 | Branch m_branchBuf[MAXNODES+1]; 347 | int m_branchCount; 348 | Rect m_coverSplit; 349 | ELEMTYPEREAL m_coverSplitArea; 350 | }; 351 | 352 | Node* AllocNode(); 353 | void FreeNode(Node* a_node); 354 | void InitNode(Node* a_node); 355 | void InitRect(Rect* a_rect); 356 | bool InsertRectRec(const Branch& a_branch, Node* a_node, Node** a_newNode, int a_level); 357 | bool InsertRect(const Branch& a_branch, Node** a_root, int a_level); 358 | Rect NodeCover(Node* a_node); 359 | bool AddBranch(const Branch* a_branch, Node* a_node, Node** a_newNode); 360 | void DisconnectBranch(Node* a_node, int a_index); 361 | int PickBranch(const Rect* a_rect, Node* a_node); 362 | Rect CombineRect(const Rect* a_rectA, const Rect* a_rectB); 363 | void SplitNode(Node* a_node, const Branch* a_branch, Node** a_newNode); 364 | ELEMTYPEREAL RectSphericalVolume(Rect* a_rect); 365 | ELEMTYPEREAL RectVolume(Rect* a_rect); 366 | ELEMTYPEREAL CalcRectVolume(Rect* a_rect); 367 | void GetBranches(Node* a_node, const Branch* a_branch, PartitionVars* a_parVars); 368 | void ChoosePartition(PartitionVars* a_parVars, int a_minFill); 369 | void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars); 370 | void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill); 371 | void PickSeeds(PartitionVars* a_parVars); 372 | void Classify(int a_index, int a_group, PartitionVars* a_parVars); 373 | bool RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root); 374 | bool RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode); 375 | ListNode* AllocListNode(); 376 | void FreeListNode(ListNode* a_listNode); 377 | bool Overlap(Rect* a_rectA, Rect* a_rectB) const; 378 | ELEMTYPE SquareDistance(Rect const& a_rectA, Rect const& a_rectB) const; 379 | void ReInsert(Node* a_node, ListNode** a_listNode); 380 | bool Search(Node* a_node, Rect* a_rect, int& a_foundCount, std::function callback) const; 381 | void RemoveAllRec(Node* a_node); 382 | void Reset(); 383 | void CountRec(Node* a_node, int& a_count); 384 | 385 | bool SaveRec(Node* a_node, RTFileStream& a_stream); 386 | bool LoadRec(Node* a_node, RTFileStream& a_stream); 387 | void CopyRec(Node* current, Node* other); 388 | 389 | Node* m_root; ///< Root of tree 390 | ELEMTYPEREAL m_unitSphereVolume; ///< Unit sphere constant for required number of dimensions 391 | 392 | public: 393 | // return all the AABBs that form the RTree 394 | std::vector ListTree() const; 395 | }; 396 | 397 | 398 | // Because there is not stream support, this is a quick and dirty file I/O helper. 399 | // Users will likely replace its usage with a Stream implementation from their favorite API. 400 | class RTFileStream 401 | { 402 | FILE* m_file; 403 | 404 | public: 405 | 406 | 407 | RTFileStream() 408 | { 409 | m_file = NULL; 410 | } 411 | 412 | ~RTFileStream() 413 | { 414 | Close(); 415 | } 416 | 417 | bool Open(const char* a_fileName, const char* mode) 418 | { 419 | #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) 420 | return fopen_s(&m_file, a_fileName, mode) == 0; 421 | #else 422 | m_file = fopen(a_fileName, mode); 423 | return m_file != nullptr; 424 | #endif 425 | } 426 | 427 | bool OpenRead(const char* a_fileName) 428 | { 429 | return this->Open(a_fileName, "rb"); 430 | } 431 | 432 | bool OpenWrite(const char* a_fileName) 433 | { 434 | return this->Open(a_fileName, "wb"); 435 | } 436 | 437 | void Close() 438 | { 439 | if(m_file) 440 | { 441 | fclose(m_file); 442 | m_file = NULL; 443 | } 444 | } 445 | 446 | template< typename TYPE > 447 | size_t Write(const TYPE& a_value) 448 | { 449 | RTREE_ASSERT(m_file); 450 | return fwrite((void*)&a_value, sizeof(a_value), 1, m_file); 451 | } 452 | 453 | template< typename TYPE > 454 | size_t WriteArray(const TYPE* a_array, int a_count) 455 | { 456 | RTREE_ASSERT(m_file); 457 | return fwrite((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); 458 | } 459 | 460 | template< typename TYPE > 461 | size_t Read(TYPE& a_value) 462 | { 463 | RTREE_ASSERT(m_file); 464 | return fread((void*)&a_value, sizeof(a_value), 1, m_file); 465 | } 466 | 467 | template< typename TYPE > 468 | size_t ReadArray(TYPE* a_array, int a_count) 469 | { 470 | RTREE_ASSERT(m_file); 471 | return fread((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); 472 | } 473 | }; 474 | 475 | 476 | RTREE_TEMPLATE 477 | RTREE_QUAL::RTree() 478 | { 479 | RTREE_ASSERT(MAXNODES > MINNODES); 480 | RTREE_ASSERT(MINNODES > 0); 481 | 482 | // Precomputed volumes of the unit spheres for the first few dimensions 483 | const float UNIT_SPHERE_VOLUMES[] = { 484 | 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2 485 | 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5 486 | 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8 487 | 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11 488 | 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14 489 | 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17 490 | 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20 491 | }; 492 | 493 | m_root = AllocNode(); 494 | m_root->m_level = 0; 495 | 496 | if (NUMDIMS < 21) 497 | { 498 | m_unitSphereVolume = (ELEMTYPEREAL)UNIT_SPHERE_VOLUMES[NUMDIMS]; 499 | } else { 500 | // Stirling's approximation, applicable to high dimensions 501 | // https://en.wikipedia.org/wiki/Volume_of_an_n-ball#Approximation_for_high_dimensions 502 | m_unitSphereVolume = (ELEMTYPEREAL)(1.0 / std::sqrt(NUMDIMS * M_PI) * 503 | std::pow(2 * M_PI * M_E / NUMDIMS, NUMDIMS / 2.0)); 504 | } 505 | } 506 | 507 | 508 | RTREE_TEMPLATE 509 | RTREE_QUAL::RTree(const RTree& other) : RTree() 510 | { 511 | CopyRec(m_root, other.m_root); 512 | } 513 | 514 | 515 | RTREE_TEMPLATE 516 | RTREE_QUAL::~RTree() 517 | { 518 | Reset(); // Free, or reset node memory 519 | } 520 | 521 | 522 | RTREE_TEMPLATE 523 | void RTREE_QUAL::Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId) 524 | { 525 | #ifdef _DEBUG 526 | for(int index=0; index callback) const 577 | { 578 | #ifdef _DEBUG 579 | for(int index=0; index callback 605 | ) const 606 | { 607 | // Create a search rectangle 608 | Rect rect; 609 | for (int axis = 0; axis < NUMDIMS; ++axis) 610 | { 611 | rect.m_min[axis] = a_min[axis]; 612 | rect.m_max[axis] = a_max[axis]; 613 | } 614 | 615 | // class to store branches in the priority queue 616 | struct QueueItem 617 | { 618 | QueueItem(Branch* branch, ELEMTYPE distance) : 619 | branch(branch), 620 | distance(distance) 621 | {} 622 | 623 | // Sort in the queue with the minimum distance 624 | // taking priority 625 | bool operator<(QueueItem const& a) const 626 | { 627 | return this->distance > a.distance; 628 | } 629 | 630 | Branch* branch; 631 | ELEMTYPE distance; 632 | }; 633 | 634 | std::priority_queue search_queue; 635 | 636 | // All branches in the root node are inserted into the priority queue. 637 | for (auto i = 0; i < m_root->m_count; ++i) 638 | { 639 | auto d = this->SquareDistance(rect, m_root->m_branch[i].m_rect); 640 | search_queue.emplace(m_root->m_branch + i, d); 641 | } 642 | 643 | size_t foundCount = 0; 644 | 645 | // Until the queue is empty 646 | while (!search_queue.empty()) 647 | { 648 | // Process the top item in the queue 649 | auto process = std::move(search_queue.top()); 650 | search_queue.pop(); 651 | 652 | if (process.branch->m_child) 653 | { 654 | // If the branch has children, add them all into the queue 655 | Node* node = process.branch->m_child; 656 | for (auto i = 0; i < node->m_count; ++i) 657 | { 658 | auto d = this->SquareDistance(rect, node->m_branch[i].m_rect); 659 | search_queue.emplace(node->m_branch + i, d); 660 | } 661 | } 662 | else 663 | { 664 | // If this is a leaf, then we have found a minimum distance 665 | // Call the callback 666 | ++foundCount; 667 | if (!callback(process.branch->m_data, process.distance)) 668 | { 669 | // If the user has flaged to stopped, then return 670 | // the number found. 671 | return foundCount; 672 | } 673 | } 674 | 675 | } 676 | 677 | // No more items to search 678 | return foundCount; 679 | } 680 | 681 | 682 | RTREE_TEMPLATE 683 | int RTREE_QUAL::Count() 684 | { 685 | int count = 0; 686 | CountRec(m_root, count); 687 | 688 | return count; 689 | } 690 | 691 | 692 | 693 | RTREE_TEMPLATE 694 | void RTREE_QUAL::CountRec(Node* a_node, int& a_count) 695 | { 696 | if(a_node->IsInternalNode()) // not a leaf node 697 | { 698 | for(int index = 0; index < a_node->m_count; ++index) 699 | { 700 | CountRec(a_node->m_branch[index].m_child, a_count); 701 | } 702 | } 703 | else // A leaf node 704 | { 705 | a_count += a_node->m_count; 706 | } 707 | } 708 | 709 | 710 | RTREE_TEMPLATE 711 | bool RTREE_QUAL::Load(const char* a_fileName) 712 | { 713 | RemoveAll(); // Clear existing tree 714 | 715 | RTFileStream stream; 716 | if(!stream.OpenRead(a_fileName)) 717 | { 718 | return false; 719 | } 720 | 721 | bool result = Load(stream); 722 | 723 | stream.Close(); 724 | 725 | return result; 726 | } 727 | 728 | 729 | 730 | RTREE_TEMPLATE 731 | bool RTREE_QUAL::Load(RTFileStream& a_stream) 732 | { 733 | // Write some kind of header 734 | int _dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); 735 | int _dataSize = sizeof(DATATYPE); 736 | int _dataNumDims = NUMDIMS; 737 | int _dataElemSize = sizeof(ELEMTYPE); 738 | int _dataElemRealSize = sizeof(ELEMTYPEREAL); 739 | int _dataMaxNodes = TMAXNODES; 740 | int _dataMinNodes = TMINNODES; 741 | 742 | int dataFileId = 0; 743 | int dataSize = 0; 744 | int dataNumDims = 0; 745 | int dataElemSize = 0; 746 | int dataElemRealSize = 0; 747 | int dataMaxNodes = 0; 748 | int dataMinNodes = 0; 749 | 750 | a_stream.Read(dataFileId); 751 | a_stream.Read(dataSize); 752 | a_stream.Read(dataNumDims); 753 | a_stream.Read(dataElemSize); 754 | a_stream.Read(dataElemRealSize); 755 | a_stream.Read(dataMaxNodes); 756 | a_stream.Read(dataMinNodes); 757 | 758 | bool result = false; 759 | 760 | // Test if header was valid and compatible 761 | if( (dataFileId == _dataFileId) 762 | && (dataSize == _dataSize) 763 | && (dataNumDims == _dataNumDims) 764 | && (dataElemSize == _dataElemSize) 765 | && (dataElemRealSize == _dataElemRealSize) 766 | && (dataMaxNodes == _dataMaxNodes) 767 | && (dataMinNodes == _dataMinNodes) 768 | ) 769 | { 770 | // Recursively load tree 771 | result = LoadRec(m_root, a_stream); 772 | } 773 | 774 | return result; 775 | } 776 | 777 | 778 | RTREE_TEMPLATE 779 | bool RTREE_QUAL::LoadRec(Node* a_node, RTFileStream& a_stream) 780 | { 781 | a_stream.Read(a_node->m_level); 782 | a_stream.Read(a_node->m_count); 783 | 784 | if(a_node->IsInternalNode()) // not a leaf node 785 | { 786 | for(int index = 0; index < a_node->m_count; ++index) 787 | { 788 | Branch* curBranch = &a_node->m_branch[index]; 789 | 790 | a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); 791 | a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); 792 | 793 | curBranch->m_child = AllocNode(); 794 | LoadRec(curBranch->m_child, a_stream); 795 | } 796 | } 797 | else // A leaf node 798 | { 799 | for(int index = 0; index < a_node->m_count; ++index) 800 | { 801 | Branch* curBranch = &a_node->m_branch[index]; 802 | 803 | a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); 804 | a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); 805 | 806 | a_stream.Read(curBranch->m_data); 807 | } 808 | } 809 | 810 | return true; // Should do more error checking on I/O operations 811 | } 812 | 813 | 814 | RTREE_TEMPLATE 815 | void RTREE_QUAL::CopyRec(Node* current, Node* other) 816 | { 817 | current->m_level = other->m_level; 818 | current->m_count = other->m_count; 819 | 820 | if(current->IsInternalNode()) // not a leaf node 821 | { 822 | for(int index = 0; index < current->m_count; ++index) 823 | { 824 | Branch* currentBranch = ¤t->m_branch[index]; 825 | Branch* otherBranch = &other->m_branch[index]; 826 | 827 | std::copy(otherBranch->m_rect.m_min, 828 | otherBranch->m_rect.m_min + NUMDIMS, 829 | currentBranch->m_rect.m_min); 830 | 831 | std::copy(otherBranch->m_rect.m_max, 832 | otherBranch->m_rect.m_max + NUMDIMS, 833 | currentBranch->m_rect.m_max); 834 | 835 | currentBranch->m_child = AllocNode(); 836 | CopyRec(currentBranch->m_child, otherBranch->m_child); 837 | } 838 | } 839 | else // A leaf node 840 | { 841 | for(int index = 0; index < current->m_count; ++index) 842 | { 843 | Branch* currentBranch = ¤t->m_branch[index]; 844 | Branch* otherBranch = &other->m_branch[index]; 845 | 846 | std::copy(otherBranch->m_rect.m_min, 847 | otherBranch->m_rect.m_min + NUMDIMS, 848 | currentBranch->m_rect.m_min); 849 | 850 | std::copy(otherBranch->m_rect.m_max, 851 | otherBranch->m_rect.m_max + NUMDIMS, 852 | currentBranch->m_rect.m_max); 853 | 854 | currentBranch->m_data = otherBranch->m_data; 855 | } 856 | } 857 | } 858 | 859 | 860 | RTREE_TEMPLATE 861 | bool RTREE_QUAL::Save(const char* a_fileName) 862 | { 863 | RTFileStream stream; 864 | if(!stream.OpenWrite(a_fileName)) 865 | { 866 | return false; 867 | } 868 | 869 | bool result = Save(stream); 870 | 871 | stream.Close(); 872 | 873 | return result; 874 | } 875 | 876 | 877 | RTREE_TEMPLATE 878 | bool RTREE_QUAL::Save(RTFileStream& a_stream) 879 | { 880 | // Write some kind of header 881 | int dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); 882 | int dataSize = sizeof(DATATYPE); 883 | int dataNumDims = NUMDIMS; 884 | int dataElemSize = sizeof(ELEMTYPE); 885 | int dataElemRealSize = sizeof(ELEMTYPEREAL); 886 | int dataMaxNodes = TMAXNODES; 887 | int dataMinNodes = TMINNODES; 888 | 889 | a_stream.Write(dataFileId); 890 | a_stream.Write(dataSize); 891 | a_stream.Write(dataNumDims); 892 | a_stream.Write(dataElemSize); 893 | a_stream.Write(dataElemRealSize); 894 | a_stream.Write(dataMaxNodes); 895 | a_stream.Write(dataMinNodes); 896 | 897 | // Recursively save tree 898 | bool result = SaveRec(m_root, a_stream); 899 | 900 | return result; 901 | } 902 | 903 | 904 | RTREE_TEMPLATE 905 | bool RTREE_QUAL::SaveRec(Node* a_node, RTFileStream& a_stream) 906 | { 907 | a_stream.Write(a_node->m_level); 908 | a_stream.Write(a_node->m_count); 909 | 910 | if(a_node->IsInternalNode()) // not a leaf node 911 | { 912 | for(int index = 0; index < a_node->m_count; ++index) 913 | { 914 | Branch* curBranch = &a_node->m_branch[index]; 915 | 916 | a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); 917 | a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); 918 | 919 | SaveRec(curBranch->m_child, a_stream); 920 | } 921 | } 922 | else // A leaf node 923 | { 924 | for(int index = 0; index < a_node->m_count; ++index) 925 | { 926 | Branch* curBranch = &a_node->m_branch[index]; 927 | 928 | a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); 929 | a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); 930 | 931 | a_stream.Write(curBranch->m_data); 932 | } 933 | } 934 | 935 | return true; // Should do more error checking on I/O operations 936 | } 937 | 938 | 939 | RTREE_TEMPLATE 940 | void RTREE_QUAL::RemoveAll() 941 | { 942 | // Delete all existing nodes 943 | Reset(); 944 | 945 | m_root = AllocNode(); 946 | m_root->m_level = 0; 947 | } 948 | 949 | 950 | RTREE_TEMPLATE 951 | void RTREE_QUAL::Reset() 952 | { 953 | #ifdef RTREE_DONT_USE_MEMPOOLS 954 | // Delete all existing nodes 955 | RemoveAllRec(m_root); 956 | #else // RTREE_DONT_USE_MEMPOOLS 957 | // Just reset memory pools. We are not using complex types 958 | // EXAMPLE 959 | #endif // RTREE_DONT_USE_MEMPOOLS 960 | } 961 | 962 | 963 | RTREE_TEMPLATE 964 | void RTREE_QUAL::RemoveAllRec(Node* a_node) 965 | { 966 | RTREE_ASSERT(a_node); 967 | RTREE_ASSERT(a_node->m_level >= 0); 968 | 969 | if(a_node->IsInternalNode()) // This is an internal node in the tree 970 | { 971 | for(int index=0; index < a_node->m_count; ++index) 972 | { 973 | RemoveAllRec(a_node->m_branch[index].m_child); 974 | } 975 | } 976 | FreeNode(a_node); 977 | } 978 | 979 | 980 | RTREE_TEMPLATE 981 | typename RTREE_QUAL::Node* RTREE_QUAL::AllocNode() 982 | { 983 | Node* newNode; 984 | #ifdef RTREE_DONT_USE_MEMPOOLS 985 | newNode = new Node; 986 | #else // RTREE_DONT_USE_MEMPOOLS 987 | // EXAMPLE 988 | #endif // RTREE_DONT_USE_MEMPOOLS 989 | InitNode(newNode); 990 | return newNode; 991 | } 992 | 993 | 994 | RTREE_TEMPLATE 995 | void RTREE_QUAL::FreeNode(Node* a_node) 996 | { 997 | RTREE_ASSERT(a_node); 998 | 999 | #ifdef RTREE_DONT_USE_MEMPOOLS 1000 | delete a_node; 1001 | #else // RTREE_DONT_USE_MEMPOOLS 1002 | // EXAMPLE 1003 | #endif // RTREE_DONT_USE_MEMPOOLS 1004 | } 1005 | 1006 | 1007 | // Allocate space for a node in the list used in DeletRect to 1008 | // store Nodes that are too empty. 1009 | RTREE_TEMPLATE 1010 | typename RTREE_QUAL::ListNode* RTREE_QUAL::AllocListNode() 1011 | { 1012 | #ifdef RTREE_DONT_USE_MEMPOOLS 1013 | return new ListNode; 1014 | #else // RTREE_DONT_USE_MEMPOOLS 1015 | // EXAMPLE 1016 | #endif // RTREE_DONT_USE_MEMPOOLS 1017 | } 1018 | 1019 | 1020 | RTREE_TEMPLATE 1021 | void RTREE_QUAL::FreeListNode(ListNode* a_listNode) 1022 | { 1023 | #ifdef RTREE_DONT_USE_MEMPOOLS 1024 | delete a_listNode; 1025 | #else // RTREE_DONT_USE_MEMPOOLS 1026 | // EXAMPLE 1027 | #endif // RTREE_DONT_USE_MEMPOOLS 1028 | } 1029 | 1030 | 1031 | RTREE_TEMPLATE 1032 | void RTREE_QUAL::InitNode(Node* a_node) 1033 | { 1034 | a_node->m_count = 0; 1035 | a_node->m_level = -1; 1036 | } 1037 | 1038 | 1039 | RTREE_TEMPLATE 1040 | void RTREE_QUAL::InitRect(Rect* a_rect) 1041 | { 1042 | for(int index = 0; index < NUMDIMS; ++index) 1043 | { 1044 | a_rect->m_min[index] = (ELEMTYPE)0; 1045 | a_rect->m_max[index] = (ELEMTYPE)0; 1046 | } 1047 | } 1048 | 1049 | 1050 | // Inserts a new data rectangle into the index structure. 1051 | // Recursively descends tree, propagates splits back up. 1052 | // Returns 0 if node was not split. Old node updated. 1053 | // If node was split, returns 1 and sets the pointer pointed to by 1054 | // new_node to point to the new node. Old node updated to become one of two. 1055 | // The level argument specifies the number of steps up from the leaf 1056 | // level to insert; e.g. a data rectangle goes in at level = 0. 1057 | RTREE_TEMPLATE 1058 | bool RTREE_QUAL::InsertRectRec(const Branch& a_branch, Node* a_node, Node** a_newNode, int a_level) 1059 | { 1060 | RTREE_ASSERT(a_node && a_newNode); 1061 | RTREE_ASSERT(a_level >= 0 && a_level <= a_node->m_level); 1062 | 1063 | // recurse until we reach the correct level for the new record. data records 1064 | // will always be called with a_level == 0 (leaf) 1065 | if(a_node->m_level > a_level) 1066 | { 1067 | // Still above level for insertion, go down tree recursively 1068 | Node* otherNode; 1069 | 1070 | // find the optimal branch for this record 1071 | int index = PickBranch(&a_branch.m_rect, a_node); 1072 | 1073 | // recursively insert this record into the picked branch 1074 | bool childWasSplit = InsertRectRec(a_branch, a_node->m_branch[index].m_child, &otherNode, a_level); 1075 | 1076 | if (!childWasSplit) 1077 | { 1078 | // Child was not split. Merge the bounding box of the new record with the 1079 | // existing bounding box 1080 | a_node->m_branch[index].m_rect = CombineRect(&a_branch.m_rect, &(a_node->m_branch[index].m_rect)); 1081 | return false; 1082 | } 1083 | else 1084 | { 1085 | // Child was split. The old branches are now re-partitioned to two nodes 1086 | // so we have to re-calculate the bounding boxes of each node 1087 | a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); 1088 | Branch branch; 1089 | branch.m_child = otherNode; 1090 | branch.m_rect = NodeCover(otherNode); 1091 | 1092 | // The old node is already a child of a_node. Now add the newly-created 1093 | // node to a_node as well. a_node might be split because of that. 1094 | return AddBranch(&branch, a_node, a_newNode); 1095 | } 1096 | } 1097 | else if(a_node->m_level == a_level) 1098 | { 1099 | // We have reached level for insertion. Add rect, split if necessary 1100 | return AddBranch(&a_branch, a_node, a_newNode); 1101 | } 1102 | else 1103 | { 1104 | // Should never occur 1105 | RTREE_ASSERT(0); 1106 | return false; 1107 | } 1108 | } 1109 | 1110 | 1111 | // Insert a data rectangle into an index structure. 1112 | // InsertRect provides for splitting the root; 1113 | // returns 1 if root was split, 0 if it was not. 1114 | // The level argument specifies the number of steps up from the leaf 1115 | // level to insert; e.g. a data rectangle goes in at level = 0. 1116 | // InsertRect2 does the recursion. 1117 | // 1118 | RTREE_TEMPLATE 1119 | bool RTREE_QUAL::InsertRect(const Branch& a_branch, Node** a_root, int a_level) 1120 | { 1121 | RTREE_ASSERT(a_root); 1122 | RTREE_ASSERT(a_level >= 0 && a_level <= (*a_root)->m_level); 1123 | #ifdef _DEBUG 1124 | for(int index=0; index < NUMDIMS; ++index) 1125 | { 1126 | RTREE_ASSERT(a_branch.m_rect.m_min[index] <= a_branch.m_rect.m_max[index]); 1127 | } 1128 | #endif //_DEBUG 1129 | 1130 | Node* newNode; 1131 | 1132 | if(InsertRectRec(a_branch, *a_root, &newNode, a_level)) // Root split 1133 | { 1134 | // Grow tree taller and new root 1135 | Node* newRoot = AllocNode(); 1136 | newRoot->m_level = (*a_root)->m_level + 1; 1137 | 1138 | Branch branch; 1139 | 1140 | // add old root node as a child of the new root 1141 | branch.m_rect = NodeCover(*a_root); 1142 | branch.m_child = *a_root; 1143 | AddBranch(&branch, newRoot, NULL); 1144 | 1145 | // add the split node as a child of the new root 1146 | branch.m_rect = NodeCover(newNode); 1147 | branch.m_child = newNode; 1148 | AddBranch(&branch, newRoot, NULL); 1149 | 1150 | // set the new root as the root node 1151 | *a_root = newRoot; 1152 | 1153 | return true; 1154 | } 1155 | 1156 | return false; 1157 | } 1158 | 1159 | 1160 | // Find the smallest rectangle that includes all rectangles in branches of a node. 1161 | RTREE_TEMPLATE 1162 | typename RTREE_QUAL::Rect RTREE_QUAL::NodeCover(Node* a_node) 1163 | { 1164 | RTREE_ASSERT(a_node); 1165 | 1166 | Rect rect = a_node->m_branch[0].m_rect; 1167 | for(int index = 1; index < a_node->m_count; ++index) 1168 | { 1169 | rect = CombineRect(&rect, &(a_node->m_branch[index].m_rect)); 1170 | } 1171 | 1172 | return rect; 1173 | } 1174 | 1175 | 1176 | // Add a branch to a node. Split the node if necessary. 1177 | // Returns 0 if node not split. Old node updated. 1178 | // Returns 1 if node split, sets *new_node to address of new node. 1179 | // Old node updated, becomes one of two. 1180 | RTREE_TEMPLATE 1181 | bool RTREE_QUAL::AddBranch(const Branch* a_branch, Node* a_node, Node** a_newNode) 1182 | { 1183 | RTREE_ASSERT(a_branch); 1184 | RTREE_ASSERT(a_node); 1185 | 1186 | if(a_node->m_count < MAXNODES) // Split won't be necessary 1187 | { 1188 | a_node->m_branch[a_node->m_count] = *a_branch; 1189 | ++a_node->m_count; 1190 | 1191 | return false; 1192 | } 1193 | else 1194 | { 1195 | RTREE_ASSERT(a_newNode); 1196 | 1197 | SplitNode(a_node, a_branch, a_newNode); 1198 | return true; 1199 | } 1200 | } 1201 | 1202 | 1203 | // Disconnect a dependent node. 1204 | // Caller must return (or stop using iteration index) after this as count has changed 1205 | RTREE_TEMPLATE 1206 | void RTREE_QUAL::DisconnectBranch(Node* a_node, int a_index) 1207 | { 1208 | RTREE_ASSERT(a_node && (a_index >= 0) && (a_index < MAXNODES)); 1209 | RTREE_ASSERT(a_node->m_count > 0); 1210 | 1211 | // Remove element by swapping with the last element to prevent gaps in array 1212 | a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1]; 1213 | 1214 | --a_node->m_count; 1215 | } 1216 | 1217 | 1218 | // Pick a branch. Pick the one that will need the smallest increase 1219 | // in area to accomodate the new rectangle. This will result in the 1220 | // least total area for the covering rectangles in the current node. 1221 | // In case of a tie, pick the one which was smaller before, to get 1222 | // the best resolution when searching. 1223 | RTREE_TEMPLATE 1224 | int RTREE_QUAL::PickBranch(const Rect* a_rect, Node* a_node) 1225 | { 1226 | RTREE_ASSERT(a_rect && a_node); 1227 | 1228 | bool firstTime = true; 1229 | ELEMTYPEREAL increase; 1230 | ELEMTYPEREAL bestIncr = (ELEMTYPEREAL)-1; 1231 | ELEMTYPEREAL area; 1232 | ELEMTYPEREAL bestArea = (ELEMTYPEREAL)-1; 1233 | int best = 0; 1234 | Rect tempRect; 1235 | 1236 | for(int index=0; index < a_node->m_count; ++index) 1237 | { 1238 | Rect* curRect = &a_node->m_branch[index].m_rect; 1239 | area = CalcRectVolume(curRect); 1240 | tempRect = CombineRect(a_rect, curRect); 1241 | increase = CalcRectVolume(&tempRect) - area; 1242 | if((increase < bestIncr) || firstTime) 1243 | { 1244 | best = index; 1245 | bestArea = area; 1246 | bestIncr = increase; 1247 | firstTime = false; 1248 | } 1249 | else if((increase == bestIncr) && (area < bestArea)) 1250 | { 1251 | best = index; 1252 | bestArea = area; 1253 | bestIncr = increase; 1254 | } 1255 | } 1256 | return best; 1257 | } 1258 | 1259 | 1260 | // Combine two rectangles into larger one containing both 1261 | RTREE_TEMPLATE 1262 | typename RTREE_QUAL::Rect RTREE_QUAL::CombineRect(const Rect* a_rectA, const Rect* a_rectB) 1263 | { 1264 | RTREE_ASSERT(a_rectA && a_rectB); 1265 | 1266 | Rect newRect; 1267 | 1268 | for(int index = 0; index < NUMDIMS; ++index) 1269 | { 1270 | newRect.m_min[index] = RTREE_MIN(a_rectA->m_min[index], a_rectB->m_min[index]); 1271 | newRect.m_max[index] = RTREE_MAX(a_rectA->m_max[index], a_rectB->m_max[index]); 1272 | } 1273 | 1274 | return newRect; 1275 | } 1276 | 1277 | 1278 | 1279 | // Split a node. 1280 | // Divides the nodes branches and the extra one between two nodes. 1281 | // Old node is one of the new ones, and one really new one is created. 1282 | // Tries more than one method for choosing a partition, uses best result. 1283 | RTREE_TEMPLATE 1284 | void RTREE_QUAL::SplitNode(Node* a_node, const Branch* a_branch, Node** a_newNode) 1285 | { 1286 | RTREE_ASSERT(a_node); 1287 | RTREE_ASSERT(a_branch); 1288 | 1289 | // Could just use local here, but member or external is faster since it is reused 1290 | PartitionVars localVars; 1291 | PartitionVars* parVars = &localVars; 1292 | 1293 | // Load all the branches into a buffer, initialize old node 1294 | GetBranches(a_node, a_branch, parVars); 1295 | 1296 | // Find partition 1297 | ChoosePartition(parVars, MINNODES); 1298 | 1299 | // Create a new node to hold (about) half of the branches 1300 | *a_newNode = AllocNode(); 1301 | (*a_newNode)->m_level = a_node->m_level; 1302 | 1303 | // Put branches from buffer into 2 nodes according to the chosen partition 1304 | a_node->m_count = 0; 1305 | LoadNodes(a_node, *a_newNode, parVars); 1306 | 1307 | RTREE_ASSERT((a_node->m_count + (*a_newNode)->m_count) == parVars->m_total); 1308 | } 1309 | 1310 | 1311 | // Calculate the n-dimensional volume of a rectangle 1312 | RTREE_TEMPLATE 1313 | ELEMTYPEREAL RTREE_QUAL::RectVolume(Rect* a_rect) 1314 | { 1315 | RTREE_ASSERT(a_rect); 1316 | 1317 | ELEMTYPEREAL volume = (ELEMTYPEREAL)1; 1318 | 1319 | for(int index=0; indexm_max[index] - a_rect->m_min[index]; 1322 | } 1323 | 1324 | RTREE_ASSERT(volume >= (ELEMTYPEREAL)0); 1325 | 1326 | return volume; 1327 | } 1328 | 1329 | 1330 | // The exact volume of the bounding sphere for the given Rect 1331 | RTREE_TEMPLATE 1332 | ELEMTYPEREAL RTREE_QUAL::RectSphericalVolume(Rect* a_rect) 1333 | { 1334 | RTREE_ASSERT(a_rect); 1335 | 1336 | ELEMTYPEREAL sumOfSquares = (ELEMTYPEREAL)0; 1337 | ELEMTYPEREAL radius; 1338 | 1339 | for(int index=0; index < NUMDIMS; ++index) 1340 | { 1341 | ELEMTYPEREAL halfExtent = ((ELEMTYPEREAL)a_rect->m_max[index] - (ELEMTYPEREAL)a_rect->m_min[index]) * (ELEMTYPEREAL)0.5; 1342 | sumOfSquares += halfExtent * halfExtent; 1343 | } 1344 | 1345 | radius = (ELEMTYPEREAL)sqrt(sumOfSquares); 1346 | 1347 | // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. 1348 | if(NUMDIMS == 3) 1349 | { 1350 | return (radius * radius * radius * m_unitSphereVolume); 1351 | } 1352 | else if(NUMDIMS == 2) 1353 | { 1354 | return (radius * radius * m_unitSphereVolume); 1355 | } 1356 | else 1357 | { 1358 | return (ELEMTYPEREAL)(pow(radius, NUMDIMS) * m_unitSphereVolume); 1359 | } 1360 | } 1361 | 1362 | 1363 | // Use one of the methods to calculate retangle volume 1364 | RTREE_TEMPLATE 1365 | ELEMTYPEREAL RTREE_QUAL::CalcRectVolume(Rect* a_rect) 1366 | { 1367 | #ifdef RTREE_USE_SPHERICAL_VOLUME 1368 | return RectSphericalVolume(a_rect); // Slower but helps certain merge cases 1369 | #else // RTREE_USE_SPHERICAL_VOLUME 1370 | return RectVolume(a_rect); // Faster but can cause poor merges 1371 | #endif // RTREE_USE_SPHERICAL_VOLUME 1372 | } 1373 | 1374 | 1375 | // Load branch buffer with branches from full node plus the extra branch. 1376 | RTREE_TEMPLATE 1377 | void RTREE_QUAL::GetBranches(Node* a_node, const Branch* a_branch, PartitionVars* a_parVars) 1378 | { 1379 | RTREE_ASSERT(a_node); 1380 | RTREE_ASSERT(a_branch); 1381 | 1382 | RTREE_ASSERT(a_node->m_count == MAXNODES); 1383 | 1384 | // Load the branch buffer 1385 | for(int index=0; index < MAXNODES; ++index) 1386 | { 1387 | a_parVars->m_branchBuf[index] = a_node->m_branch[index]; 1388 | } 1389 | a_parVars->m_branchBuf[MAXNODES] = *a_branch; 1390 | a_parVars->m_branchCount = MAXNODES + 1; 1391 | 1392 | // Calculate rect containing all in the set 1393 | a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect; 1394 | for(int index=1; index < MAXNODES+1; ++index) 1395 | { 1396 | a_parVars->m_coverSplit = CombineRect(&a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect); 1397 | } 1398 | a_parVars->m_coverSplitArea = CalcRectVolume(&a_parVars->m_coverSplit); 1399 | } 1400 | 1401 | 1402 | // Method #0 for choosing a partition: 1403 | // As the seeds for the two groups, pick the two rects that would waste the 1404 | // most area if covered by a single rectangle, i.e. evidently the worst pair 1405 | // to have in the same group. 1406 | // Of the remaining, one at a time is chosen to be put in one of the two groups. 1407 | // The one chosen is the one with the greatest difference in area expansion 1408 | // depending on which group - the rect most strongly attracted to one group 1409 | // and repelled from the other. 1410 | // If one group gets too full (more would force other group to violate min 1411 | // fill requirement) then other group gets the rest. 1412 | // These last are the ones that can go in either group most easily. 1413 | RTREE_TEMPLATE 1414 | void RTREE_QUAL::ChoosePartition(PartitionVars* a_parVars, int a_minFill) 1415 | { 1416 | RTREE_ASSERT(a_parVars); 1417 | 1418 | bool firstTime; 1419 | ELEMTYPEREAL biggestDiff; 1420 | int group, chosen = 0, betterGroup = 0; 1421 | 1422 | InitParVars(a_parVars, a_parVars->m_branchCount, a_minFill); 1423 | PickSeeds(a_parVars); 1424 | 1425 | while (((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) 1426 | && (a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill)) 1427 | && (a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill))) 1428 | { 1429 | firstTime = true; 1430 | for(int index=0; indexm_total; ++index) 1431 | { 1432 | if(PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) 1433 | { 1434 | Rect* curRect = &a_parVars->m_branchBuf[index].m_rect; 1435 | Rect rect0 = CombineRect(curRect, &a_parVars->m_cover[0]); 1436 | Rect rect1 = CombineRect(curRect, &a_parVars->m_cover[1]); 1437 | ELEMTYPEREAL growth0 = CalcRectVolume(&rect0) - a_parVars->m_area[0]; 1438 | ELEMTYPEREAL growth1 = CalcRectVolume(&rect1) - a_parVars->m_area[1]; 1439 | ELEMTYPEREAL diff = growth1 - growth0; 1440 | if(diff >= 0) 1441 | { 1442 | group = 0; 1443 | } 1444 | else 1445 | { 1446 | group = 1; 1447 | diff = -diff; 1448 | } 1449 | 1450 | if(firstTime || diff > biggestDiff) 1451 | { 1452 | firstTime = false; 1453 | biggestDiff = diff; 1454 | chosen = index; 1455 | betterGroup = group; 1456 | } 1457 | else if((diff == biggestDiff) && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup])) 1458 | { 1459 | chosen = index; 1460 | betterGroup = group; 1461 | } 1462 | } 1463 | } 1464 | RTREE_ASSERT(!firstTime); 1465 | Classify(chosen, betterGroup, a_parVars); 1466 | } 1467 | 1468 | // If one group too full, put remaining rects in the other 1469 | if((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) 1470 | { 1471 | if(a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill) 1472 | { 1473 | group = 1; 1474 | } 1475 | else 1476 | { 1477 | group = 0; 1478 | } 1479 | for(int index=0; indexm_total; ++index) 1480 | { 1481 | if(PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) 1482 | { 1483 | Classify(index, group, a_parVars); 1484 | } 1485 | } 1486 | } 1487 | 1488 | RTREE_ASSERT((a_parVars->m_count[0] + a_parVars->m_count[1]) == a_parVars->m_total); 1489 | RTREE_ASSERT((a_parVars->m_count[0] >= a_parVars->m_minFill) && 1490 | (a_parVars->m_count[1] >= a_parVars->m_minFill)); 1491 | } 1492 | 1493 | 1494 | // Copy branches from the buffer into two nodes according to the partition. 1495 | RTREE_TEMPLATE 1496 | void RTREE_QUAL::LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars) 1497 | { 1498 | RTREE_ASSERT(a_nodeA); 1499 | RTREE_ASSERT(a_nodeB); 1500 | RTREE_ASSERT(a_parVars); 1501 | 1502 | for(int index=0; index < a_parVars->m_total; ++index) 1503 | { 1504 | RTREE_ASSERT(a_parVars->m_partition[index] == 0 || a_parVars->m_partition[index] == 1); 1505 | 1506 | int targetNodeIndex = a_parVars->m_partition[index]; 1507 | Node* targetNodes[] = {a_nodeA, a_nodeB}; 1508 | 1509 | // It is assured that AddBranch here will not cause a node split. 1510 | bool nodeWasSplit = AddBranch(&a_parVars->m_branchBuf[index], targetNodes[targetNodeIndex], NULL); 1511 | RTREE_ASSERT(!nodeWasSplit); 1512 | } 1513 | } 1514 | 1515 | 1516 | // Initialize a PartitionVars structure. 1517 | RTREE_TEMPLATE 1518 | void RTREE_QUAL::InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill) 1519 | { 1520 | RTREE_ASSERT(a_parVars); 1521 | 1522 | a_parVars->m_count[0] = a_parVars->m_count[1] = 0; 1523 | a_parVars->m_area[0] = a_parVars->m_area[1] = (ELEMTYPEREAL)0; 1524 | a_parVars->m_total = a_maxRects; 1525 | a_parVars->m_minFill = a_minFill; 1526 | for(int index=0; index < a_maxRects; ++index) 1527 | { 1528 | a_parVars->m_partition[index] = PartitionVars::NOT_TAKEN; 1529 | } 1530 | } 1531 | 1532 | 1533 | RTREE_TEMPLATE 1534 | void RTREE_QUAL::PickSeeds(PartitionVars* a_parVars) 1535 | { 1536 | bool firstTime; 1537 | int seed0 = 0, seed1 = 0; 1538 | ELEMTYPEREAL worst, waste; 1539 | ELEMTYPEREAL area[MAXNODES+1]; 1540 | 1541 | for(int index=0; indexm_total; ++index) 1542 | { 1543 | area[index] = CalcRectVolume(&a_parVars->m_branchBuf[index].m_rect); 1544 | } 1545 | 1546 | firstTime = true; 1547 | for(int indexA=0; indexA < a_parVars->m_total-1; ++indexA) 1548 | { 1549 | for(int indexB = indexA+1; indexB < a_parVars->m_total; ++indexB) 1550 | { 1551 | Rect oneRect = CombineRect(&a_parVars->m_branchBuf[indexA].m_rect, &a_parVars->m_branchBuf[indexB].m_rect); 1552 | waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB]; 1553 | if(firstTime || waste > worst) 1554 | { 1555 | firstTime = false; 1556 | worst = waste; 1557 | seed0 = indexA; 1558 | seed1 = indexB; 1559 | } 1560 | } 1561 | } 1562 | RTREE_ASSERT(!firstTime); 1563 | 1564 | Classify(seed0, 0, a_parVars); 1565 | Classify(seed1, 1, a_parVars); 1566 | } 1567 | 1568 | 1569 | // Put a branch in one of the groups. 1570 | RTREE_TEMPLATE 1571 | void RTREE_QUAL::Classify(int a_index, int a_group, PartitionVars* a_parVars) 1572 | { 1573 | RTREE_ASSERT(a_parVars); 1574 | RTREE_ASSERT(PartitionVars::NOT_TAKEN == a_parVars->m_partition[a_index]); 1575 | 1576 | a_parVars->m_partition[a_index] = a_group; 1577 | 1578 | // Calculate combined rect 1579 | if (a_parVars->m_count[a_group] == 0) 1580 | { 1581 | a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect; 1582 | } 1583 | else 1584 | { 1585 | a_parVars->m_cover[a_group] = CombineRect(&a_parVars->m_branchBuf[a_index].m_rect, &a_parVars->m_cover[a_group]); 1586 | } 1587 | 1588 | // Calculate volume of combined rect 1589 | a_parVars->m_area[a_group] = CalcRectVolume(&a_parVars->m_cover[a_group]); 1590 | 1591 | ++a_parVars->m_count[a_group]; 1592 | } 1593 | 1594 | 1595 | // Delete a data rectangle from an index structure. 1596 | // Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. 1597 | // Returns 1 if record not found, 0 if success. 1598 | // RemoveRect provides for eliminating the root. 1599 | RTREE_TEMPLATE 1600 | bool RTREE_QUAL::RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root) 1601 | { 1602 | RTREE_ASSERT(a_root); 1603 | RTREE_ASSERT(*a_root); 1604 | 1605 | ListNode* reInsertList = NULL; 1606 | 1607 | if(!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList)) 1608 | { 1609 | // Found and deleted a data item 1610 | // Reinsert any branches from eliminated nodes 1611 | while(reInsertList) 1612 | { 1613 | Node* tempNode = reInsertList->m_node; 1614 | 1615 | for(int index = 0; index < tempNode->m_count; ++index) 1616 | { 1617 | // TODO go over this code. should I use (tempNode->m_level - 1)? 1618 | InsertRect(tempNode->m_branch[index], 1619 | a_root, 1620 | tempNode->m_level); 1621 | } 1622 | 1623 | ListNode* remLNode = reInsertList; 1624 | reInsertList = reInsertList->m_next; 1625 | 1626 | FreeNode(remLNode->m_node); 1627 | FreeListNode(remLNode); 1628 | } 1629 | 1630 | // Check for redundant root (not leaf, 1 child) and eliminate TODO replace 1631 | // if with while? In case there is a whole branch of redundant roots... 1632 | if((*a_root)->m_count == 1 && (*a_root)->IsInternalNode()) 1633 | { 1634 | Node* tempNode = (*a_root)->m_branch[0].m_child; 1635 | 1636 | RTREE_ASSERT(tempNode); 1637 | FreeNode(*a_root); 1638 | *a_root = tempNode; 1639 | } 1640 | return false; 1641 | } 1642 | else 1643 | { 1644 | return true; 1645 | } 1646 | } 1647 | 1648 | 1649 | // Delete a rectangle from non-root part of an index structure. 1650 | // Called by RemoveRect. Descends tree recursively, 1651 | // merges branches on the way back up. 1652 | // Returns 1 if record not found, 0 if success. 1653 | RTREE_TEMPLATE 1654 | bool RTREE_QUAL::RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode) 1655 | { 1656 | RTREE_ASSERT(a_node && a_listNode); 1657 | RTREE_ASSERT(a_node->m_level >= 0); 1658 | 1659 | if(a_node->IsInternalNode()) // not a leaf node 1660 | { 1661 | for(int index = 0; index < a_node->m_count; ++index) 1662 | { 1663 | if(a_rect == NULL || Overlap(a_rect, &(a_node->m_branch[index].m_rect))) 1664 | { 1665 | if(!RemoveRectRec(a_rect, a_id, a_node->m_branch[index].m_child, a_listNode)) 1666 | { 1667 | if(a_node->m_branch[index].m_child->m_count >= MINNODES) 1668 | { 1669 | // child removed, just resize parent rect 1670 | a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); 1671 | } 1672 | else 1673 | { 1674 | // child removed, not enough entries in node, eliminate node 1675 | ReInsert(a_node->m_branch[index].m_child, a_listNode); 1676 | DisconnectBranch(a_node, index); // Must return after this call as count has changed 1677 | } 1678 | return false; 1679 | } 1680 | } 1681 | } 1682 | return true; 1683 | } 1684 | else // A leaf node 1685 | { 1686 | for(int index = 0; index < a_node->m_count; ++index) 1687 | { 1688 | if(a_node->m_branch[index].m_data == a_id) 1689 | { 1690 | DisconnectBranch(a_node, index); // Must return after this call as count has changed 1691 | return false; 1692 | } 1693 | } 1694 | return true; 1695 | } 1696 | } 1697 | 1698 | 1699 | // Decide whether two rectangles overlap. 1700 | RTREE_TEMPLATE 1701 | bool RTREE_QUAL::Overlap(Rect* a_rectA, Rect* a_rectB) const 1702 | { 1703 | RTREE_ASSERT(a_rectA && a_rectB); 1704 | 1705 | for(int index=0; index < NUMDIMS; ++index) 1706 | { 1707 | if (a_rectA->m_min[index] > a_rectB->m_max[index] || 1708 | a_rectB->m_min[index] > a_rectA->m_max[index]) 1709 | { 1710 | return false; 1711 | } 1712 | } 1713 | return true; 1714 | } 1715 | 1716 | // Decide whether two rectangles overlap. 1717 | RTREE_TEMPLATE 1718 | ELEMTYPE RTREE_QUAL::SquareDistance(Rect const& a_rectA, Rect const& a_rectB) const 1719 | { 1720 | ELEMTYPE dist{}; 1721 | 1722 | for (int index = 0; index < NUMDIMS; ++index) 1723 | { 1724 | auto diff1 = a_rectA.m_min[index] - a_rectB.m_max[index]; 1725 | auto diff2 = a_rectA.m_max[index] - a_rectB.m_min[index]; 1726 | 1727 | dist += diff1 * diff2 < 0 ? 0 : std::min(diff1 * diff1, diff2 * diff2); 1728 | 1729 | } 1730 | return dist; 1731 | } 1732 | 1733 | // Add a node to the reinsertion list. All its branches will later 1734 | // be reinserted into the index structure. 1735 | RTREE_TEMPLATE 1736 | void RTREE_QUAL::ReInsert(Node* a_node, ListNode** a_listNode) 1737 | { 1738 | ListNode* newListNode; 1739 | 1740 | newListNode = AllocListNode(); 1741 | newListNode->m_node = a_node; 1742 | newListNode->m_next = *a_listNode; 1743 | *a_listNode = newListNode; 1744 | } 1745 | 1746 | 1747 | // Search in an index tree or subtree for all data retangles that overlap the argument rectangle. 1748 | RTREE_TEMPLATE 1749 | bool RTREE_QUAL::Search(Node* a_node, Rect* a_rect, int& a_foundCount, std::function callback) const 1750 | { 1751 | RTREE_ASSERT(a_node); 1752 | RTREE_ASSERT(a_node->m_level >= 0); 1753 | RTREE_ASSERT(a_rect); 1754 | 1755 | if(a_node->IsInternalNode()) 1756 | { 1757 | // This is an internal node in the tree 1758 | for(int index=0; index < a_node->m_count; ++index) 1759 | { 1760 | if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) 1761 | { 1762 | if(!Search(a_node->m_branch[index].m_child, a_rect, a_foundCount, callback)) 1763 | { 1764 | // The callback indicated to stop searching 1765 | return false; 1766 | } 1767 | } 1768 | } 1769 | } 1770 | else 1771 | { 1772 | // This is a leaf node 1773 | for(int index=0; index < a_node->m_count; ++index) 1774 | { 1775 | if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) 1776 | { 1777 | DATATYPE& id = a_node->m_branch[index].m_data; 1778 | ++a_foundCount; 1779 | 1780 | if(callback && !callback(id)) 1781 | { 1782 | return false; // Don't continue searching 1783 | } 1784 | } 1785 | } 1786 | } 1787 | 1788 | return true; // Continue searching 1789 | } 1790 | 1791 | 1792 | RTREE_TEMPLATE 1793 | std::vector RTREE_QUAL::ListTree() const 1794 | { 1795 | RTREE_ASSERT(m_root); 1796 | RTREE_ASSERT(m_root->m_level >= 0); 1797 | 1798 | std::vector treeList; 1799 | 1800 | std::vector toVisit; 1801 | toVisit.push_back(m_root); 1802 | 1803 | while (!toVisit.empty()) { 1804 | Node* a_node = toVisit.back(); 1805 | toVisit.pop_back(); 1806 | if(a_node->IsInternalNode()) 1807 | { 1808 | // This is an internal node in the tree 1809 | for(int index=0; index < a_node->m_count; ++index) 1810 | { 1811 | treeList.push_back(a_node->m_branch[index].m_rect); 1812 | toVisit.push_back(a_node->m_branch[index].m_child); 1813 | } 1814 | } 1815 | else 1816 | { 1817 | // This is a leaf node 1818 | for(int index=0; index < a_node->m_count; ++index) 1819 | { 1820 | treeList.push_back(a_node->m_branch[index].m_rect); 1821 | } 1822 | } 1823 | } 1824 | 1825 | return treeList; 1826 | } 1827 | 1828 | 1829 | #undef RTREE_TEMPLATE 1830 | #undef RTREE_QUAL 1831 | 1832 | #endif //RTREE_H 1833 | 1834 | --------------------------------------------------------------------------------