mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[pal] Bring back refined upstream version of superliminal rtree index
Turns out this index is MUCH (magnitudes) faster for use in pal. So grab an updated version of the upstream library and place in external libs, and use this for indices in pal. (we should probably investigate whether this is faster for snapping and other index use too!)
This commit is contained in:
parent
7464290ae3
commit
da5cd52162
0
external/rtree/.Rhistory
vendored
Normal file
0
external/rtree/.Rhistory
vendored
Normal file
26
external/rtree/CMakeLists.txt
vendored
Normal file
26
external/rtree/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# CMake version check
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
|
||||
# Check build directory
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source.")
|
||||
endif()
|
||||
|
||||
# RTree project
|
||||
project(RTree
|
||||
VERSION 0.1.0)
|
||||
|
||||
# Project build options
|
||||
option(RTREE_BUILD_TESTS "Build test programs" OFF)
|
||||
|
||||
# RTree as header only library
|
||||
add_library(RTree INTERFACE)
|
||||
target_include_directories(RTree
|
||||
INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_compile_features(RTree
|
||||
INTERFACE cxx_std_11)
|
||||
|
||||
# Tests
|
||||
if (RTREE_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
56
external/rtree/CMakeSettings.json
vendored
Normal file
56
external/rtree/CMakeSettings.json
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-Wno-dev -DRTREE_BUILD_TESTS=ON",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-Wno-dev -DRTREE_BUILD_TESTS=ON",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x86"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-Wno-dev -DRTREE_BUILD_TESTS=ON",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x86"
|
||||
],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-Wno-dev -DRTREE_BUILD_TESTS=ON",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
84
external/rtree/README.md
vendored
Normal file
84
external/rtree/README.md
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
# R-Trees: A Dynamic Index Structure for Spatial Searching
|
||||
|
||||
## Description
|
||||
|
||||
A C++ templated version of [this](http://www.superliminal.com/sources/sources.htm)
|
||||
RTree algorithm.
|
||||
The code it now generally compatible with the STL and Boost C++ libraries.
|
||||
|
||||
## Usage
|
||||
|
||||
```cpp
|
||||
#include <RTree.h>
|
||||
|
||||
// ...
|
||||
|
||||
RTree<Foo*, double, 3> tree;
|
||||
double min[3] = {0., 0., 0.};
|
||||
double max[3] = {1., 1., 1.};
|
||||
Foo* bar = new Foo();
|
||||
tree.Insert(min, max, bar);
|
||||
```
|
||||
|
||||
Provides search in and iteration over the tree. For examples see
|
||||
[Test.cpp](https://github.com/nushoin/RTree/blob/master/Test.cpp)
|
||||
|
||||
## Testing
|
||||
|
||||
Run `make` to build and `make test` to run the tests. The RTree itself is
|
||||
a single header file and can be included without compiling.
|
||||
|
||||
## Authors
|
||||
|
||||
- 1983 Original algorithm and test code by Antonin Guttman and Michael Stonebraker, UC Berkely
|
||||
- 1994 ANCI C ported from original test code by Melinda Green - melinda@superliminal.com
|
||||
- 1995 Sphere volume fix for degeneracy problem submitted by Paul Brook
|
||||
- 2004 Templated C++ port by Greg Douglas
|
||||
- 2011 Modified the container to support more data types, by Yariv Barkan
|
||||
- 2017 Modified Search to take C++11 function to allow lambdas and added const qualifier, by Gero Mueller
|
||||
|
||||
## License
|
||||
|
||||
Original code was taken from http://www.superliminal.com/sources/sources.htm
|
||||
and is stored as git revision 0. This revision is entirely free for all
|
||||
uses. Enjoy!
|
||||
|
||||
Due to restrictions on public domain in certain jurisdictions, code
|
||||
contributed by Yariv Barkan is released in these jurisdictions under the
|
||||
BSD, MIT or the GPL - you may choose one or more, whichever that suits you
|
||||
best.
|
||||
|
||||
In jurisdictions where public domain property is recognized, the user of
|
||||
this software may choose to accept it either 1) as public domain, 2) under
|
||||
the conditions of the BSD, MIT or GPL or 3) any combination of public
|
||||
domain and one or more of these licenses.
|
||||
|
||||
Thanks [Baptiste Lepilleur](http://jsoncpp.sourceforge.net/LICENSE) for the
|
||||
licensing idea.
|
||||
|
||||
## Recent Change Log
|
||||
|
||||
### 31 Jan 2018
|
||||
|
||||
- Added copy constructor
|
||||
- Callback function is now `std::function`
|
||||
|
||||
### 05 Apr 2014
|
||||
|
||||
- Added tests
|
||||
|
||||
### 02 Sep 2011
|
||||
|
||||
- Modified the container to support more data types. The code it now generally
|
||||
compatible with the STL and Boost C++ libraries.
|
||||
|
||||
### 05 Jan 2010
|
||||
|
||||
- Fixed Iterator GetFirst() - Previous fix was not incomplete
|
||||
|
||||
### 03 Dec 2009
|
||||
|
||||
- Added Iteartor GetBounds()
|
||||
- Added Iterator usage to simple test
|
||||
- Fixed Iterator GetFirst() - Thanks Mathew Riek
|
||||
- Minor updates for MSVC 2005/08 compilers
|
1331
external/rtree/include/RTree.h
vendored
Normal file
1331
external/rtree/include/RTree.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
external/rtree/source.txt
vendored
Normal file
3
external/rtree/source.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Taken from https://github.com/DevHwan/RTree, at the last commit before c++17 support was required
|
||||
(https://github.com/DevHwan/RTree/commit/b6688880dfced02879f98dcb24dd8db0d09efce7)
|
||||
|
46
external/rtree/tests/CMakeLists.txt
vendored
Normal file
46
external/rtree/tests/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# CMake version check
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
|
||||
# Default Test
|
||||
add_executable(Test_RTree
|
||||
Test.cpp)
|
||||
add_dependencies(Test_RTree
|
||||
RTree)
|
||||
target_include_directories(Test_RTree
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(Test_RTree
|
||||
PRIVATE RTree)
|
||||
if(MSVC)
|
||||
target_compile_options(Test_RTree
|
||||
PRIVATE /permissive- /sdl)
|
||||
target_compile_definitions(Test_RTree
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Memory Test file
|
||||
add_executable(Test_Memory_RTree
|
||||
MemoryTest.cpp)
|
||||
target_include_directories(Test_Memory_RTree
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(Test_Memory_RTree
|
||||
PRIVATE RTree)
|
||||
if(MSVC)
|
||||
target_compile_options(Test_Memory_RTree
|
||||
PRIVATE /permissive- /sdl)
|
||||
target_compile_definitions(Test_Memory_RTree
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Bad Data Test file
|
||||
add_executable(Test_BadData_RTree
|
||||
TestBadData.cpp)
|
||||
target_include_directories(Test_BadData_RTree
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(Test_BadData_RTree
|
||||
PRIVATE RTree)
|
||||
if(MSVC)
|
||||
target_compile_options(Test_BadData_RTree
|
||||
PRIVATE /permissive- /sdl)
|
||||
target_compile_definitions(Test_BadData_RTree
|
||||
PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
246
external/rtree/tests/MemoryTest.cpp
vendored
Normal file
246
external/rtree/tests/MemoryTest.cpp
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
//
|
||||
// MemoryTest.cpp
|
||||
//
|
||||
// This demonstrates a use of RTree
|
||||
//
|
||||
|
||||
// RTree
|
||||
#include <RTree.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#ifdef WIN32
|
||||
#include <crtdbg.h>
|
||||
#endif //WIN32
|
||||
|
||||
#include <random>
|
||||
|
||||
// Use CRT Debug facility to dump memory leaks on app exit
|
||||
#ifdef WIN32
|
||||
// These two are for MSVS 2005 security consciousness until safe std lib funcs are available
|
||||
#pragma warning(disable : 4996) // Deprecated functions
|
||||
#define _CRT_SECURE_NO_DEPRECATE // Allow old unsecure standard library functions, Disable some 'warning C4996 - function was deprecated'
|
||||
|
||||
// The following macros set and clear, respectively, given bits
|
||||
// of the C runtime library debug flag, as specified by a bitmask.
|
||||
#ifdef _DEBUG
|
||||
#define SET_CRT_DEBUG_FIELD(a) \
|
||||
_CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
|
||||
#define CLEAR_CRT_DEBUG_FIELD(a) \
|
||||
_CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
|
||||
#else
|
||||
#define SET_CRT_DEBUG_FIELD(a) ((void) 0)
|
||||
#define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
|
||||
#endif
|
||||
#endif //WIN32
|
||||
|
||||
//
|
||||
// Get a random float b/n two values
|
||||
// The returned value is >= min && < max (exclusive of max)
|
||||
//
|
||||
static std::random_device sRandomDevice;
|
||||
static std::mt19937 sMT(sRandomDevice());
|
||||
static float RandFloat(float a_min, float a_max)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(a_min, a_max);
|
||||
return distribution(sMT);
|
||||
}
|
||||
|
||||
|
||||
/// Simplify handling of 3 dimensional coordinate
|
||||
struct Vec3
|
||||
{
|
||||
/// Default constructor
|
||||
Vec3() noexcept = default;
|
||||
|
||||
/// Construct from three elements
|
||||
constexpr Vec3(float a_x, float a_y, float a_z) noexcept
|
||||
: fVal{ a_x, a_y, a_z }
|
||||
{
|
||||
}
|
||||
|
||||
/// Add two vectors and return result
|
||||
Vec3 operator+ (const Vec3& a_other) const
|
||||
{
|
||||
return Vec3(fVal[0] + a_other.fVal[0],
|
||||
fVal[1] + a_other.fVal[1],
|
||||
fVal[2] + a_other.fVal[2]);
|
||||
}
|
||||
|
||||
float fVal[3] = { 0.0f, }; ///< 3 float components for axes or dimensions
|
||||
};
|
||||
|
||||
|
||||
static bool BoxesIntersect(const Vec3& a_boxMinA, const Vec3& a_boxMaxA,
|
||||
const Vec3& a_boxMinB, const Vec3& a_boxMaxB)
|
||||
{
|
||||
if (a_boxMinA.fVal[0] > a_boxMaxB.fVal[0] || a_boxMaxA.fVal[0] < a_boxMinB.fVal[0])
|
||||
return false;
|
||||
if (a_boxMinA.fVal[1] > a_boxMaxB.fVal[1] || a_boxMaxA.fVal[1] < a_boxMinB.fVal[1])
|
||||
return false;
|
||||
if (a_boxMinA.fVal[2] > a_boxMaxB.fVal[2] || a_boxMaxA.fVal[2] < a_boxMinB.fVal[2])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// A user type to test with, instead of a simple type such as an 'int'
|
||||
struct SomeThing
|
||||
{
|
||||
SomeThing()
|
||||
{
|
||||
++s_outstandingAllocs;
|
||||
}
|
||||
~SomeThing()
|
||||
{
|
||||
--s_outstandingAllocs;
|
||||
}
|
||||
|
||||
int m_creationCounter; ///< Just a number for identifying within test program
|
||||
Vec3 m_min, m_max; ///< Minimal bounding rect, values must be known and constant in order to remove from RTree
|
||||
|
||||
static int s_outstandingAllocs; ///< Count how many outstanding objects remain
|
||||
};
|
||||
|
||||
/// Init static
|
||||
int SomeThing::s_outstandingAllocs = 0;
|
||||
|
||||
|
||||
/// A callback function to obtain query results in this implementation
|
||||
bool QueryResultCallback(SomeThing* a_data)
|
||||
{
|
||||
printf("search found %d\n", a_data->m_creationCounter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
constexpr const int NUM_OBJECTS = 40; // Number of objects in test set
|
||||
constexpr const int FRAC_OBJECTS = 4;
|
||||
static_assert(NUM_OBJECTS > FRAC_OBJECTS, "NUM_OBJECTS must be bigger than FRAC_OBJECTS for this test");
|
||||
|
||||
constexpr const float MAX_WORLDSIZE = 10.0f;
|
||||
constexpr const float FRAC_WORLDSIZE = MAX_WORLDSIZE / 2;
|
||||
|
||||
// typedef the RTree useage just for conveniance with iteration
|
||||
using SomeThingTree = RTree<SomeThing*, float, 3>;
|
||||
|
||||
SomeThing* thingArray[NUM_OBJECTS * 2] = { nullptr, }; // Store objects in another container to test with, sized larger than we need
|
||||
|
||||
// Create intance of RTree
|
||||
|
||||
SomeThingTree tree;
|
||||
|
||||
|
||||
// Add some nodes
|
||||
int counter = 0;
|
||||
for (int index = 0; index < NUM_OBJECTS; ++index)
|
||||
{
|
||||
auto newThing = new SomeThing{};
|
||||
|
||||
newThing->m_creationCounter = counter++;
|
||||
newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE));
|
||||
Vec3 extent = Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE));
|
||||
newThing->m_max = newThing->m_min + extent;
|
||||
|
||||
thingArray[counter - 1] = newThing;
|
||||
|
||||
tree.Insert(newThing->m_min.fVal, newThing->m_max.fVal, newThing);
|
||||
printf("inserting %d\n", newThing->m_creationCounter);
|
||||
}
|
||||
|
||||
printf("tree count = %d\n", tree.Count());
|
||||
|
||||
int numToDelete = NUM_OBJECTS / FRAC_OBJECTS;
|
||||
int numToStep = FRAC_OBJECTS;
|
||||
|
||||
// Delete some nodes
|
||||
for (int index = 0; index < NUM_OBJECTS; index += numToStep)
|
||||
{
|
||||
auto curThing = thingArray[index];
|
||||
|
||||
if (curThing)
|
||||
{
|
||||
tree.Remove(curThing->m_min.fVal, curThing->m_max.fVal, curThing);
|
||||
printf("removing %d\n", curThing->m_creationCounter);
|
||||
|
||||
delete curThing;
|
||||
thingArray[index] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
printf("tree count = %d\n", tree.Count());
|
||||
|
||||
// Add some more nodes
|
||||
for (int index = 0; index < numToDelete; ++index)
|
||||
{
|
||||
auto newThing = new SomeThing{};
|
||||
|
||||
newThing->m_creationCounter = counter++;
|
||||
newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE));
|
||||
Vec3 extent = Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE));
|
||||
newThing->m_max = newThing->m_min + extent;
|
||||
|
||||
thingArray[counter - 1] = newThing;
|
||||
|
||||
tree.Insert(newThing->m_min.fVal, newThing->m_max.fVal, newThing);
|
||||
printf("inserting %d\n", newThing->m_creationCounter);
|
||||
}
|
||||
|
||||
printf("tree count = %d\n", tree.Count());
|
||||
|
||||
Vec3 searchMin(0, 0, 0);
|
||||
Vec3 searchMax(FRAC_WORLDSIZE, FRAC_WORLDSIZE, FRAC_WORLDSIZE);
|
||||
tree.Search(searchMin.fVal, searchMax.fVal, &QueryResultCallback);
|
||||
|
||||
// NOTE: Even better than just dumping text, it would be nice to render the
|
||||
// tree contents and search result for visualization.
|
||||
|
||||
|
||||
// List values. Iterator is NOT delete safe
|
||||
SomeThingTree::Iterator it;
|
||||
for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it))
|
||||
{
|
||||
SomeThing* curThing = tree.GetAt(it);
|
||||
|
||||
if (BoxesIntersect(searchMin, searchMax, curThing->m_min, curThing->m_max))
|
||||
{
|
||||
printf("brute found %d\n", curThing->m_creationCounter);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete our nodes, NOTE, we are NOT deleting the tree nodes, just our data
|
||||
// of course the tree will now contain invalid pointers that must not be used any more.
|
||||
for (tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it))
|
||||
{
|
||||
SomeThing* removeElem = tree.GetAt(it);
|
||||
if (removeElem)
|
||||
{
|
||||
printf("deleting %d\n", removeElem->m_creationCounter);
|
||||
delete removeElem;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all contents (This would have happened automatically during destructor)
|
||||
tree.RemoveAll();
|
||||
|
||||
if (SomeThing::s_outstandingAllocs > 0)
|
||||
{
|
||||
printf("Memory leak!\n");
|
||||
printf("s_outstandingAllocs = %d\n", SomeThing::s_outstandingAllocs);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("No memory leaks detected by app\n");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// Use CRT Debug facility to dump memory leaks on app exit
|
||||
SET_CRT_DEBUG_FIELD(_CRTDBG_LEAK_CHECK_DF);
|
||||
#endif //WIN32
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
149
external/rtree/tests/Test.cpp
vendored
Normal file
149
external/rtree/tests/Test.cpp
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
//
|
||||
// Test.cpp
|
||||
//
|
||||
// This is a direct port of the C version of the RTree test program.
|
||||
//
|
||||
|
||||
// RTree
|
||||
#include <RTree.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef int ValueType;
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect() noexcept = default;
|
||||
|
||||
constexpr Rect(int a_minX, int a_minY, int a_maxX, int a_maxY) noexcept
|
||||
: fMin{ a_minX, a_minY }
|
||||
, fMax{ a_maxX, a_maxY }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int fMin[2] = { 0, };
|
||||
int fMax[2] = { 0, };
|
||||
};
|
||||
|
||||
struct Rect rects[] =
|
||||
{
|
||||
Rect(0, 0, 2, 2), // xmin, ymin, xmax, ymax (for 2 dimensional RTree)
|
||||
Rect(5, 5, 7, 7),
|
||||
Rect(8, 5, 9, 6),
|
||||
Rect(7, 1, 9, 2),
|
||||
};
|
||||
|
||||
constexpr const auto nrects = sizeof(rects) / sizeof(rects[0]);
|
||||
|
||||
Rect search_rect(6, 4, 10, 6); // search will find above rects that this one overlaps
|
||||
|
||||
|
||||
bool MySearchCallback(ValueType id)
|
||||
{
|
||||
cout << "Hit data rect " << id << "\n";
|
||||
return true; // keep going
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using MyTree = RTree<ValueType, int, 2, float>;
|
||||
static_assert(std::is_same<MyTree::ElementType, int>::value, "ElementType must match");
|
||||
static_assert(std::is_same<MyTree::Element, int[2]>::value, "Element must match");
|
||||
static_assert(std::is_same<MyTree::ElementTypeReal, float>::value, "ElementTypeReal must match");
|
||||
static_assert(MyTree::kNumDimensions == 2, "Dimension must match");
|
||||
|
||||
MyTree tree;
|
||||
|
||||
cout << "nrects = " << nrects << "\n";
|
||||
|
||||
for (size_t i = 0; i < nrects; i++)
|
||||
{
|
||||
tree.Insert(rects[i].fMin, rects[i].fMax, static_cast<int>(i)); // Note, all values including zero are fine in this version
|
||||
}
|
||||
|
||||
const auto nhits = tree.Search(search_rect.fMin, search_rect.fMax, MySearchCallback);
|
||||
|
||||
cout << "Search resulted in " << nhits << " hits\n";
|
||||
|
||||
// Iterator test
|
||||
int itIndex = 0;
|
||||
MyTree::Iterator it;
|
||||
for (tree.GetFirst(it);
|
||||
!tree.IsNull(it);
|
||||
tree.GetNext(it))
|
||||
{
|
||||
int value = tree.GetAt(it);
|
||||
|
||||
int boundsMin[2] = { 0,0 };
|
||||
int boundsMax[2] = { 0,0 };
|
||||
it.GetBounds(boundsMin, boundsMax);
|
||||
cout << "it[" << itIndex++ << "] " << value << " = (" << boundsMin[0] << "," << boundsMin[1] << "," << boundsMax[0] << "," << boundsMax[1] << ")\n";
|
||||
}
|
||||
|
||||
// Iterator test, alternate syntax
|
||||
itIndex = 0;
|
||||
tree.GetFirst(it);
|
||||
while (!it.IsNull())
|
||||
{
|
||||
int value = *it;
|
||||
++it;
|
||||
cout << "it[" << itIndex++ << "] " << value << "\n";
|
||||
}
|
||||
|
||||
// test copy constructor
|
||||
MyTree copy = tree;
|
||||
|
||||
// Iterator test
|
||||
itIndex = 0;
|
||||
for (copy.GetFirst(it);
|
||||
!copy.IsNull(it);
|
||||
copy.GetNext(it))
|
||||
{
|
||||
int value = copy.GetAt(it);
|
||||
|
||||
int boundsMin[2] = { 0,0 };
|
||||
int boundsMax[2] = { 0,0 };
|
||||
it.GetBounds(boundsMin, boundsMax);
|
||||
cout << "it[" << itIndex++ << "] " << value << " = (" << boundsMin[0] << "," << boundsMin[1] << "," << boundsMax[0] << "," << boundsMax[1] << ")\n";
|
||||
}
|
||||
|
||||
// Iterator test, alternate syntax
|
||||
itIndex = 0;
|
||||
copy.GetFirst(it);
|
||||
while (!it.IsNull())
|
||||
{
|
||||
int value = *it;
|
||||
++it;
|
||||
cout << "it[" << itIndex++ << "] " << value << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
// Output:
|
||||
//
|
||||
// nrects = 4
|
||||
// Hit data rect 1
|
||||
// Hit data rect 2
|
||||
// Search resulted in 2 hits
|
||||
// it[0] 0 = (0,0,2,2)
|
||||
// it[1] 1 = (5,5,7,7)
|
||||
// it[2] 2 = (8,5,9,6)
|
||||
// it[3] 3 = (7,1,9,2)
|
||||
// it[0] 0
|
||||
// it[1] 1
|
||||
// it[2] 2
|
||||
// it[3] 3
|
||||
// it[0] 0 = (0,0,2,2)
|
||||
// it[1] 1 = (5,5,7,7)
|
||||
// it[2] 2 = (8,5,9,6)
|
||||
// it[3] 3 = (7,1,9,2)
|
||||
// it[0] 0
|
||||
// it[1] 1
|
||||
// it[2] 2
|
||||
// it[3] 3
|
||||
}
|
||||
|
111
external/rtree/tests/TestBadData.cpp
vendored
Normal file
111
external/rtree/tests/TestBadData.cpp
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// TestBadData.cpp
|
||||
//
|
||||
|
||||
// RTree
|
||||
#include <RTree.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef int ValueType;
|
||||
typedef long long CoordType;
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect() noexcept = default;
|
||||
|
||||
constexpr Rect(CoordType a_minX, CoordType a_minY, CoordType a_maxX, CoordType a_maxY) noexcept
|
||||
: fMin{ a_minX, a_minY }
|
||||
, fMax{ a_maxX, a_maxY }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CoordType fMin[2] = { 0, };
|
||||
CoordType fMax[2] = { 0, };
|
||||
};
|
||||
|
||||
|
||||
bool MySearchCallback(ValueType id)
|
||||
{
|
||||
cout << "Hit data rect " << id << "\n";
|
||||
return true; // keep going
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage: " << argv[0] << " inFile\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
using RectVector = std::vector<Rect>;
|
||||
RectVector rectVector;
|
||||
|
||||
// read the data
|
||||
{
|
||||
ifstream inFile(argv[1]);
|
||||
if (!inFile.is_open()) {
|
||||
std::cerr << "Can't open input file\n";
|
||||
return -1;
|
||||
}
|
||||
while (!inFile.eof()) {
|
||||
// security and robustness be damned
|
||||
CoordType xmin, ymin, xmax, ymax;
|
||||
string dummy;
|
||||
inFile >> xmin >> ymin >> xmax >> ymax;
|
||||
cout << xmin << " " << ymin << " " << xmax << " " << ymax << "\n";
|
||||
rectVector.emplace_back(xmin, ymin, xmin + xmax, ymin + ymax);
|
||||
}
|
||||
}
|
||||
|
||||
using MyTree = RTree<ValueType, CoordType, 2, float>;
|
||||
MyTree tree;
|
||||
|
||||
int i, nhits;
|
||||
cout << "number of rectangles is " << rectVector.size() << "\n";
|
||||
|
||||
for (i = 0; i < rectVector.size(); i++)
|
||||
{
|
||||
tree.Insert(rectVector[i].fMin, rectVector[i].fMax, i); // Note, all values including zero are fine in this version
|
||||
}
|
||||
|
||||
Rect search_rect(6, 4, 10, 6);
|
||||
nhits = tree.Search(search_rect.fMin, search_rect.fMax, MySearchCallback);
|
||||
|
||||
cout << "Search resulted in " << nhits << " hits\n";
|
||||
|
||||
// Iterator test
|
||||
int itIndex = 0;
|
||||
MyTree::Iterator it;
|
||||
for (tree.GetFirst(it);
|
||||
!tree.IsNull(it);
|
||||
tree.GetNext(it))
|
||||
{
|
||||
int value = tree.GetAt(it);
|
||||
|
||||
CoordType boundsMin[2] = { 0,0 };
|
||||
CoordType boundsMax[2] = { 0,0 };
|
||||
it.GetBounds(boundsMin, boundsMax);
|
||||
cout << "it[" << itIndex++ << "] " << value << " = (" << boundsMin[0] << "," << boundsMin[1] << "," << boundsMax[0] << "," << boundsMax[1] << ")\n";
|
||||
}
|
||||
|
||||
// Iterator test, alternate syntax
|
||||
itIndex = 0;
|
||||
tree.GetFirst(it);
|
||||
while (!it.IsNull())
|
||||
{
|
||||
CoordType value = *it;
|
||||
++it;
|
||||
cout << "it[" << itIndex++ << "] " << value << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
174
external/rtree/tests/baddata.txt
vendored
Normal file
174
external/rtree/tests/baddata.txt
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120182105 20050120182105 32743 32743
|
||||
20050120181004 20050120181004 32743 32743
|
||||
20050120185604 20050120185604 32743 32743
|
||||
20050120191706 20050120192143 32743 32743
|
||||
20050129054438 20050129054455 32743 32743
|
||||
20050125004242 20050127004348 32743 32743
|
||||
20050127080821 20050127080821 32743 32743
|
||||
20050103232047 20050103232047 32743 32743
|
||||
20050103231608 20050103231953 32743 32743
|
||||
20050103232124 20050103233547 32743 32743
|
||||
20050103234758 20050103234758 32743 32743
|
||||
20050113072936 20050113072936 32743 32743
|
||||
20050105014304 20050111225505 32743 32743
|
||||
20050117025915 20050118054001 32743 32743
|
||||
20050118064200 20050119020157 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041231081821 20041231081821 32743 32743
|
||||
20041231084441 20050101210045 32743 32743
|
||||
20041231053402 20041231053402 32743 32743
|
||||
20041227225557 20041228062229 32743 32743
|
||||
20041227003512 20041227003512 32743 32743
|
||||
20041227004805 20041227074924 32743 32743
|
||||
20041227080309 20041227080309 32743 32743
|
||||
20041227075241 20041227075241 32743 32743
|
||||
20041227000445 20041227000931 32743 32743
|
||||
20041227003006 20041227003006 32743 32743
|
||||
20050120181004 20050120182105 32743 32743
|
||||
20050120183502 20050120183502 32743 32743
|
||||
20050101213828 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
||||
20050119201652 20050120105309 32743 32743
|
||||
20050120185604 20050120185604 32743 32743
|
||||
20050120191706 20050120192143 32743 32743
|
||||
20050129054438 20050130172429 32743 32743
|
||||
20050125004242 20050127004348 32743 32743
|
||||
20050127080821 20050127080821 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120182105 20050120182105 32743 32743
|
||||
20050120181004 20050120181004 32743 32743
|
||||
20050120185604 20050120185604 32743 32743
|
||||
20050120191706 20050120192143 32743 32743
|
||||
20050129054438 20050129054455 32743 32743
|
||||
20050125004242 20050127004348 32743 32743
|
||||
20050127080821 20050127080821 32743 32743
|
||||
20050103232047 20050103232047 32743 32743
|
||||
20050103231608 20050103231953 32743 32743
|
||||
20050103232124 20050103233547 32743 32743
|
||||
20050103234758 20050103234758 32743 32743
|
||||
20050113072936 20050113072936 32743 32743
|
||||
20050105014304 20050111225505 32743 32743
|
||||
20050117025915 20050118054001 32743 32743
|
||||
20050118064200 20050119020157 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041227000445 20041227080309 32743 32743
|
||||
20041227225557 20050102160402 32743 32743
|
||||
20050103024822 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
||||
20050120073145 20050120181004 32743 32743
|
||||
20050120182105 20050120182105 32743 32743
|
||||
20050120185604 20050120192143 32743 32743
|
||||
20050125004242 20050130172429 32743 32743
|
||||
20041227225454 20041227225454 32743 32743
|
||||
20050119201652 20050119201652 32743 32743
|
||||
20050120183502 20050120183502 32743 32743
|
||||
20050120212256 20050120212256 32743 32743
|
||||
20050122001605 20050122001605 32743 32743
|
||||
20050120182105 20050120182105 32743 32743
|
||||
20050120181004 20050120181004 32743 32743
|
||||
20050120185604 20050120185604 32743 32743
|
||||
20050120191706 20050120192143 32743 32743
|
||||
20050129054438 20050130172429 32743 32743
|
||||
20050125004242 20050127004348 32743 32743
|
||||
20050127080821 20050127080821 32743 32743
|
||||
20041231081821 20050101210045 32743 32743
|
||||
20041227225557 20041231053402 32743 32743
|
||||
20041227003512 20041227074924 32743 32743
|
||||
20041227075241 20041227080309 32743 32743
|
||||
20041227003340 20041227003340 32743 32743
|
||||
20041227000445 20041227003006 32743 32743
|
||||
20050103224855 20050103234758 32743 32743
|
||||
20050105014304 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
||||
20050101213828 20050101213828 32743 32743
|
||||
20050102160402 20050102160402 32743 32743
|
||||
20050103024822 20050103025321 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120105309 20050120105309 32743 32743
|
||||
20050120073145 20050120073145 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050103232124 20050103232503 32743 32743
|
||||
20050103232710 20050103232710 32743 32743
|
||||
20050105034455 20050106034834 32743 32743
|
||||
20050106215124 20050111225505 32743 32743
|
||||
20050106035210 20050106035210 32743 32743
|
||||
20050117213917 20050118025128 32743 32743
|
||||
20050118025641 20050118025641 32743 32743
|
||||
20050118065543 20050118065543 32743 32743
|
||||
20050119020157 20050119020157 32743 32743
|
||||
20050118064200 20050118064200 32743 32743
|
||||
20050118064228 20050118064228 32743 32743
|
||||
20050120181004 20050120182105 32743 32743
|
||||
20050120185604 20050120192143 32743 32743
|
||||
20050125004242 20050129054455 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120182105 20050120182105 32743 32743
|
||||
20050120181004 20050120181004 32743 32743
|
||||
20050120185604 20050120185604 32743 32743
|
||||
20050120191706 20050120192143 32743 32743
|
||||
20050129054438 20050129054455 32743 32743
|
||||
20050125004242 20050127004348 32743 32743
|
||||
20050127080821 20050127080821 32743 32743
|
||||
20050103232047 20050103232047 32743 32743
|
||||
20050103231608 20050103231953 32743 32743
|
||||
20050103232124 20050103233547 32743 32743
|
||||
20050103234758 20050103234758 32743 32743
|
||||
20050113072936 20050113072936 32743 32743
|
||||
20050105014304 20050111225505 32743 32743
|
||||
20050117025915 20050118054001 32743 32743
|
||||
20050118064200 20050119020157 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120191706 20050120191706 32743 32743
|
||||
20050120192143 20050120192143 32743 32743
|
||||
20050129054438 20050129054438 32743 32743
|
||||
20050129054455 20050130172429 32743 32743
|
||||
20050125004242 20050125035134 32743 32743
|
||||
20050126112156 20050127004348 32743 32743
|
||||
20041227225454 20050101210045 32743 32743
|
||||
20041227000445 20041227080309 32743 32743
|
||||
20050101213828 20050101213828 32743 32743
|
||||
20050102160402 20050102160402 32743 32743
|
||||
20050103224855 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
||||
20050103024822 20050103025321 32743 32743
|
||||
20050119201652 20050119201652 32743 32743
|
||||
20050120073145 20050120105309 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120191706 20050120191706 32743 32743
|
||||
20050120192143 20050120192143 32743 32743
|
||||
20050129054438 20050129054438 32743 32743
|
||||
20050129054455 20050130172429 32743 32743
|
||||
20050125004242 20050125035134 32743 32743
|
||||
20050126112156 20050127004348 32743 32743
|
||||
20041227225454 20050101210045 32743 32743
|
||||
20041227000445 20041227080309 32743 32743
|
||||
20050101213828 20050101213828 32743 32743
|
||||
20050102160402 20050102160402 32743 32743
|
||||
20050103224855 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
||||
20050103024822 20050103025321 32743 32743
|
||||
20050119201652 20050119201652 32743 32743
|
||||
20050120073145 20050120105309 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20041225182812 20041225182812 32743 32743
|
||||
20050120191706 20050120191706 32743 32743
|
||||
20050120192143 20050120192143 32743 32743
|
||||
20050129054438 20050129054438 32743 32743
|
||||
20050129054455 20050130172429 32743 32743
|
||||
20050125004242 20050125035134 32743 32743
|
||||
20050126112156 20050127004348 32743 32743
|
||||
20041227225454 20050101210045 32743 32743
|
||||
20041227000445 20041227080309 32743 32743
|
||||
20050101213828 20050101213828 32743 32743
|
||||
20050102160402 20050102160402 32743 32743
|
||||
20050103224855 20050113072936 32743 32743
|
||||
20050117025915 20050119020157 32743 32743
|
@ -89,7 +89,7 @@ astyleit() {
|
||||
|
||||
for f in "$@"; do
|
||||
case "$f" in
|
||||
src/plugins/grass/qtermwidget/*|external/o2/*|external/qt-unix-signals/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*)
|
||||
src/plugins/grass/qtermwidget/*|external/o2/*|external/qt-unix-signals/*|external/rtree/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*)
|
||||
echo -ne "$f skipped $elcr"
|
||||
continue
|
||||
;;
|
||||
|
@ -1337,6 +1337,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/external/kdbush/include
|
||||
${CMAKE_SOURCE_DIR}/external/nmea
|
||||
${CMAKE_SOURCE_DIR}/external/poly2tri
|
||||
${CMAKE_SOURCE_DIR}/external/rtree/include
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
|
@ -112,7 +112,7 @@ void CostCalculator::addObstacleCostPenalty( LabelPosition *lp, FeaturePart *obs
|
||||
lp->setCost( lp->cost() + obstacleCost );
|
||||
}
|
||||
|
||||
void CostCalculator::setPolygonCandidatesCost( std::size_t nblp, std::vector< std::unique_ptr< LabelPosition > > &lPos, QgsGenericSpatialIndex<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
void CostCalculator::setPolygonCandidatesCost( std::size_t nblp, std::vector< std::unique_ptr< LabelPosition > > &lPos, PalRtree<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
double normalizer;
|
||||
// compute raw cost
|
||||
@ -157,7 +157,7 @@ void CostCalculator::setPolygonCandidatesCost( std::size_t nblp, std::vector< st
|
||||
}
|
||||
}
|
||||
|
||||
void CostCalculator::setCandidateCostFromPolygon( LabelPosition *lp, QgsGenericSpatialIndex<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
void CostCalculator::setCandidateCostFromPolygon( LabelPosition *lp, PalRtree<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
PolygonCostCalculator *pCost = new PolygonCostCalculator( lp );
|
||||
|
||||
@ -190,7 +190,7 @@ void CostCalculator::setCandidateCostFromPolygon( LabelPosition *lp, QgsGenericS
|
||||
delete pCost;
|
||||
}
|
||||
|
||||
std::size_t CostCalculator::finalizeCandidatesCosts( Feats *feat, std::size_t max_p, QgsGenericSpatialIndex<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
std::size_t CostCalculator::finalizeCandidatesCosts( Feats *feat, std::size_t max_p, PalRtree<FeaturePart> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
// If candidates list is smaller than expected
|
||||
if ( max_p > feat->candidates.size() )
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <QList>
|
||||
#include "palrtree.h"
|
||||
|
||||
/**
|
||||
* \class pal::CostCalculator
|
||||
@ -40,13 +41,13 @@ namespace pal
|
||||
static void addObstacleCostPenalty( pal::LabelPosition *lp, pal::FeaturePart *obstacle, Pal *pal );
|
||||
|
||||
//! Calculates the costs for polygon label candidates
|
||||
static void setPolygonCandidatesCost( std::size_t nblp, std::vector<std::unique_ptr<pal::LabelPosition> > &lPos, QgsGenericSpatialIndex< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
static void setPolygonCandidatesCost( std::size_t nblp, std::vector<std::unique_ptr<pal::LabelPosition> > &lPos, PalRtree< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
|
||||
//! Sets cost to the smallest distance between lPos's centroid and a polygon stored in geometry field
|
||||
static void setCandidateCostFromPolygon( LabelPosition *lp, QgsGenericSpatialIndex< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
static void setCandidateCostFromPolygon( LabelPosition *lp, PalRtree< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
|
||||
//! Sort candidates by costs, skip the worse ones, evaluate polygon candidates
|
||||
static std::size_t finalizeCandidatesCosts( Feats *feat, std::size_t max_p, QgsGenericSpatialIndex< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
static std::size_t finalizeCandidatesCosts( Feats *feat, std::size_t max_p, PalRtree< FeaturePart > *obstacles, double bbx[4], double bby[4] );
|
||||
|
||||
/**
|
||||
* Sorts label candidates in ascending order of cost
|
||||
|
@ -428,7 +428,7 @@ void LabelPosition::setHasHardObstacleConflict( bool conflicts )
|
||||
nextPart->setHasHardObstacleConflict( conflicts );
|
||||
}
|
||||
|
||||
void LabelPosition::removeFromIndex( QgsGenericSpatialIndex<LabelPosition> &index )
|
||||
void LabelPosition::removeFromIndex( PalRtree<LabelPosition> &index )
|
||||
{
|
||||
double amin[2];
|
||||
double amax[2];
|
||||
@ -436,7 +436,7 @@ void LabelPosition::removeFromIndex( QgsGenericSpatialIndex<LabelPosition> &inde
|
||||
index.remove( this, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
|
||||
}
|
||||
|
||||
void LabelPosition::insertIntoIndex( QgsGenericSpatialIndex<LabelPosition> &index )
|
||||
void LabelPosition::insertIntoIndex( PalRtree<LabelPosition> &index )
|
||||
{
|
||||
double amin[2];
|
||||
double amax[2];
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "pointset.h"
|
||||
#include "qgsgenericspatialindex.h"
|
||||
#include "palrtree.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace pal
|
||||
@ -288,12 +288,12 @@ namespace pal
|
||||
/**
|
||||
* Removes the label position from the specified \a index.
|
||||
*/
|
||||
void removeFromIndex( QgsGenericSpatialIndex<LabelPosition> &index );
|
||||
void removeFromIndex( PalRtree<LabelPosition> &index );
|
||||
|
||||
/**
|
||||
* Inserts the label position into the specified \a index.
|
||||
*/
|
||||
void insertIntoIndex( QgsGenericSpatialIndex<LabelPosition> &index );
|
||||
void insertIntoIndex( PalRtree<LabelPosition> &index );
|
||||
|
||||
/**
|
||||
* The offset of the anchor point in x direction.
|
||||
|
@ -47,10 +47,6 @@ class QgsLabelFeature;
|
||||
namespace pal
|
||||
{
|
||||
|
||||
/// @cond PRIVATE
|
||||
template<class DATATYPE, class ELEMTYPE, int NUMDIMS, class ELEMTYPEREAL, int TMAXNODES, int TMINNODES> class RTree;
|
||||
/// @endcond
|
||||
|
||||
class FeaturePart;
|
||||
|
||||
class Pal;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "pointset.h"
|
||||
#include "internalexception.h"
|
||||
#include "util.h"
|
||||
#include "palrtree.h"
|
||||
#include <cfloat>
|
||||
#include <list>
|
||||
|
||||
@ -84,7 +85,7 @@ Layer *Pal::addLayer( QgsAbstractLabelProvider *provider, const QString &layerNa
|
||||
std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeometry &mapBoundary )
|
||||
{
|
||||
// to store obstacles
|
||||
std::unique_ptr< QgsGenericSpatialIndex< FeaturePart > > obstacles = qgis::make_unique< QgsGenericSpatialIndex< FeaturePart > >();
|
||||
PalRtree< FeaturePart > obstacles;
|
||||
std::vector< FeaturePart * > allObstacleParts;
|
||||
std::unique_ptr< Problem > prob = qgis::make_unique< Problem >();
|
||||
|
||||
@ -153,7 +154,7 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
|
||||
for ( int i = 0; i < featurePart->getNumSelfObstacles(); i++ )
|
||||
{
|
||||
FeaturePart *selfObstacle = featurePart->getSelfObstacle( i );
|
||||
obstacles->insert( selfObstacle, selfObstacle->boundingBox() );
|
||||
obstacles.insert( selfObstacle, selfObstacle->boundingBox() );
|
||||
allObstacleParts.emplace_back( selfObstacle );
|
||||
|
||||
if ( !featurePart->getSelfObstacle( i )->getHoleOf() )
|
||||
@ -215,7 +216,7 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
|
||||
break; // do not continue searching
|
||||
|
||||
// insert into obstacles
|
||||
obstacles->insert( obstaclePart, obstaclePart->boundingBox() );
|
||||
obstacles.insert( obstaclePart, obstaclePart->boundingBox() );
|
||||
allObstacleParts.emplace_back( obstaclePart );
|
||||
obstacleCount++;
|
||||
}
|
||||
@ -301,7 +302,7 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
|
||||
}
|
||||
|
||||
// sort candidates by cost, skip less interesting ones, calculate polygon costs (if using polygons)
|
||||
max_p = CostCalculator::finalizeCandidatesCosts( feat.get(), max_p, obstacles.get(), bbx, bby );
|
||||
max_p = CostCalculator::finalizeCandidatesCosts( feat.get(), max_p, &obstacles, bbx, bby );
|
||||
|
||||
if ( isCanceled() )
|
||||
return nullptr;
|
||||
@ -411,8 +412,6 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
|
||||
prob->mNbOverlap = nbOverlaps;
|
||||
}
|
||||
|
||||
obstacles.reset();
|
||||
|
||||
return prob;
|
||||
}
|
||||
|
||||
|
100
src/core/pal/palrtree.h
Normal file
100
src/core/pal/palrtree.h
Normal file
@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
parlrtree.h
|
||||
------------------------
|
||||
Date : December 2019
|
||||
Copyright : (C) 2019 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "RTree.h"
|
||||
#include "qgsrectangle.h"
|
||||
|
||||
#ifndef QGSPALRTREE_H
|
||||
#define QGSPALRTREE_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \class PalRtree
|
||||
*
|
||||
* A rtree spatial index for use in the pal labeling engine.
|
||||
*
|
||||
* \note Not available in Python bindings.
|
||||
* \since QGIS 3.12
|
||||
*/
|
||||
template <typename T>
|
||||
class PalRtree : public RTree<T *, float, 2, float>
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Inserts new \a data into the spatial index, with the specified \a bounds.
|
||||
*
|
||||
* Ownership of \a data is not transferred, and it is the caller's responsibility to ensure that
|
||||
* it exists for the lifetime of the spatial index.
|
||||
*/
|
||||
void insert( T *data, const QgsRectangle &bounds )
|
||||
{
|
||||
this->Insert(
|
||||
{
|
||||
static_cast< float >( bounds.xMinimum() ),
|
||||
static_cast< float >( bounds.yMinimum() )
|
||||
},
|
||||
{
|
||||
static_cast< float>( bounds.xMaximum() ),
|
||||
static_cast< float >( bounds.yMaximum() )
|
||||
},
|
||||
data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes existing \a data from the spatial index, with the specified \a bounds.
|
||||
*
|
||||
* \a data is not deleted, and it is the caller's responsibility to ensure that
|
||||
* it is appropriately cleaned up.
|
||||
*/
|
||||
void remove( T *data, const QgsRectangle &bounds )
|
||||
{
|
||||
this->Remove(
|
||||
{
|
||||
static_cast< float >( bounds.xMinimum() ),
|
||||
static_cast< float >( bounds.yMinimum() )
|
||||
},
|
||||
{
|
||||
static_cast< float>( bounds.xMaximum() ),
|
||||
static_cast< float >( bounds.yMaximum() )
|
||||
},
|
||||
data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an intersection check against the index, for data intersecting the specified \a bounds.
|
||||
*
|
||||
* The \a callback function will be called once for each matching data object encountered.
|
||||
*/
|
||||
bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const
|
||||
{
|
||||
this->Search(
|
||||
{
|
||||
static_cast< float >( bounds.xMinimum() ),
|
||||
static_cast< float >( bounds.yMinimum() )
|
||||
},
|
||||
{
|
||||
static_cast< float>( bounds.xMaximum() ),
|
||||
static_cast< float >( bounds.yMaximum() )
|
||||
},
|
||||
callback );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -132,7 +132,7 @@ void Problem::reduce()
|
||||
delete[] ok;
|
||||
}
|
||||
|
||||
void ignoreLabel( const LabelPosition *lp, PriorityQueue &list, QgsGenericSpatialIndex< LabelPosition > &candidatesIndex )
|
||||
void ignoreLabel( const LabelPosition *lp, PriorityQueue &list, PalRtree< LabelPosition > &candidatesIndex )
|
||||
{
|
||||
if ( list.isIn( lp->getId() ) )
|
||||
{
|
||||
|
@ -36,7 +36,9 @@
|
||||
#include "qgis_core.h"
|
||||
#include <list>
|
||||
#include <QList>
|
||||
#include "qgsgenericspatialindex.h"
|
||||
#include "palrtree.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace pal
|
||||
{
|
||||
@ -142,7 +144,7 @@ namespace pal
|
||||
/**
|
||||
* Returns the index containing all label candidates.
|
||||
*/
|
||||
QgsGenericSpatialIndex<LabelPosition> &allCandidatesIndex() { return mAllCandidatesIndex; }
|
||||
PalRtree< LabelPosition > &allCandidatesIndex() { return mAllCandidatesIndex; }
|
||||
|
||||
private:
|
||||
|
||||
@ -183,8 +185,8 @@ namespace pal
|
||||
|
||||
std::vector< std::unique_ptr< LabelPosition > > mLabelPositions;
|
||||
|
||||
QgsGenericSpatialIndex<LabelPosition> mAllCandidatesIndex;
|
||||
QgsGenericSpatialIndex<LabelPosition> mActiveCandidatesIndex;
|
||||
PalRtree<LabelPosition> mAllCandidatesIndex;
|
||||
PalRtree<LabelPosition> mActiveCandidatesIndex;
|
||||
|
||||
std::vector< std::unique_ptr< LabelPosition > > mPositionsWithNoCandidates;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user