2014-11-28 06:13:18 -05:00
|
|
|
#ifndef STATIC_RTREE_HPP
|
|
|
|
#define STATIC_RTREE_HPP
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/deallocating_vector.hpp"
|
|
|
|
#include "util/hilbert_value.hpp"
|
|
|
|
#include "util/rectangle.hpp"
|
|
|
|
#include "util/shared_memory_vector_wrapper.hpp"
|
2013-09-23 12:03:07 -04:00
|
|
|
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/bearing.hpp"
|
2016-01-28 08:27:05 -05:00
|
|
|
#include "util/exception.hpp"
|
2016-04-06 10:47:16 -04:00
|
|
|
#include "util/integer_range.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/typedefs.hpp"
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "osrm/coordinate.hpp"
|
2013-12-17 11:59:44 -05:00
|
|
|
|
2013-06-26 09:43:13 -04:00
|
|
|
#include <boost/assert.hpp>
|
2013-08-09 11:47:11 -04:00
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include <boost/filesystem/fstream.hpp>
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-20 17:59:30 -04:00
|
|
|
#include <tbb/parallel_for.h>
|
2014-05-22 13:07:29 -04:00
|
|
|
#include <tbb/parallel_sort.h>
|
2014-05-20 17:59:30 -04:00
|
|
|
|
2014-08-28 04:50:42 -04:00
|
|
|
#include <variant/variant.hpp>
|
|
|
|
|
2013-06-26 09:43:13 -04:00
|
|
|
#include <algorithm>
|
2014-05-06 09:20:31 -04:00
|
|
|
#include <array>
|
2013-10-02 05:22:42 -04:00
|
|
|
#include <limits>
|
2014-05-09 10:47:42 -04:00
|
|
|
#include <memory>
|
2013-06-26 09:43:13 -04:00
|
|
|
#include <queue>
|
2013-07-22 10:32:19 -04:00
|
|
|
#include <string>
|
2013-06-26 09:43:13 -04:00
|
|
|
#include <vector>
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace util
|
|
|
|
{
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
// Static RTree for serving nearest neighbour queries
|
2016-03-28 14:38:19 -04:00
|
|
|
// All coordinates are pojected first to Web Mercator before the bounding boxes
|
|
|
|
// are computed, this means the internal distance metric doesn not represent meters!
|
2014-06-23 10:54:31 -04:00
|
|
|
template <class EdgeDataT,
|
2016-02-23 15:23:13 -05:00
|
|
|
class CoordinateListT = std::vector<Coordinate>,
|
2014-06-27 10:59:11 -04:00
|
|
|
bool UseSharedMemory = false,
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t BRANCHING_FACTOR = 64,
|
2016-04-08 18:52:47 -04:00
|
|
|
std::uint32_t LEAF_NODE_SIZE = 256>
|
2014-05-07 12:39:16 -04:00
|
|
|
class StaticRTree
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
|
|
|
public:
|
2015-12-03 14:04:23 -05:00
|
|
|
using Rectangle = RectangleInt2D;
|
|
|
|
using EdgeData = EdgeDataT;
|
|
|
|
using CoordinateList = CoordinateListT;
|
2014-08-29 06:37:07 -04:00
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
struct CandidateSegment
|
|
|
|
{
|
|
|
|
Coordinate fixed_projected_coordinate;
|
|
|
|
EdgeDataT data;
|
|
|
|
};
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
struct TreeNode
|
|
|
|
{
|
2014-05-09 10:48:58 -04:00
|
|
|
TreeNode() : child_count(0), child_is_on_disk(false) {}
|
2015-12-03 14:04:23 -05:00
|
|
|
Rectangle minimum_bounding_rectangle;
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t child_count : 31;
|
2014-05-06 09:20:31 -04:00
|
|
|
bool child_is_on_disk : 1;
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t children[BRANCHING_FACTOR];
|
2013-09-24 06:07:34 -04:00
|
|
|
};
|
|
|
|
|
2016-01-29 20:52:20 -05:00
|
|
|
struct LeafNode
|
|
|
|
{
|
|
|
|
LeafNode() : object_count(0), objects() {}
|
|
|
|
uint32_t object_count;
|
|
|
|
std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
|
|
|
|
};
|
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
private:
|
|
|
|
struct WrappedInputElement
|
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
explicit WrappedInputElement(const uint64_t _hilbert_value,
|
|
|
|
const std::uint32_t _array_index)
|
2014-05-29 11:16:24 -04:00
|
|
|
: m_hilbert_value(_hilbert_value), m_array_index(_array_index)
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
|
|
|
}
|
2013-06-27 10:57:40 -04:00
|
|
|
|
2014-05-29 11:16:24 -04:00
|
|
|
WrappedInputElement() : m_hilbert_value(0), m_array_index(UINT_MAX) {}
|
2013-06-26 09:43:13 -04:00
|
|
|
|
|
|
|
uint64_t m_hilbert_value;
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t m_array_index;
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-10-21 12:34:50 -04:00
|
|
|
inline bool operator<(const WrappedInputElement &other) const
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2013-06-26 09:43:13 -04:00
|
|
|
return m_hilbert_value < other.m_hilbert_value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
using QueryNodeType = mapbox::util::variant<TreeNode, CandidateSegment>;
|
2014-05-06 09:20:31 -04:00
|
|
|
struct QueryCandidate
|
|
|
|
{
|
2014-10-21 12:34:50 -04:00
|
|
|
inline bool operator<(const QueryCandidate &other) const
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2014-05-29 09:36:14 -04:00
|
|
|
// Attn: this is reversed order. std::pq is a max pq!
|
2016-03-28 14:38:19 -04:00
|
|
|
return other.squared_min_dist < squared_min_dist;
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
2014-06-10 11:26:05 -04:00
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
double squared_min_dist;
|
2015-12-03 14:04:23 -05:00
|
|
|
QueryNodeType node;
|
2014-06-23 10:54:31 -04:00
|
|
|
};
|
2014-06-10 11:26:05 -04:00
|
|
|
|
2013-09-23 12:03:07 -04:00
|
|
|
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
2013-06-26 09:43:13 -04:00
|
|
|
uint64_t m_element_count;
|
2013-07-22 10:32:19 -04:00
|
|
|
const std::string m_leaf_node_filename;
|
2014-05-09 10:47:42 -04:00
|
|
|
std::shared_ptr<CoordinateListT> m_coordinate_list;
|
2014-06-27 10:25:55 -04:00
|
|
|
boost::filesystem::ifstream leaves_stream;
|
2014-02-21 10:55:41 -05:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
public:
|
2014-05-07 12:39:16 -04:00
|
|
|
StaticRTree(const StaticRTree &) = delete;
|
Takes care of proper special member generation globally, fixes #1689
Phew, a lot of classes were affected by this. The rationale for the
changes are as follows:
- When a type X declares any constructor, the default constructor is
not declared, so there is no need for X() = delete there. In fact,
there is brutal difference between those two: deleted members
participate in overload resolution, but not-declared members do not!
- When a type X wants to be non-copyable (e.g. to be only movable, like
threads, unique_ptrs, and so on), you can either do it by inheriting
from boost::noncopyable (the old way), or better declare both (!) the
copy constructor _and_ the copy assignment operator as deleted:
X(X const&) = delete;
X& operator=(X const&) = delete;
We had tons of types with deleted copy constructors that were lacking
a corresponding deleted copy assignment operator, making them still
copyable and you wouldn't even notice (read: scary)!
References:
- http://accu.org/content/conf2014/Howard_Hinnant_Accu_2014.pdf
- http://www.boost.org/doc/libs/master/libs/core/doc/html/core/noncopyable.html
Note: I know, I'm quoting Hinnant's extraordinary slides a lot, but
getting the sematic right here is so incredibly important.
2016-01-27 05:20:55 -05:00
|
|
|
StaticRTree &operator=(const StaticRTree &) = delete;
|
2014-05-07 12:39:16 -04:00
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
template <typename CoordinateT>
|
2014-05-06 09:20:31 -04:00
|
|
|
// Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
|
2015-04-21 04:43:02 -04:00
|
|
|
explicit StaticRTree(const std::vector<EdgeDataT> &input_data_vector,
|
2015-09-08 17:34:20 -04:00
|
|
|
const std::string &tree_node_filename,
|
|
|
|
const std::string &leaf_node_filename,
|
2015-12-03 14:04:23 -05:00
|
|
|
const std::vector<CoordinateT> &coordinate_list)
|
2014-07-20 18:24:40 -04:00
|
|
|
: m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
|
2013-06-27 10:57:40 -04:00
|
|
|
{
|
2014-07-20 18:24:40 -04:00
|
|
|
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-20 17:59:30 -04:00
|
|
|
// generate auxiliary vector of hilbert-values
|
2014-06-23 10:54:31 -04:00
|
|
|
tbb::parallel_for(
|
2014-07-20 18:24:40 -04:00
|
|
|
tbb::blocked_range<uint64_t>(0, m_element_count),
|
2016-02-23 15:23:13 -05:00
|
|
|
[&input_data_vector, &input_wrapper_vector,
|
2016-04-06 10:47:16 -04:00
|
|
|
&coordinate_list](const tbb::blocked_range<uint64_t> &range) {
|
2015-09-14 19:13:31 -04:00
|
|
|
for (uint64_t element_counter = range.begin(), end = range.end();
|
|
|
|
element_counter != end; ++element_counter)
|
2014-05-20 17:59:30 -04:00
|
|
|
{
|
|
|
|
WrappedInputElement ¤t_wrapper = input_wrapper_vector[element_counter];
|
|
|
|
current_wrapper.m_array_index = element_counter;
|
|
|
|
|
2014-06-23 10:54:31 -04:00
|
|
|
EdgeDataT const ¤t_element = input_data_vector[element_counter];
|
2014-05-20 17:59:30 -04:00
|
|
|
|
|
|
|
// Get Hilbert-Value for centroid in mercartor projection
|
2016-02-17 21:20:27 -05:00
|
|
|
BOOST_ASSERT(current_element.u < coordinate_list.size());
|
|
|
|
BOOST_ASSERT(current_element.v < coordinate_list.size());
|
|
|
|
|
2016-03-26 12:28:22 -04:00
|
|
|
Coordinate current_centroid = coordinate_calculation::centroid(
|
|
|
|
coordinate_list[current_element.u], coordinate_list[current_element.v]);
|
2016-02-23 15:23:13 -05:00
|
|
|
current_centroid.lat = FixedLatitude(
|
|
|
|
COORDINATE_PRECISION *
|
|
|
|
coordinate_calculation::mercator::latToY(toFloating(current_centroid.lat)));
|
2014-05-20 17:59:30 -04:00
|
|
|
|
2016-01-25 09:32:41 -05:00
|
|
|
current_wrapper.m_hilbert_value = hilbertCode(current_centroid);
|
2014-05-20 17:59:30 -04:00
|
|
|
}
|
2014-06-23 10:54:31 -04:00
|
|
|
});
|
2013-11-22 12:05:47 -05:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// open leaf file
|
2013-08-09 11:47:11 -04:00
|
|
|
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
2014-07-20 18:24:40 -04:00
|
|
|
leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// sort the hilbert-value representatives
|
2015-09-10 05:36:02 -04:00
|
|
|
tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
2013-06-26 09:43:13 -04:00
|
|
|
std::vector<TreeNode> tree_nodes_in_level;
|
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// pack M elements into leaf node and write to leaf file
|
2013-06-26 09:43:13 -04:00
|
|
|
uint64_t processed_objects_count = 0;
|
2014-07-20 18:24:40 -04:00
|
|
|
while (processed_objects_count < m_element_count)
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2013-06-26 09:43:13 -04:00
|
|
|
|
|
|
|
LeafNode current_leaf;
|
|
|
|
TreeNode current_node;
|
2016-02-26 08:08:04 -05:00
|
|
|
for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
|
2014-05-06 09:20:31 -04:00
|
|
|
++current_element_index)
|
|
|
|
{
|
2014-07-20 18:24:40 -04:00
|
|
|
if (m_element_count > (processed_objects_count + current_element_index))
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t index_of_next_object =
|
2014-05-06 09:20:31 -04:00
|
|
|
input_wrapper_vector[processed_objects_count + current_element_index]
|
|
|
|
.m_array_index;
|
|
|
|
current_leaf.objects[current_element_index] =
|
|
|
|
input_data_vector[index_of_next_object];
|
2013-06-26 09:43:13 -04:00
|
|
|
++current_leaf.object_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// generate tree node that resemble the objects in leaf and store it for next level
|
2015-01-27 11:44:46 -05:00
|
|
|
InitializeMBRectangle(current_node.minimum_bounding_rectangle, current_leaf.objects,
|
|
|
|
current_leaf.object_count, coordinate_list);
|
2013-06-26 09:43:13 -04:00
|
|
|
current_node.child_is_on_disk = true;
|
|
|
|
current_node.children[0] = tree_nodes_in_level.size();
|
2014-05-06 09:20:31 -04:00
|
|
|
tree_nodes_in_level.emplace_back(current_node);
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// write leaf_node to leaf node file
|
|
|
|
leaf_node_file.write((char *)¤t_leaf, sizeof(current_leaf));
|
2013-06-26 09:43:13 -04:00
|
|
|
processed_objects_count += current_leaf.object_count;
|
|
|
|
}
|
|
|
|
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t processing_level = 0;
|
2014-05-06 09:20:31 -04:00
|
|
|
while (1 < tree_nodes_in_level.size())
|
|
|
|
{
|
2013-06-26 09:43:13 -04:00
|
|
|
std::vector<TreeNode> tree_nodes_in_next_level;
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t processed_tree_nodes_in_level = 0;
|
2014-05-06 09:20:31 -04:00
|
|
|
while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
|
|
|
|
{
|
2013-06-26 09:43:13 -04:00
|
|
|
TreeNode parent_node;
|
2014-06-27 10:59:11 -04:00
|
|
|
// pack BRANCHING_FACTOR elements into tree_nodes each
|
2016-02-26 08:08:04 -05:00
|
|
|
for (std::uint32_t current_child_node_index = 0;
|
2015-01-27 11:44:46 -05:00
|
|
|
BRANCHING_FACTOR > current_child_node_index; ++current_child_node_index)
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
|
|
|
if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
|
|
|
|
{
|
|
|
|
TreeNode ¤t_child_node =
|
|
|
|
tree_nodes_in_level[processed_tree_nodes_in_level];
|
|
|
|
// add tree node to parent entry
|
2014-07-20 18:24:40 -04:00
|
|
|
parent_node.children[current_child_node_index] = m_search_tree.size();
|
|
|
|
m_search_tree.emplace_back(current_child_node);
|
2014-06-19 11:52:59 -04:00
|
|
|
// merge MBRs
|
2014-05-29 09:36:14 -04:00
|
|
|
parent_node.minimum_bounding_rectangle.MergeBoundingBoxes(
|
2014-05-06 09:20:31 -04:00
|
|
|
current_child_node.minimum_bounding_rectangle);
|
|
|
|
// increase counters
|
2013-06-26 09:43:13 -04:00
|
|
|
++parent_node.child_count;
|
|
|
|
++processed_tree_nodes_in_level;
|
|
|
|
}
|
|
|
|
}
|
2014-05-06 09:20:31 -04:00
|
|
|
tree_nodes_in_next_level.emplace_back(parent_node);
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
|
|
|
tree_nodes_in_level.swap(tree_nodes_in_next_level);
|
|
|
|
++processing_level;
|
|
|
|
}
|
|
|
|
BOOST_ASSERT_MSG(1 == tree_nodes_in_level.size(), "tree broken, more than one root node");
|
2014-05-06 09:20:31 -04:00
|
|
|
// last remaining entry is the root node, store it
|
2014-07-20 18:24:40 -04:00
|
|
|
m_search_tree.emplace_back(tree_nodes_in_level[0]);
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// reverse and renumber tree to have root at index 0
|
2014-07-20 18:24:40 -04:00
|
|
|
std::reverse(m_search_tree.begin(), m_search_tree.end());
|
2013-11-22 12:05:47 -05:00
|
|
|
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t search_tree_size = m_search_tree.size();
|
2016-04-06 10:47:16 -04:00
|
|
|
tbb::parallel_for(
|
|
|
|
tbb::blocked_range<std::uint32_t>(0, search_tree_size),
|
|
|
|
[this, &search_tree_size](const tbb::blocked_range<std::uint32_t> &range) {
|
|
|
|
for (std::uint32_t i = range.begin(), end = range.end(); i != end; ++i)
|
|
|
|
{
|
|
|
|
TreeNode ¤t_tree_node = this->m_search_tree[i];
|
|
|
|
for (std::uint32_t j = 0; j < current_tree_node.child_count; ++j)
|
|
|
|
{
|
|
|
|
const std::uint32_t old_id = current_tree_node.children[j];
|
|
|
|
const std::uint32_t new_id = search_tree_size - old_id - 1;
|
|
|
|
current_tree_node.children[j] = new_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2013-06-26 09:43:13 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// open tree file
|
|
|
|
boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
|
2013-08-09 11:47:11 -04:00
|
|
|
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t size_of_tree = m_search_tree.size();
|
2013-06-26 09:43:13 -04:00
|
|
|
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
|
2016-02-26 08:08:04 -05:00
|
|
|
tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
|
2014-07-20 18:24:40 -04:00
|
|
|
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
explicit StaticRTree(const boost::filesystem::path &node_file,
|
|
|
|
const boost::filesystem::path &leaf_file,
|
2014-05-09 10:47:42 -04:00
|
|
|
const std::shared_ptr<CoordinateListT> coordinate_list)
|
2014-05-06 09:20:31 -04:00
|
|
|
: m_leaf_node_filename(leaf_file.string())
|
|
|
|
{
|
|
|
|
// open tree node file and load into RAM.
|
2014-02-21 10:55:41 -05:00
|
|
|
m_coordinate_list = coordinate_list;
|
2013-08-09 11:47:11 -04:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
if (!boost::filesystem::exists(node_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("ram index file does not exist");
|
2013-08-09 11:47:11 -04:00
|
|
|
}
|
2014-05-06 09:20:31 -04:00
|
|
|
if (0 == boost::filesystem::file_size(node_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("ram index file is empty");
|
2013-08-09 11:47:11 -04:00
|
|
|
}
|
2014-05-06 09:20:31 -04:00
|
|
|
boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
|
2013-08-09 11:47:11 -04:00
|
|
|
|
2016-02-26 08:08:04 -05:00
|
|
|
std::uint32_t tree_size = 0;
|
|
|
|
tree_node_file.read((char *)&tree_size, sizeof(std::uint32_t));
|
2013-11-22 12:05:47 -05:00
|
|
|
|
2013-06-26 09:43:13 -04:00
|
|
|
m_search_tree.resize(tree_size);
|
2014-06-05 13:14:36 -04:00
|
|
|
if (tree_size > 0)
|
|
|
|
{
|
|
|
|
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
|
|
|
}
|
2016-03-07 09:25:47 -05:00
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
// open leaf node file and store thread specific pointer
|
|
|
|
if (!boost::filesystem::exists(leaf_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("mem index file does not exist");
|
2013-09-23 12:03:07 -04:00
|
|
|
}
|
2014-05-06 09:20:31 -04:00
|
|
|
if (0 == boost::filesystem::file_size(leaf_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("mem index file is empty");
|
2013-09-23 12:03:07 -04:00
|
|
|
}
|
|
|
|
|
2014-06-27 10:25:55 -04:00
|
|
|
leaves_stream.open(leaf_file, std::ios::binary);
|
|
|
|
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
|
2013-09-23 12:03:07 -04:00
|
|
|
}
|
|
|
|
|
2014-05-06 09:20:31 -04:00
|
|
|
explicit StaticRTree(TreeNode *tree_node_ptr,
|
2014-07-15 09:25:44 -04:00
|
|
|
const uint64_t number_of_nodes,
|
2014-05-06 09:20:31 -04:00
|
|
|
const boost::filesystem::path &leaf_file,
|
2014-05-09 10:47:42 -04:00
|
|
|
std::shared_ptr<CoordinateListT> coordinate_list)
|
2014-05-06 09:20:31 -04:00
|
|
|
: m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
|
2015-08-18 06:56:34 -04:00
|
|
|
m_coordinate_list(std::move(coordinate_list))
|
2013-09-24 06:07:34 -04:00
|
|
|
{
|
2014-05-06 09:20:31 -04:00
|
|
|
// open leaf node file and store thread specific pointer
|
|
|
|
if (!boost::filesystem::exists(leaf_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("mem index file does not exist");
|
2013-08-09 11:47:11 -04:00
|
|
|
}
|
2014-05-06 09:20:31 -04:00
|
|
|
if (0 == boost::filesystem::file_size(leaf_file))
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("mem index file is empty");
|
2013-08-09 11:47:11 -04:00
|
|
|
}
|
|
|
|
|
2014-06-27 10:25:55 -04:00
|
|
|
leaves_stream.open(leaf_file, std::ios::binary);
|
|
|
|
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
|
2013-08-26 08:16:34 -04:00
|
|
|
}
|
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
/* Returns all features inside the bounding box.
|
|
|
|
Rectangle needs to be projected!*/
|
2016-02-26 06:29:57 -05:00
|
|
|
std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle)
|
2016-02-16 13:51:04 -05:00
|
|
|
{
|
2016-03-28 14:38:19 -04:00
|
|
|
const Rectangle projected_rectangle{
|
|
|
|
search_rectangle.min_lon, search_rectangle.max_lon,
|
|
|
|
toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
|
|
|
|
toFloating(FixedLatitude(search_rectangle.min_lat)))}),
|
|
|
|
toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
|
|
|
|
toFloating(FixedLatitude(search_rectangle.max_lat)))})};
|
2016-02-16 13:51:04 -05:00
|
|
|
std::vector<EdgeDataT> results;
|
|
|
|
|
|
|
|
std::queue<TreeNode> traversal_queue;
|
|
|
|
|
|
|
|
traversal_queue.push(m_search_tree[0]);
|
|
|
|
|
|
|
|
while (!traversal_queue.empty())
|
|
|
|
{
|
|
|
|
auto const current_tree_node = traversal_queue.front();
|
|
|
|
traversal_queue.pop();
|
|
|
|
|
|
|
|
if (current_tree_node.child_is_on_disk)
|
|
|
|
{
|
|
|
|
LeafNode current_leaf_node;
|
|
|
|
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
|
|
|
|
|
|
|
for (const auto i : irange(0u, current_leaf_node.object_count))
|
|
|
|
{
|
|
|
|
const auto ¤t_edge = current_leaf_node.objects[i];
|
|
|
|
|
2016-04-03 05:41:46 -04:00
|
|
|
// we don't need to project the coordinates here,
|
|
|
|
// because we use the unprojected rectangle to test against
|
2016-02-26 08:08:04 -05:00
|
|
|
const Rectangle bbox{std::min((*m_coordinate_list)[current_edge.u].lon,
|
|
|
|
(*m_coordinate_list)[current_edge.v].lon),
|
|
|
|
std::max((*m_coordinate_list)[current_edge.u].lon,
|
|
|
|
(*m_coordinate_list)[current_edge.v].lon),
|
|
|
|
std::min((*m_coordinate_list)[current_edge.u].lat,
|
|
|
|
(*m_coordinate_list)[current_edge.v].lat),
|
|
|
|
std::max((*m_coordinate_list)[current_edge.u].lat,
|
|
|
|
(*m_coordinate_list)[current_edge.v].lat)};
|
2016-02-16 13:51:04 -05:00
|
|
|
|
2016-04-03 05:41:46 -04:00
|
|
|
// use the _unprojected_ input rectangle here
|
2016-02-16 13:51:04 -05:00
|
|
|
if (bbox.Intersects(search_rectangle))
|
|
|
|
{
|
|
|
|
results.push_back(current_edge);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If it's a tree node, look at all children and add them
|
|
|
|
// to the search queue if their bounding boxes intersect
|
2016-02-26 08:08:04 -05:00
|
|
|
for (std::uint32_t i = 0; i < current_tree_node.child_count; ++i)
|
2016-02-16 13:51:04 -05:00
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
const std::int32_t child_id = current_tree_node.children[i];
|
2016-02-16 13:51:04 -05:00
|
|
|
const auto &child_tree_node = m_search_tree[child_id];
|
|
|
|
const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
|
|
|
|
2016-04-03 05:41:46 -04:00
|
|
|
if (child_rectangle.Intersects(projected_rectangle))
|
2016-02-16 13:51:04 -05:00
|
|
|
{
|
|
|
|
traversal_queue.push(m_search_tree[child_id]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
// Override filter and terminator for the desired behaviour.
|
2016-02-23 15:23:13 -05:00
|
|
|
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, const std::size_t max_results)
|
2015-09-21 21:34:37 -04:00
|
|
|
{
|
2015-12-03 14:04:23 -05:00
|
|
|
return Nearest(input_coordinate,
|
2016-04-06 10:47:16 -04:00
|
|
|
[](const CandidateSegment &) { return std::make_pair(true, true); },
|
|
|
|
[max_results](const std::size_t num_results, const CandidateSegment &) {
|
2015-12-03 14:04:23 -05:00
|
|
|
return num_results >= max_results;
|
|
|
|
});
|
2015-09-21 21:34:37 -04:00
|
|
|
}
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
// Override filter and terminator for the desired behaviour.
|
|
|
|
template <typename FilterT, typename TerminationT>
|
2016-02-23 15:23:13 -05:00
|
|
|
std::vector<EdgeDataT>
|
|
|
|
Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate)
|
2014-06-10 11:26:05 -04:00
|
|
|
{
|
2015-12-03 14:04:23 -05:00
|
|
|
std::vector<EdgeDataT> results;
|
2016-03-28 14:38:19 -04:00
|
|
|
auto projected_coordinate = coordinate_calculation::mercator::fromWGS84(input_coordinate);
|
|
|
|
Coordinate fixed_projected_coordinate{projected_coordinate};
|
2015-01-20 10:24:49 -05:00
|
|
|
|
2014-06-23 10:54:31 -04:00
|
|
|
// initialize queue with root element
|
2015-12-03 14:04:23 -05:00
|
|
|
std::priority_queue<QueryCandidate> traversal_queue;
|
2016-01-05 06:04:04 -05:00
|
|
|
traversal_queue.push(QueryCandidate{0.f, m_search_tree[0]});
|
2014-06-23 10:54:31 -04:00
|
|
|
|
|
|
|
while (!traversal_queue.empty())
|
|
|
|
{
|
2016-03-28 14:38:19 -04:00
|
|
|
QueryCandidate current_query_node = traversal_queue.top();
|
2014-07-23 13:25:09 -04:00
|
|
|
traversal_queue.pop();
|
|
|
|
|
2014-09-23 12:46:14 -04:00
|
|
|
if (current_query_node.node.template is<TreeNode>())
|
|
|
|
{ // current object is a tree node
|
2015-01-27 11:44:46 -05:00
|
|
|
const TreeNode ¤t_tree_node =
|
|
|
|
current_query_node.node.template get<TreeNode>();
|
2014-07-23 13:25:09 -04:00
|
|
|
if (current_tree_node.child_is_on_disk)
|
|
|
|
{
|
2016-03-28 14:38:19 -04:00
|
|
|
ExploreLeafNode(current_tree_node.children[0], projected_coordinate,
|
|
|
|
traversal_queue);
|
2014-07-23 13:25:09 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-28 14:38:19 -04:00
|
|
|
ExploreTreeNode(current_tree_node, fixed_projected_coordinate, traversal_queue);
|
2014-07-23 13:25:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2015-12-03 14:04:23 -05:00
|
|
|
{
|
2014-07-23 13:25:09 -04:00
|
|
|
// inspecting an actual road segment
|
2016-03-28 14:38:19 -04:00
|
|
|
auto ¤t_candidate = current_query_node.node.template get<CandidateSegment>();
|
2014-07-23 13:25:09 -04:00
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
auto use_segment = filter(current_candidate);
|
2015-12-03 14:04:23 -05:00
|
|
|
if (!use_segment.first && !use_segment.second)
|
2014-12-08 17:46:31 -05:00
|
|
|
{
|
2015-09-21 21:34:37 -04:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-28 14:38:19 -04:00
|
|
|
current_candidate.data.forward_segment_id.enabled &= use_segment.first;
|
|
|
|
current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
|
2015-09-21 21:34:37 -04:00
|
|
|
|
2014-09-23 12:46:14 -04:00
|
|
|
// store phantom node in result vector
|
2016-03-28 14:38:19 -04:00
|
|
|
results.push_back(std::move(current_candidate.data));
|
2016-04-06 10:47:16 -04:00
|
|
|
|
|
|
|
if (terminate(results.size(), current_candidate))
|
|
|
|
{
|
|
|
|
traversal_queue = std::priority_queue<QueryCandidate>{};
|
|
|
|
break;
|
|
|
|
}
|
2014-12-23 11:18:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
return results;
|
2014-12-23 11:18:32 -05:00
|
|
|
}
|
2014-06-23 10:54:31 -04:00
|
|
|
|
|
|
|
private:
|
2015-12-03 14:04:23 -05:00
|
|
|
template <typename QueueT>
|
|
|
|
void ExploreLeafNode(const std::uint32_t leaf_id,
|
2016-03-28 14:38:19 -04:00
|
|
|
const FloatCoordinate &projected_input_coordinate,
|
2015-12-03 14:04:23 -05:00
|
|
|
QueueT &traversal_queue)
|
2014-06-23 10:54:31 -04:00
|
|
|
{
|
2015-12-03 14:04:23 -05:00
|
|
|
LeafNode current_leaf_node;
|
|
|
|
LoadLeafFromDisk(leaf_id, current_leaf_node);
|
2014-06-23 10:54:31 -04:00
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
// current object represents a block on disk
|
2016-01-05 10:51:13 -05:00
|
|
|
for (const auto i : irange(0u, current_leaf_node.object_count))
|
2015-01-27 11:44:46 -05:00
|
|
|
{
|
2016-04-06 10:47:16 -04:00
|
|
|
const auto ¤t_edge = current_leaf_node.objects[i];
|
|
|
|
const auto projected_u =
|
2016-03-28 14:38:19 -04:00
|
|
|
coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
|
2016-04-06 10:47:16 -04:00
|
|
|
const auto projected_v =
|
2016-03-28 14:38:19 -04:00
|
|
|
coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
|
|
|
|
|
|
|
|
FloatCoordinate projected_nearest;
|
|
|
|
std::tie(std::ignore, projected_nearest) =
|
|
|
|
coordinate_calculation::projectPointOnSegment(projected_u, projected_v,
|
|
|
|
projected_input_coordinate);
|
|
|
|
|
2016-04-06 10:47:16 -04:00
|
|
|
const auto squared_distance = coordinate_calculation::squaredEuclideanDistance(
|
|
|
|
projected_nearest, projected_input_coordinate);
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
// distance must be non-negative
|
2016-03-28 14:38:19 -04:00
|
|
|
BOOST_ASSERT(0. <= squared_distance);
|
2016-01-05 06:04:04 -05:00
|
|
|
traversal_queue.push(
|
2016-03-28 14:38:19 -04:00
|
|
|
QueryCandidate{squared_distance, CandidateSegment{Coordinate{projected_nearest},
|
|
|
|
std::move(current_edge)}});
|
2015-01-27 11:44:46 -05:00
|
|
|
}
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
2013-08-26 08:16:34 -04:00
|
|
|
|
2014-05-29 09:36:14 -04:00
|
|
|
template <class QueueT>
|
2015-12-03 14:04:23 -05:00
|
|
|
void ExploreTreeNode(const TreeNode &parent,
|
2016-03-28 14:38:19 -04:00
|
|
|
const Coordinate fixed_projected_input_coordinate,
|
2015-12-03 14:04:23 -05:00
|
|
|
QueueT &traversal_queue)
|
2014-05-29 09:36:14 -04:00
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
for (std::uint32_t i = 0; i < parent.child_count; ++i)
|
2014-05-29 09:36:14 -04:00
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
const std::int32_t child_id = parent.children[i];
|
2015-12-03 14:04:23 -05:00
|
|
|
const auto &child_tree_node = m_search_tree[child_id];
|
|
|
|
const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
2016-03-28 14:38:19 -04:00
|
|
|
const auto squared_lower_bound_to_element =
|
|
|
|
child_rectangle.GetMinSquaredDist(fixed_projected_input_coordinate);
|
|
|
|
traversal_queue.push(
|
|
|
|
QueryCandidate{squared_lower_bound_to_element, m_search_tree[child_id]});
|
2014-05-29 09:36:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-26 08:08:04 -05:00
|
|
|
inline void LoadLeafFromDisk(const std::uint32_t leaf_id, LeafNode &result_node)
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2014-06-27 10:25:55 -04:00
|
|
|
if (!leaves_stream.is_open())
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2014-06-27 10:25:55 -04:00
|
|
|
leaves_stream.open(m_leaf_node_filename, std::ios::in | std::ios::binary);
|
2014-05-06 09:20:31 -04:00
|
|
|
}
|
2014-06-27 10:25:55 -04:00
|
|
|
if (!leaves_stream.good())
|
2014-05-06 09:20:31 -04:00
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw exception("Could not read from leaf file.");
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
2014-05-26 11:37:44 -04:00
|
|
|
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
|
2014-06-27 10:25:55 -04:00
|
|
|
leaves_stream.seekg(seek_pos);
|
2015-01-27 11:44:46 -05:00
|
|
|
BOOST_ASSERT_MSG(leaves_stream.good(), "Seeking to position in leaf file failed.");
|
2014-06-27 10:25:55 -04:00
|
|
|
leaves_stream.read((char *)&result_node, sizeof(LeafNode));
|
|
|
|
BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
|
2013-06-26 09:43:13 -04:00
|
|
|
}
|
|
|
|
|
2015-12-03 14:04:23 -05:00
|
|
|
template <typename CoordinateT>
|
|
|
|
void InitializeMBRectangle(Rectangle &rectangle,
|
|
|
|
const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
|
2016-02-26 08:08:04 -05:00
|
|
|
const std::uint32_t element_count,
|
2015-12-03 14:04:23 -05:00
|
|
|
const std::vector<CoordinateT> &coordinate_list)
|
2014-10-28 19:33:43 -04:00
|
|
|
{
|
2016-02-26 08:08:04 -05:00
|
|
|
for (std::uint32_t i = 0; i < element_count; ++i)
|
2014-10-28 19:33:43 -04:00
|
|
|
{
|
2016-02-17 21:20:27 -05:00
|
|
|
BOOST_ASSERT(objects[i].u < coordinate_list.size());
|
|
|
|
BOOST_ASSERT(objects[i].v < coordinate_list.size());
|
|
|
|
|
2016-03-28 14:38:19 -04:00
|
|
|
Coordinate projected_u{coordinate_calculation::mercator::fromWGS84(
|
|
|
|
Coordinate{coordinate_list[objects[i].u]})};
|
|
|
|
Coordinate projected_v{coordinate_calculation::mercator::fromWGS84(
|
|
|
|
Coordinate{coordinate_list[objects[i].v]})};
|
|
|
|
|
|
|
|
BOOST_ASSERT(toFloating(projected_u.lon) <= FloatLongitude(180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_u.lon) >= FloatLongitude(-180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_u.lat) <= FloatLatitude(180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_u.lat) >= FloatLatitude(-180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_v.lon) <= FloatLongitude(180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_v.lon) >= FloatLongitude(-180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_v.lat) <= FloatLatitude(180.));
|
|
|
|
BOOST_ASSERT(toFloating(projected_v.lat) >= FloatLatitude(-180.));
|
|
|
|
|
2015-01-27 11:44:46 -05:00
|
|
|
rectangle.min_lon =
|
2016-03-28 14:38:19 -04:00
|
|
|
std::min(rectangle.min_lon, std::min(projected_u.lon, projected_v.lon));
|
2015-01-27 11:44:46 -05:00
|
|
|
rectangle.max_lon =
|
2016-03-28 14:38:19 -04:00
|
|
|
std::max(rectangle.max_lon, std::max(projected_u.lon, projected_v.lon));
|
2015-01-27 11:44:46 -05:00
|
|
|
|
|
|
|
rectangle.min_lat =
|
2016-03-28 14:38:19 -04:00
|
|
|
std::min(rectangle.min_lat, std::min(projected_u.lat, projected_v.lat));
|
2015-01-27 11:44:46 -05:00
|
|
|
rectangle.max_lat =
|
2016-03-28 14:38:19 -04:00
|
|
|
std::max(rectangle.max_lat, std::max(projected_u.lat, projected_v.lat));
|
2014-10-28 19:33:43 -04:00
|
|
|
}
|
2016-02-23 15:23:13 -05:00
|
|
|
BOOST_ASSERT(rectangle.min_lon != FixedLongitude(std::numeric_limits<int>::min()));
|
|
|
|
BOOST_ASSERT(rectangle.min_lat != FixedLatitude(std::numeric_limits<int>::min()));
|
|
|
|
BOOST_ASSERT(rectangle.max_lon != FixedLongitude(std::numeric_limits<int>::min()));
|
|
|
|
BOOST_ASSERT(rectangle.max_lat != FixedLatitude(std::numeric_limits<int>::min()));
|
2014-10-28 19:33:43 -04:00
|
|
|
}
|
2013-06-26 09:43:13 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
|
|
|
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
|
2014-06-23 10:54:31 -04:00
|
|
|
//[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
|
|
|
|
// Vol.24 No.2, pp.265-318
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 06:13:18 -05:00
|
|
|
#endif // STATIC_RTREE_HPP
|