Compare commits
19 Commits
v5.1.0-rc.1
...
v5.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 6aed145dae | |||
| d15cc77b0b | |||
| 24a75d37fb | |||
| 7e80dae59b | |||
| 7316c48e9f | |||
| c520c7a24a | |||
| 7564633045 | |||
| 7174c5d036 | |||
| ddd128ce0e | |||
| f5aa5c0769 | |||
| 2acde49f0f | |||
| 8849015bbf | |||
| 70cd7a94ec | |||
| 3984dea34b | |||
| b11b471aa4 | |||
| 63754df4d4 | |||
| e644424508 | |||
| 4f6eef3d16 | |||
| e2e8104864 |
@@ -16,6 +16,7 @@
|
||||
|
||||
- Infrastructure
|
||||
- BREAKING: reordered internal instruction types. This breaks the **data format**
|
||||
- BREAKING: Changed the on-disk encoding of the StaticRTree for better performance. This breaks the **data format**
|
||||
|
||||
- Fixes:
|
||||
- Issue #2310: post-processing for local paths, fixes #2310
|
||||
|
||||
+3
-2
@@ -421,7 +421,8 @@ step.
|
||||
direction of travel immediately before the maneuver.
|
||||
- `bearing_after`: The clockwise angle from true north to the
|
||||
direction of travel immediately after the maneuver.
|
||||
- `type` A string indicating the type of maneuver
|
||||
- `type` A string indicating the type of maneuver. **new identifiers might be introduced without API change**
|
||||
Types unknown to the client should be handled like the `turn` type, the existance of correct `modifier` values is guranteed.
|
||||
|
||||
| `type` | Description |
|
||||
|-------------------|--------------------------------------------------------------|
|
||||
@@ -476,7 +477,7 @@ step.
|
||||
| `turn` or `end of road`| Indicates the number of intersections passed until the turn. Example instruction: `at the fourth intersection, turn left` |
|
||||
|
||||
|
||||
New maneuver `type` and `modifier` and new properties (potentially depending on `type`) may be introduced in the future without an API version change.
|
||||
New properties (potentially depending on `type`) may be introduced in the future without an API version change.
|
||||
|
||||
### Waypoint
|
||||
|
||||
|
||||
@@ -90,47 +90,47 @@ class BaseDataFacade
|
||||
virtual extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
|
||||
const util::Coordinate north_east) = 0;
|
||||
const util::Coordinate north_east) const = 0;
|
||||
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) = 0;
|
||||
const int bearing_range) const = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance) = 0;
|
||||
const float max_distance) const = 0;
|
||||
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) = 0;
|
||||
const int bearing_range) const = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range) = 0;
|
||||
const int bearing_range) const = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results) = 0;
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results) const = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance) = 0;
|
||||
const double max_distance) const = 0;
|
||||
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) = 0;
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance) = 0;
|
||||
const double max_distance) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) = 0;
|
||||
const int bearing_range) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate, const int bearing, const int bearing_range) = 0;
|
||||
const util::Coordinate input_coordinate, const int bearing, const int bearing_range) const = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list;
|
||||
util::ShM<util::Coordinate, false>::vector m_coordinate_list;
|
||||
util::ShM<NodeID, false>::vector m_via_node_list;
|
||||
util::ShM<unsigned, false>::vector m_name_ID_list;
|
||||
util::ShM<extractor::guidance::TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
@@ -83,8 +83,8 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
util::ShM<std::string, false>::vector m_datasource_names;
|
||||
extractor::ProfileProperties m_profile_properties;
|
||||
|
||||
boost::thread_specific_ptr<InternalRTree> m_static_rtree;
|
||||
boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
|
||||
std::unique_ptr<InternalRTree> m_static_rtree;
|
||||
std::unique_ptr<InternalGeospatialQuery> m_geospatial_query;
|
||||
boost::filesystem::path ram_index_path;
|
||||
boost::filesystem::path file_index_path;
|
||||
util::RangeTable<16, false> m_name_table;
|
||||
@@ -139,12 +139,12 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
extractor::QueryNode current_node;
|
||||
unsigned number_of_coordinates = 0;
|
||||
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
|
||||
m_coordinate_list = std::make_shared<std::vector<util::Coordinate>>(number_of_coordinates);
|
||||
m_coordinate_list.resize(number_of_coordinates);
|
||||
for (unsigned i = 0; i < number_of_coordinates; ++i)
|
||||
{
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
|
||||
m_coordinate_list->at(i) = util::Coordinate(current_node.lon, current_node.lat);
|
||||
BOOST_ASSERT(m_coordinate_list->at(i).IsValid());
|
||||
m_coordinate_list[i] = util::Coordinate(current_node.lon, current_node.lat);
|
||||
BOOST_ASSERT(m_coordinate_list[i].IsValid());
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
|
||||
@@ -253,7 +253,7 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
|
||||
m_geospatial_query.reset(
|
||||
@@ -313,6 +313,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
|
||||
util::SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(config.names_data_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading rtree";
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
// search graph access
|
||||
@@ -361,7 +364,7 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
// node and edge information access
|
||||
util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
return m_coordinate_list[id];
|
||||
}
|
||||
|
||||
extractor::guidance::TurnInstruction
|
||||
@@ -376,13 +379,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
}
|
||||
|
||||
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
|
||||
const util::Coordinate north_east) override final
|
||||
const util::Coordinate north_east) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
|
||||
north_east.lat};
|
||||
return m_geospatial_query->Search(bbox);
|
||||
@@ -390,13 +389,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance) override final
|
||||
const float max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
|
||||
}
|
||||
@@ -405,13 +400,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
|
||||
bearing, bearing_range);
|
||||
@@ -419,13 +410,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results) override final
|
||||
const unsigned max_results) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
|
||||
}
|
||||
@@ -433,13 +420,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance) override final
|
||||
const double max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
|
||||
}
|
||||
@@ -448,13 +431,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
|
||||
bearing_range);
|
||||
@@ -465,13 +444,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
const unsigned max_results,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
|
||||
bearing, bearing_range);
|
||||
@@ -479,26 +454,18 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance) override final
|
||||
const double max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate) override final
|
||||
const util::Coordinate input_coordinate) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate);
|
||||
@@ -508,13 +475,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance, bearing, bearing_range);
|
||||
@@ -523,13 +486,9 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, bearing, bearing_range);
|
||||
|
||||
@@ -55,7 +55,6 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
using SharedRTree =
|
||||
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>;
|
||||
using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
|
||||
using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
|
||||
using RTreeNode = SharedRTree::TreeNode;
|
||||
|
||||
storage::SharedDataLayout *data_layout;
|
||||
@@ -71,9 +70,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
std::unique_ptr<storage::SharedMemory> m_layout_memory;
|
||||
std::unique_ptr<storage::SharedMemory> m_large_memory;
|
||||
std::string m_timestamp;
|
||||
extractor::ProfileProperties* m_profile_properties;
|
||||
extractor::ProfileProperties *m_profile_properties;
|
||||
|
||||
std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list;
|
||||
util::ShM<util::Coordinate, true>::vector m_coordinate_list;
|
||||
util::ShM<NodeID, true>::vector m_via_node_list;
|
||||
util::ShM<unsigned, true>::vector m_name_ID_list;
|
||||
util::ShM<extractor::guidance::TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
@@ -89,8 +88,8 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
util::ShM<std::size_t, true>::vector m_datasource_name_offsets;
|
||||
util::ShM<std::size_t, true>::vector m_datasource_name_lengths;
|
||||
|
||||
boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
|
||||
boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
|
||||
std::unique_ptr<SharedRTree> m_static_rtree;
|
||||
std::unique_ptr<SharedGeospatialQuery> m_geospatial_query;
|
||||
boost::filesystem::path file_index_path;
|
||||
|
||||
std::shared_ptr<util::RangeTable<16, true>> m_name_table;
|
||||
@@ -104,8 +103,8 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
void LoadProfileProperties()
|
||||
{
|
||||
m_profile_properties =
|
||||
data_layout->GetBlockPtr<extractor::ProfileProperties>(shared_memory, storage::SharedDataLayout::PROPERTIES);
|
||||
m_profile_properties = data_layout->GetBlockPtr<extractor::ProfileProperties>(
|
||||
shared_memory, storage::SharedDataLayout::PROPERTIES);
|
||||
}
|
||||
|
||||
void LoadTimestamp()
|
||||
@@ -120,17 +119,15 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
auto tree_ptr = data_layout->GetBlockPtr<RTreeNode>(
|
||||
shared_memory, storage::SharedDataLayout::R_SEARCH_TREE);
|
||||
m_static_rtree.reset(new TimeStampedRTreePair(
|
||||
CURRENT_TIMESTAMP,
|
||||
util::make_unique<SharedRTree>(
|
||||
tree_ptr, data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
|
||||
file_index_path, m_coordinate_list)));
|
||||
m_static_rtree.reset(new SharedRTree(
|
||||
tree_ptr, data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
|
||||
file_index_path, m_coordinate_list));
|
||||
m_geospatial_query.reset(
|
||||
new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list, *this));
|
||||
new SharedGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
@@ -152,8 +149,7 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
{
|
||||
auto coordinate_list_ptr = data_layout->GetBlockPtr<util::Coordinate>(
|
||||
shared_memory, storage::SharedDataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list = util::make_unique<util::ShM<util::Coordinate, true>::vector>(
|
||||
coordinate_list_ptr,
|
||||
m_coordinate_list.reset(coordinate_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
|
||||
|
||||
auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
|
||||
@@ -165,10 +161,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
auto turn_instruction_list_ptr =
|
||||
data_layout->GetBlockPtr<extractor::guidance::TurnInstruction>(
|
||||
shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
|
||||
util::ShM<extractor::guidance::TurnInstruction, true>::vector
|
||||
turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
|
||||
util::ShM<extractor::guidance::TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list = std::move(turn_instruction_list);
|
||||
|
||||
auto name_id_list_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
@@ -234,9 +229,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
auto geometries_list_ptr =
|
||||
data_layout->GetBlockPtr<extractor::CompressedEdgeContainer::CompressedEdge>(
|
||||
shared_memory, storage::SharedDataLayout::GEOMETRIES_LIST);
|
||||
util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector
|
||||
geometry_list(geometries_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_LIST]);
|
||||
util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector geometry_list(
|
||||
geometries_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_LIST]);
|
||||
m_geometry_list = std::move(geometry_list);
|
||||
|
||||
auto datasources_list_ptr = data_layout->GetBlockPtr<uint8_t>(
|
||||
@@ -354,15 +349,13 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
LoadNames();
|
||||
LoadCoreInformation();
|
||||
LoadProfileProperties();
|
||||
LoadRTree();
|
||||
|
||||
util::SimpleLogger().Write() << "number of geometries: "
|
||||
<< m_coordinate_list->size();
|
||||
for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
|
||||
<< m_coordinate_list.size();
|
||||
for (unsigned i = 0; i < m_coordinate_list.size(); ++i)
|
||||
{
|
||||
if (!GetCoordinateOfNode(i).IsValid())
|
||||
{
|
||||
util::SimpleLogger().Write() << "coordinate " << i << " not valid";
|
||||
}
|
||||
BOOST_ASSERT(GetCoordinateOfNode(i).IsValid());
|
||||
}
|
||||
}
|
||||
util::SimpleLogger().Write(logDEBUG) << "Releasing exclusive lock";
|
||||
@@ -415,7 +408,7 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
// node and edge information access
|
||||
util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
return m_coordinate_list[id];
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const EdgeID id,
|
||||
@@ -466,13 +459,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
}
|
||||
|
||||
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
|
||||
const util::Coordinate north_east) override final
|
||||
const util::Coordinate north_east) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
|
||||
north_east.lat};
|
||||
return m_geospatial_query->Search(bbox);
|
||||
@@ -480,13 +469,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance) override final
|
||||
const float max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
|
||||
}
|
||||
@@ -495,13 +480,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
|
||||
bearing, bearing_range);
|
||||
@@ -509,13 +490,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results) override final
|
||||
const unsigned max_results) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
|
||||
}
|
||||
@@ -523,13 +500,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance) override final
|
||||
const double max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
|
||||
}
|
||||
@@ -538,13 +511,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
|
||||
bearing_range);
|
||||
@@ -555,26 +524,18 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
const unsigned max_results,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
|
||||
bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate) override final
|
||||
const util::Coordinate input_coordinate) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate);
|
||||
@@ -582,13 +543,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance) override final
|
||||
const double max_distance) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance);
|
||||
@@ -598,13 +555,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance, bearing, bearing_range);
|
||||
@@ -613,13 +566,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range) override final
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, bearing, bearing_range);
|
||||
@@ -710,7 +659,10 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
|
||||
std::string GetTimestamp() const override final { return m_timestamp; }
|
||||
|
||||
bool GetContinueStraightDefault() const override final { return m_profile_properties->continue_straight_at_waypoint; }
|
||||
bool GetContinueStraightDefault() const override final
|
||||
{
|
||||
return m_profile_properties->continue_straight_at_waypoint;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace engine
|
||||
|
||||
// Implements complex queries on top of an RTree and builds PhantomNodes from it.
|
||||
//
|
||||
// Only holds a weak reference on the RTree!
|
||||
// Only holds a weak reference on the RTree and coordinates!
|
||||
template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
{
|
||||
using EdgeData = typename RTreeT::EdgeData;
|
||||
@@ -31,9 +31,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
|
||||
public:
|
||||
GeospatialQuery(RTreeT &rtree_,
|
||||
std::shared_ptr<CoordinateList> coordinates_,
|
||||
const CoordinateList &coordinates_,
|
||||
DataFacadeT &datafacade_)
|
||||
: rtree(rtree_), coordinates(std::move(coordinates_)), datafacade(datafacade_)
|
||||
: rtree(rtree_), coordinates(coordinates_), datafacade(datafacade_)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// Returns nearest PhantomNodes in the given bearing range within max_distance.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance)
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance) const
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
@@ -68,7 +68,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range)
|
||||
const int bearing_range) const
|
||||
{
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
@@ -91,7 +91,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range)
|
||||
const int bearing_range) const
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
@@ -115,7 +115,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const unsigned max_results,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range)
|
||||
const int bearing_range) const
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
@@ -136,7 +136,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// Returns max_results nearest PhantomNodes.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results)
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results) const
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
@@ -157,7 +157,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance)
|
||||
const double max_distance) const
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
@@ -179,7 +179,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance)
|
||||
const double max_distance) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -216,7 +216,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate)
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -251,7 +251,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate, const int bearing, const int bearing_range)
|
||||
const util::Coordinate input_coordinate, const int bearing, const int bearing_range) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -297,7 +297,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range)
|
||||
const int bearing_range) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -360,7 +360,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
double ratio;
|
||||
const auto current_perpendicular_distance =
|
||||
util::coordinate_calculation::perpendicularDistance(
|
||||
coordinates->at(data.u), coordinates->at(data.v), input_coordinate,
|
||||
coordinates[data.u], coordinates[data.v], input_coordinate,
|
||||
point_on_segment, ratio);
|
||||
|
||||
// Find the node-based-edge that this belongs to, and directly
|
||||
@@ -418,7 +418,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
|
||||
bool CheckSegmentDistance(const Coordinate input_coordinate,
|
||||
const CandidateSegment &segment,
|
||||
const double max_distance)
|
||||
const double max_distance) const
|
||||
{
|
||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||
!segment.data.forward_segment_id.enabled);
|
||||
@@ -434,7 +434,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
|
||||
std::pair<bool, bool> CheckSegmentBearing(const CandidateSegment &segment,
|
||||
const int filter_bearing,
|
||||
const int filter_bearing_range)
|
||||
const int filter_bearing_range) const
|
||||
{
|
||||
BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
|
||||
!segment.data.forward_segment_id.enabled);
|
||||
@@ -442,7 +442,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
!segment.data.reverse_segment_id.enabled);
|
||||
|
||||
const double forward_edge_bearing = util::coordinate_calculation::bearing(
|
||||
coordinates->at(segment.data.u), coordinates->at(segment.data.v));
|
||||
coordinates[segment.data.u], coordinates[segment.data.v]);
|
||||
|
||||
const double backward_edge_bearing = (forward_edge_bearing + 180) > 360
|
||||
? (forward_edge_bearing - 180)
|
||||
@@ -459,8 +459,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
return std::make_pair(forward_bearing_valid, backward_bearing_valid);
|
||||
}
|
||||
|
||||
RTreeT &rtree;
|
||||
const std::shared_ptr<CoordinateList> coordinates;
|
||||
const RTreeT &rtree;
|
||||
const CoordinateList &coordinates;
|
||||
DataFacadeT &datafacade;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,11 +75,15 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
BaseParametersGrammar(qi::rule<Iterator, Signature> &root_rule)
|
||||
: BaseParametersGrammar::base_type(root_rule)
|
||||
{
|
||||
const auto add_hint = [](engine::api::BaseParameters &base_parameters, const std::string &hint_string)
|
||||
const auto add_hint = [](engine::api::BaseParameters &base_parameters, const boost::optional<std::string> &hint_string)
|
||||
{
|
||||
if (hint_string.size() > 0)
|
||||
if (hint_string)
|
||||
{
|
||||
base_parameters.hints.emplace_back(engine::Hint::FromBase64(hint_string));
|
||||
base_parameters.hints.emplace_back(engine::Hint::FromBase64(hint_string.get()));
|
||||
}
|
||||
else
|
||||
{
|
||||
base_parameters.hints.emplace_back(boost::none);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -134,7 +138,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
|
||||
hints_rule
|
||||
= qi::lit("hints=")
|
||||
> -qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]][ph::bind(add_hint, qi::_r1, qi::_1)] % ';'
|
||||
> (-qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]])[ph::bind(add_hint, qi::_r1, qi::_1)] % ';'
|
||||
;
|
||||
|
||||
bearings_rule
|
||||
|
||||
@@ -55,6 +55,12 @@ template <typename DataT> class SharedMemoryWrapper
|
||||
|
||||
SharedMemoryWrapper(DataT *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
|
||||
|
||||
void reset(DataT *ptr, std::size_t size)
|
||||
{
|
||||
m_ptr = ptr;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
DataT &at(const std::size_t index) { return m_ptr[index]; }
|
||||
|
||||
const DataT &at(const std::size_t index) const { return m_ptr[index]; }
|
||||
@@ -101,6 +107,12 @@ template <> class SharedMemoryWrapper<bool>
|
||||
return m_ptr[bucket] & (1u << offset);
|
||||
}
|
||||
|
||||
void reset(unsigned *ptr, std::size_t size)
|
||||
{
|
||||
m_ptr = ptr;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
|
||||
bool empty() const { return 0 == size(); }
|
||||
|
||||
+83
-101
@@ -17,6 +17,7 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/iostreams/device/mapped_file.hpp>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
@@ -42,8 +43,8 @@ namespace util
|
||||
template <class EdgeDataT,
|
||||
class CoordinateListT = std::vector<Coordinate>,
|
||||
bool UseSharedMemory = false,
|
||||
std::uint32_t BRANCHING_FACTOR = 64,
|
||||
std::uint32_t LEAF_NODE_SIZE = 256>
|
||||
std::uint32_t BRANCHING_FACTOR = 128,
|
||||
std::uint32_t LEAF_PAGE_SIZE = 4096>
|
||||
class StaticRTree
|
||||
{
|
||||
public:
|
||||
@@ -51,6 +52,10 @@ class StaticRTree
|
||||
using EdgeData = EdgeDataT;
|
||||
using CoordinateList = CoordinateListT;
|
||||
|
||||
static_assert(LEAF_PAGE_SIZE >= sizeof(uint32_t) + sizeof(EdgeDataT), "LEAF_PAGE_SIZE is too small");
|
||||
static_assert(((LEAF_PAGE_SIZE - 1) & LEAF_PAGE_SIZE) == 0, "LEAF_PAGE_SIZE is not a power of 2");
|
||||
static constexpr std::uint32_t LEAF_NODE_SIZE = (LEAF_PAGE_SIZE - sizeof(uint32_t)) / sizeof(EdgeDataT);
|
||||
|
||||
struct CandidateSegment
|
||||
{
|
||||
Coordinate fixed_projected_coordinate;
|
||||
@@ -69,9 +74,11 @@ class StaticRTree
|
||||
struct LeafNode
|
||||
{
|
||||
LeafNode() : object_count(0), objects() {}
|
||||
uint32_t object_count;
|
||||
std::uint32_t object_count;
|
||||
std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
|
||||
unsigned char leaf_page_padding[LEAF_PAGE_SIZE - sizeof(std::uint32_t) - sizeof(std::array<EdgeDataT, LEAF_NODE_SIZE>)];
|
||||
};
|
||||
static_assert(sizeof(LeafNode) == LEAF_PAGE_SIZE, "LeafNode size does not fit the page size");
|
||||
|
||||
private:
|
||||
struct WrappedInputElement
|
||||
@@ -93,7 +100,9 @@ class StaticRTree
|
||||
}
|
||||
};
|
||||
|
||||
using QueryNodeType = mapbox::util::variant<TreeNode, CandidateSegment>;
|
||||
struct TreeIndex { std::uint32_t index; };
|
||||
struct SegmentIndex { std::uint32_t index; std::uint32_t object; Coordinate fixed_projected_coordinate; };
|
||||
using QueryNodeType = mapbox::util::variant<TreeIndex, SegmentIndex>;
|
||||
struct QueryCandidate
|
||||
{
|
||||
inline bool operator<(const QueryCandidate &other) const
|
||||
@@ -107,10 +116,11 @@ class StaticRTree
|
||||
};
|
||||
|
||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||
uint64_t m_element_count;
|
||||
const std::string m_leaf_node_filename;
|
||||
std::shared_ptr<CoordinateListT> m_coordinate_list;
|
||||
boost::filesystem::ifstream leaves_stream;
|
||||
const CoordinateListT& m_coordinate_list;
|
||||
|
||||
boost::iostreams::mapped_file_source m_leaves_region;
|
||||
// read-only view of leaves
|
||||
typename ShM<const LeafNode, true>::vector m_leaves;
|
||||
|
||||
public:
|
||||
StaticRTree(const StaticRTree &) = delete;
|
||||
@@ -122,15 +132,16 @@ class StaticRTree
|
||||
const std::string &tree_node_filename,
|
||||
const std::string &leaf_node_filename,
|
||||
const std::vector<CoordinateT> &coordinate_list)
|
||||
: m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
|
||||
: m_coordinate_list(coordinate_list)
|
||||
{
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
||||
const uint64_t element_count = input_data_vector.size();
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(element_count);
|
||||
|
||||
// generate auxiliary vector of hilbert-values
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<uint64_t>(0, m_element_count),
|
||||
tbb::blocked_range<uint64_t>(0, element_count),
|
||||
[&input_data_vector, &input_wrapper_vector,
|
||||
&coordinate_list](const tbb::blocked_range<uint64_t> &range)
|
||||
this](const tbb::blocked_range<uint64_t> &range)
|
||||
{
|
||||
for (uint64_t element_counter = range.begin(), end = range.end();
|
||||
element_counter != end; ++element_counter)
|
||||
@@ -141,11 +152,11 @@ class StaticRTree
|
||||
EdgeDataT const ¤t_element = input_data_vector[element_counter];
|
||||
|
||||
// Get Hilbert-Value for centroid in mercartor projection
|
||||
BOOST_ASSERT(current_element.u < coordinate_list.size());
|
||||
BOOST_ASSERT(current_element.v < coordinate_list.size());
|
||||
BOOST_ASSERT(current_element.u < m_coordinate_list.size());
|
||||
BOOST_ASSERT(current_element.v < m_coordinate_list.size());
|
||||
|
||||
Coordinate current_centroid = coordinate_calculation::centroid(
|
||||
coordinate_list[current_element.u], coordinate_list[current_element.v]);
|
||||
m_coordinate_list[current_element.u], m_coordinate_list[current_element.v]);
|
||||
current_centroid.lat =
|
||||
FixedLatitude(COORDINATE_PRECISION *
|
||||
web_mercator::latToY(toFloating(current_centroid.lat)));
|
||||
@@ -156,7 +167,6 @@ class StaticRTree
|
||||
|
||||
// open leaf file
|
||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||
leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
|
||||
|
||||
// sort the hilbert-value representatives
|
||||
tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
@@ -164,7 +174,7 @@ class StaticRTree
|
||||
|
||||
// pack M elements into leaf node and write to leaf file
|
||||
uint64_t processed_objects_count = 0;
|
||||
while (processed_objects_count < m_element_count)
|
||||
while (processed_objects_count < element_count)
|
||||
{
|
||||
|
||||
LeafNode current_leaf;
|
||||
@@ -172,7 +182,7 @@ class StaticRTree
|
||||
for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
|
||||
++current_element_index)
|
||||
{
|
||||
if (m_element_count > (processed_objects_count + current_element_index))
|
||||
if (element_count > (processed_objects_count + current_element_index))
|
||||
{
|
||||
std::uint32_t index_of_next_object =
|
||||
input_wrapper_vector[processed_objects_count + current_element_index]
|
||||
@@ -185,7 +195,7 @@ class StaticRTree
|
||||
|
||||
// generate tree node that resemble the objects in leaf and store it for next level
|
||||
InitializeMBRectangle(current_node.minimum_bounding_rectangle, current_leaf.objects,
|
||||
current_leaf.object_count, coordinate_list);
|
||||
current_leaf.object_count, m_coordinate_list);
|
||||
current_node.child_is_on_disk = true;
|
||||
current_node.children[0] = tree_nodes_in_level.size();
|
||||
tree_nodes_in_level.emplace_back(current_node);
|
||||
@@ -194,6 +204,8 @@ class StaticRTree
|
||||
leaf_node_file.write((char *)¤t_leaf, sizeof(current_leaf));
|
||||
processed_objects_count += current_leaf.object_count;
|
||||
}
|
||||
leaf_node_file.flush();
|
||||
leaf_node_file.close();
|
||||
|
||||
std::uint32_t processing_level = 0;
|
||||
while (1 < tree_nodes_in_level.size())
|
||||
@@ -258,16 +270,16 @@ class StaticRTree
|
||||
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
|
||||
tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
|
||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
||||
|
||||
MapLeafNodesFile(leaf_node_filename);
|
||||
}
|
||||
|
||||
explicit StaticRTree(const boost::filesystem::path &node_file,
|
||||
const boost::filesystem::path &leaf_file,
|
||||
const std::shared_ptr<CoordinateListT> coordinate_list)
|
||||
: m_leaf_node_filename(leaf_file.string())
|
||||
const CoordinateListT& coordinate_list)
|
||||
: m_coordinate_list(coordinate_list)
|
||||
{
|
||||
// open tree node file and load into RAM.
|
||||
m_coordinate_list = coordinate_list;
|
||||
|
||||
if (!boost::filesystem::exists(node_file))
|
||||
{
|
||||
throw exception("ram index file does not exist");
|
||||
@@ -287,44 +299,34 @@ class StaticRTree
|
||||
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
||||
}
|
||||
|
||||
// open leaf node file and store thread specific pointer
|
||||
if (!boost::filesystem::exists(leaf_file))
|
||||
{
|
||||
throw exception("mem index file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(leaf_file))
|
||||
{
|
||||
throw exception("mem index file is empty");
|
||||
}
|
||||
|
||||
leaves_stream.open(leaf_file, std::ios::binary);
|
||||
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
|
||||
MapLeafNodesFile(leaf_file);
|
||||
}
|
||||
|
||||
explicit StaticRTree(TreeNode *tree_node_ptr,
|
||||
const uint64_t number_of_nodes,
|
||||
const boost::filesystem::path &leaf_file,
|
||||
std::shared_ptr<CoordinateListT> coordinate_list)
|
||||
: m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
|
||||
m_coordinate_list(std::move(coordinate_list))
|
||||
const CoordinateListT& coordinate_list)
|
||||
: m_search_tree(tree_node_ptr, number_of_nodes)
|
||||
, m_coordinate_list(coordinate_list)
|
||||
{
|
||||
// open leaf node file and store thread specific pointer
|
||||
if (!boost::filesystem::exists(leaf_file))
|
||||
{
|
||||
throw exception("mem index file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(leaf_file))
|
||||
{
|
||||
throw exception("mem index file is empty");
|
||||
}
|
||||
MapLeafNodesFile(leaf_file);
|
||||
}
|
||||
|
||||
leaves_stream.open(leaf_file, std::ios::binary);
|
||||
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
|
||||
void MapLeafNodesFile(const boost::filesystem::path &leaf_file)
|
||||
{
|
||||
// open leaf node file and return a pointer to the mapped leaves data
|
||||
try {
|
||||
m_leaves_region.open(leaf_file);
|
||||
std::size_t num_leaves = m_leaves_region.size() / sizeof(LeafNode);
|
||||
m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_region.data()), num_leaves);
|
||||
} catch (std::exception& exc) {
|
||||
throw exception(boost::str(boost::format("Leaf file %1% mapping failed: %2%") % leaf_file % exc.what()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns all features inside the bounding box.
|
||||
Rectangle needs to be projected!*/
|
||||
std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle)
|
||||
std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle) const
|
||||
{
|
||||
const Rectangle projected_rectangle{
|
||||
search_rectangle.min_lon, search_rectangle.max_lon,
|
||||
@@ -334,19 +336,17 @@ class StaticRTree
|
||||
web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.max_lat)))})};
|
||||
std::vector<EdgeDataT> results;
|
||||
|
||||
std::queue<TreeNode> traversal_queue;
|
||||
|
||||
traversal_queue.push(m_search_tree[0]);
|
||||
std::queue<std::uint32_t> traversal_queue;
|
||||
traversal_queue.push(0);
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
auto const current_tree_node = traversal_queue.front();
|
||||
auto const ¤t_tree_node = m_search_tree[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);
|
||||
const LeafNode& current_leaf_node = m_leaves[current_tree_node.children[0]];
|
||||
|
||||
for (const auto i : irange(0u, current_leaf_node.object_count))
|
||||
{
|
||||
@@ -354,14 +354,14 @@ class StaticRTree
|
||||
|
||||
// we don't need to project the coordinates here,
|
||||
// because we use the unprojected rectangle to test against
|
||||
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)};
|
||||
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)};
|
||||
|
||||
// use the _unprojected_ input rectangle here
|
||||
if (bbox.Intersects(search_rectangle))
|
||||
@@ -382,7 +382,7 @@ class StaticRTree
|
||||
|
||||
if (child_rectangle.Intersects(projected_rectangle))
|
||||
{
|
||||
traversal_queue.push(m_search_tree[child_id]);
|
||||
traversal_queue.push(child_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,7 +391,7 @@ class StaticRTree
|
||||
}
|
||||
|
||||
// Override filter and terminator for the desired behaviour.
|
||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, const std::size_t max_results)
|
||||
std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, const std::size_t max_results) const
|
||||
{
|
||||
return Nearest(input_coordinate,
|
||||
[](const CandidateSegment &)
|
||||
@@ -407,7 +407,7 @@ class StaticRTree
|
||||
// Override filter and terminator for the desired behaviour.
|
||||
template <typename FilterT, typename TerminationT>
|
||||
std::vector<EdgeDataT>
|
||||
Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate)
|
||||
Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate) const
|
||||
{
|
||||
std::vector<EdgeDataT> results;
|
||||
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
||||
@@ -415,17 +415,17 @@ class StaticRTree
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
traversal_queue.push(QueryCandidate{0, m_search_tree[0]});
|
||||
traversal_queue.push(QueryCandidate{0, TreeIndex{0}});
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
if (current_query_node.node.template is<TreeNode>())
|
||||
if (current_query_node.node.template is<TreeIndex>())
|
||||
{ // current object is a tree node
|
||||
const TreeNode ¤t_tree_node =
|
||||
current_query_node.node.template get<TreeNode>();
|
||||
m_search_tree[current_query_node.node.template get<TreeIndex>().index];
|
||||
if (current_tree_node.child_is_on_disk)
|
||||
{
|
||||
ExploreLeafNode(current_tree_node.children[0], fixed_projected_coordinate,
|
||||
@@ -439,7 +439,9 @@ class StaticRTree
|
||||
else
|
||||
{
|
||||
// inspecting an actual road segment
|
||||
auto ¤t_candidate = current_query_node.node.template get<CandidateSegment>();
|
||||
const auto &segment_index = current_query_node.node.template get<SegmentIndex>();
|
||||
auto edge_data = m_leaves[segment_index.index].objects[segment_index.object];
|
||||
const auto ¤t_candidate = CandidateSegment{segment_index.fixed_projected_coordinate, edge_data};
|
||||
|
||||
// to allow returns of no-results if too restrictive filtering, this needs to be done here
|
||||
// even though performance would indicate that we want to stop after adding the first candidate
|
||||
@@ -454,11 +456,11 @@ class StaticRTree
|
||||
{
|
||||
continue;
|
||||
}
|
||||
current_candidate.data.forward_segment_id.enabled &= use_segment.first;
|
||||
current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
|
||||
edge_data.forward_segment_id.enabled &= use_segment.first;
|
||||
edge_data.reverse_segment_id.enabled &= use_segment.second;
|
||||
|
||||
// store phantom node in result vector
|
||||
results.push_back(std::move(current_candidate.data));
|
||||
results.push_back(std::move(edge_data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,17 +472,16 @@ class StaticRTree
|
||||
void ExploreLeafNode(const std::uint32_t leaf_id,
|
||||
const Coordinate projected_input_coordinate_fixed,
|
||||
const FloatCoordinate &projected_input_coordinate,
|
||||
QueueT &traversal_queue)
|
||||
QueueT &traversal_queue) const
|
||||
{
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(leaf_id, current_leaf_node);
|
||||
const LeafNode& current_leaf_node = m_leaves[leaf_id];
|
||||
|
||||
// current object represents a block on disk
|
||||
for (const auto i : irange(0u, current_leaf_node.object_count))
|
||||
{
|
||||
const auto ¤t_edge = current_leaf_node.objects[i];
|
||||
const auto projected_u = web_mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
|
||||
const auto projected_v = web_mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
|
||||
const auto projected_u = web_mercator::fromWGS84(m_coordinate_list[current_edge.u]);
|
||||
const auto projected_v = web_mercator::fromWGS84(m_coordinate_list[current_edge.v]);
|
||||
|
||||
FloatCoordinate projected_nearest;
|
||||
std::tie(std::ignore, projected_nearest) =
|
||||
@@ -491,16 +492,14 @@ class StaticRTree
|
||||
projected_input_coordinate_fixed, projected_nearest);
|
||||
// distance must be non-negative
|
||||
BOOST_ASSERT(0. <= squared_distance);
|
||||
traversal_queue.push(
|
||||
QueryCandidate{squared_distance, CandidateSegment{Coordinate{projected_nearest},
|
||||
std::move(current_edge)}});
|
||||
traversal_queue.push(QueryCandidate{squared_distance, SegmentIndex{leaf_id, i, Coordinate{projected_nearest}}});
|
||||
}
|
||||
}
|
||||
|
||||
template <class QueueT>
|
||||
void ExploreTreeNode(const TreeNode &parent,
|
||||
const Coordinate fixed_projected_input_coordinate,
|
||||
QueueT &traversal_queue)
|
||||
QueueT &traversal_queue) const
|
||||
{
|
||||
for (std::uint32_t i = 0; i < parent.child_count; ++i)
|
||||
{
|
||||
@@ -510,27 +509,10 @@ class StaticRTree
|
||||
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]});
|
||||
QueryCandidate{squared_lower_bound_to_element, TreeIndex{static_cast<std::uint32_t>(child_id)}});
|
||||
}
|
||||
}
|
||||
|
||||
inline void LoadLeafFromDisk(const std::uint32_t leaf_id, LeafNode &result_node)
|
||||
{
|
||||
if (!leaves_stream.is_open())
|
||||
{
|
||||
leaves_stream.open(m_leaf_node_filename, std::ios::in | std::ios::binary);
|
||||
}
|
||||
if (!leaves_stream.good())
|
||||
{
|
||||
throw exception("Could not read from leaf file.");
|
||||
}
|
||||
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
|
||||
leaves_stream.seekg(seek_pos);
|
||||
BOOST_ASSERT_MSG(leaves_stream.good(), "Seeking to position in leaf file failed.");
|
||||
leaves_stream.read((char *)&result_node, sizeof(LeafNode));
|
||||
BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
|
||||
}
|
||||
|
||||
template <typename CoordinateT>
|
||||
void InitializeMBRectangle(Rectangle &rectangle,
|
||||
const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
|
||||
|
||||
@@ -35,7 +35,7 @@ inline FloatLatitude yToLat(const double y)
|
||||
const double normalized_lat =
|
||||
detail::RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * detail::DEGREE_TO_RAD));
|
||||
|
||||
return FloatLatitude(normalized_lat - 90.);
|
||||
return FloatLatitude(std::round(normalized_lat * COORDINATE_PRECISION) / COORDINATE_PRECISION - 90.);
|
||||
}
|
||||
|
||||
inline double latToY(const FloatLatitude latitude)
|
||||
@@ -47,6 +47,31 @@ inline double latToY(const FloatLatitude latitude)
|
||||
return clamped_y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr double horner(double, T an) { return an; }
|
||||
|
||||
template<typename T, typename... U>
|
||||
constexpr double horner(double x, T an, U ...a) { return horner(x, a...) * x + an; }
|
||||
|
||||
inline double latToYapprox(const FloatLatitude latitude)
|
||||
{
|
||||
if (latitude < FloatLatitude(-70.) || latitude > FloatLatitude(70.))
|
||||
return latToY(latitude);
|
||||
|
||||
// Approximate the inverse Gudermannian function with the Padé approximant [11/11]: deg → deg
|
||||
// Coefficients are computed for the argument range [-70°,70°] by Remez algorithm |err|_∞=3.387e-12
|
||||
const auto x = static_cast<double>(latitude);
|
||||
return
|
||||
horner(x, 0.00000000000000000000000000e+00, 1.00000000000089108431373566e+00, 2.34439410386997223035693483e-06,
|
||||
-3.21291701673364717170998957e-04, -6.62778508496089940141103135e-10, 3.68188055470304769936079078e-08,
|
||||
6.31192702320492485752941578e-14, -1.77274453235716299127325443e-12, -2.24563810831776747318521450e-18,
|
||||
3.13524754818073129982475171e-17, 2.09014225025314211415458228e-23, -9.82938075991732185095509716e-23) /
|
||||
horner(x, 1.00000000000000000000000000e+00, 2.34439410398970701719081061e-06, -3.72061271627251952928813333e-04,
|
||||
-7.81802389685429267252612620e-10, 5.18418724186576447072888605e-08, 9.37468561198098681003717477e-14,
|
||||
-3.30833288607921773936702558e-12, -4.78446279888774903983338274e-18, 9.32999229169156878168234191e-17,
|
||||
9.17695141954265959600965170e-23, -8.72130728982012387640166055e-22, -3.23083224835967391884404730e-28);
|
||||
}
|
||||
|
||||
inline FloatLatitude clamp(const FloatLatitude lat)
|
||||
{
|
||||
return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
|
||||
@@ -87,7 +112,7 @@ inline double degreeToPixel(FloatLatitude lat, unsigned zoom)
|
||||
|
||||
inline FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
|
||||
{
|
||||
return {wgs84_coordinate.lon, FloatLatitude{latToY(wgs84_coordinate.lat)}};
|
||||
return {wgs84_coordinate.lon, FloatLatitude{latToYapprox(wgs84_coordinate.lat)}};
|
||||
}
|
||||
|
||||
inline FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
|
||||
|
||||
@@ -26,22 +26,21 @@ constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
|
||||
constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
|
||||
|
||||
using RTreeLeaf = extractor::EdgeBasedNode;
|
||||
using CoordinateListPtr = std::shared_ptr<std::vector<util::Coordinate>>;
|
||||
using BenchStaticRTree =
|
||||
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
|
||||
|
||||
CoordinateListPtr loadCoordinates(const boost::filesystem::path &nodes_file)
|
||||
std::vector<util::Coordinate> loadCoordinates(const boost::filesystem::path &nodes_file)
|
||||
{
|
||||
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
|
||||
|
||||
extractor::QueryNode current_node;
|
||||
unsigned coordinate_count = 0;
|
||||
nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
|
||||
auto coords = std::make_shared<std::vector<Coordinate>>(coordinate_count);
|
||||
std::vector<util::Coordinate> coords(coordinate_count);
|
||||
for (unsigned i = 0; i < coordinate_count; ++i)
|
||||
{
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
|
||||
coords->at(i) = util::Coordinate(current_node.lon, current_node.lat);
|
||||
coords[i] = util::Coordinate(current_node.lon, current_node.lat);
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
@@ -330,16 +330,16 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
|
||||
|
||||
using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
|
||||
|
||||
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
|
||||
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||
if (!leaf_node_file)
|
||||
{
|
||||
throw util::exception("Failed to open " + rtree_leaf_filename);
|
||||
}
|
||||
uint64_t m_element_count;
|
||||
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
|
||||
std::size_t leaf_nodes_count = leaf_node_file.tellg() / sizeof(LeafNode);
|
||||
leaf_node_file.seekg(0, std::ios::beg);
|
||||
|
||||
LeafNode current_node;
|
||||
while (m_element_count > 0)
|
||||
while (leaf_nodes_count > 0)
|
||||
{
|
||||
leaf_node_file.read(reinterpret_cast<char *>(¤t_node), sizeof(current_node));
|
||||
|
||||
@@ -435,7 +435,7 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
|
||||
}
|
||||
}
|
||||
}
|
||||
m_element_count -= current_node.object_count;
|
||||
--leaf_nodes_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -563,9 +563,9 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
node_based_edge_list.resize(new_size);
|
||||
|
||||
TIMER_START(construction);
|
||||
util::StaticRTree<EdgeBasedNode> rtree(node_based_edge_list, config.rtree_nodes_output_path,
|
||||
config.rtree_leafs_output_path,
|
||||
internal_to_external_node_map);
|
||||
util::StaticRTree<EdgeBasedNode, std::vector<QueryNode>> rtree(
|
||||
node_based_edge_list, config.rtree_nodes_output_path, config.rtree_leafs_output_path,
|
||||
internal_to_external_node_map);
|
||||
|
||||
TIMER_STOP(construction);
|
||||
util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
|
||||
|
||||
@@ -78,7 +78,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
return TRAVEL_MODE_INACCESSIBLE;
|
||||
}
|
||||
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate /* south_west */,
|
||||
const util::Coordinate /*north_east */) override
|
||||
const util::Coordinate /*north_east */) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -87,14 +87,14 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/) override
|
||||
const int /*bearing_range*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
|
||||
const float /*max_distance*/) override
|
||||
const float /*max_distance*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
const unsigned /*max_results*/,
|
||||
const double /*max_distance*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/) override
|
||||
const int /*bearing_range*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -113,14 +113,14 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
||||
const unsigned /*max_results*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/) override
|
||||
const int /*bearing_range*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
||||
const unsigned /*max_results*/) override
|
||||
const unsigned /*max_results*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -128,21 +128,21 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
std::vector<engine::PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
|
||||
const unsigned /*max_results*/,
|
||||
const double /*max_distance*/) override
|
||||
const double /*max_distance*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate /*input_coordinate*/) override
|
||||
const util::Coordinate /*input_coordinate*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
||||
const double /*max_distance*/) override
|
||||
const double /*max_distance*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -151,7 +151,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
||||
const double /*max_distance*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/) override
|
||||
const int /*bearing_range*/) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -159,7 +159,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade
|
||||
std::pair<engine::PhantomNode, engine::PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
|
||||
const int /*bearing*/,
|
||||
const int /*bearing_range*/) override
|
||||
const int /*bearing_range*/) const override
|
||||
{
|
||||
return {};
|
||||
};
|
||||
|
||||
@@ -44,6 +44,8 @@ BOOST_AUTO_TEST_CASE(invalid_route_urls)
|
||||
32UL);
|
||||
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&hints=foo"),
|
||||
29UL);
|
||||
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&hints=;;; ;"),
|
||||
32UL);
|
||||
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&geometries=foo"),
|
||||
34UL);
|
||||
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&overview=foo"),
|
||||
@@ -88,6 +90,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_1.hints, result_1->hints);
|
||||
|
||||
RouteParameters reference_2{};
|
||||
reference_2.alternatives = true;
|
||||
@@ -104,6 +107,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_2.hints, result_2->hints);
|
||||
|
||||
RouteParameters reference_3{false, false, RouteParameters::GeometriesType::GeoJSON,
|
||||
RouteParameters::OverviewType::False, true};
|
||||
@@ -120,6 +124,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_3.hints, result_3->hints);
|
||||
|
||||
std::vector<boost::optional<engine::Hint>> hints_4 = {
|
||||
engine::Hint::FromBase64("DAIAgP___"
|
||||
@@ -154,6 +159,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_4.hints, result_4->hints);
|
||||
|
||||
std::vector<boost::optional<engine::Bearing>> bearings_4 = {
|
||||
boost::none, engine::Bearing{200, 10}, engine::Bearing{100, 5},
|
||||
@@ -177,6 +183,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_5.bearings, result_5->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_5.hints, result_5->hints);
|
||||
|
||||
std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude(0), util::FloatLatitude(1)},
|
||||
{util::FloatLongitude(2), util::FloatLatitude(3)},
|
||||
@@ -194,6 +201,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_6.hints, result_6->hints);
|
||||
|
||||
auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited");
|
||||
RouteParameters reference_7{};
|
||||
@@ -208,6 +216,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_7.bearings, result_7->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_7.hints, result_7->hints);
|
||||
|
||||
auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;");
|
||||
RouteParameters reference_8{};
|
||||
@@ -223,11 +232,16 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
BOOST_CHECK(result_9);
|
||||
CHECK_EQUAL_RANGE(reference_9.radiuses, result_9->radiuses);
|
||||
|
||||
// Last Hint is empty
|
||||
// Some Hint's are empty
|
||||
std::vector<util::Coordinate> coords_3 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
|
||||
{util::FloatLongitude(3), util::FloatLatitude(4)},
|
||||
{util::FloatLongitude(5), util::FloatLatitude(6)},
|
||||
{util::FloatLongitude(7), util::FloatLatitude(8)}};
|
||||
std::vector<boost::optional<engine::Hint>> hints_10 = {
|
||||
engine::Hint::FromBase64("DAIAgP___"
|
||||
"38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_"
|
||||
"mwIAAAEBl-Umfg=="),
|
||||
boost::none,
|
||||
engine::Hint::FromBase64("cgAAgP___"
|
||||
"39jAAAADgAAACIAAABeAAAAkQAAANoDAABOAgAAGwAAAFVGcQCiRJsCR0VxAOZFmw"
|
||||
"IFAAEBl-Umfg=="),
|
||||
@@ -237,13 +251,13 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
RouteParameters::GeometriesType::Polyline,
|
||||
RouteParameters::OverviewType::Simplified,
|
||||
boost::optional<bool>{},
|
||||
coords_1,
|
||||
coords_3,
|
||||
hints_10,
|
||||
std::vector<boost::optional<double>>{},
|
||||
std::vector<boost::optional<engine::Bearing>>{}};
|
||||
auto result_10 = parseParameters<RouteParameters>(
|
||||
"1,2;3,4?steps=false&hints="
|
||||
"DAIAgP___38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_mwIAAAEBl-Umfg==;"
|
||||
"1,2;3,4;5,6;7,8?steps=false&hints="
|
||||
"DAIAgP___38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_mwIAAAEBl-Umfg==;;"
|
||||
"cgAAgP___39jAAAADgAAACIAAABeAAAAkQAAANoDAABOAgAAGwAAAFVGcQCiRJsCR0VxAOZFmwIFAAEBl-Umfg==;");
|
||||
BOOST_CHECK(result_10);
|
||||
BOOST_CHECK_EQUAL(reference_10.steps, result_10->steps);
|
||||
@@ -254,6 +268,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls)
|
||||
CHECK_EQUAL_RANGE(reference_10.bearings, result_10->bearings);
|
||||
CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses);
|
||||
CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates);
|
||||
CHECK_EQUAL_RANGE(reference_10.hints, result_10->hints);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(valid_table_urls)
|
||||
|
||||
@@ -40,7 +40,7 @@ using TestStaticRTree = StaticRTree<TestData,
|
||||
false,
|
||||
TEST_BRANCHING_FACTOR,
|
||||
TEST_LEAF_NODE_SIZE>;
|
||||
using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 3>;
|
||||
using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 128>;
|
||||
|
||||
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
|
||||
constexpr unsigned RANDOM_SEED = 42;
|
||||
@@ -52,7 +52,7 @@ static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
|
||||
template <typename DataT> class LinearSearchNN
|
||||
{
|
||||
public:
|
||||
LinearSearchNN(const std::shared_ptr<std::vector<Coordinate>> &coords,
|
||||
LinearSearchNN(const std::vector<Coordinate> &coords,
|
||||
const std::vector<DataT> &edges)
|
||||
: coords(coords), edges(edges)
|
||||
{
|
||||
@@ -67,9 +67,9 @@ template <typename DataT> class LinearSearchNN
|
||||
const DataT &rhs) {
|
||||
using web_mercator::fromWGS84;
|
||||
const auto lhs_result = coordinate_calculation::projectPointOnSegment(
|
||||
fromWGS84(coords->at(lhs.u)), fromWGS84(coords->at(lhs.v)), projected_input);
|
||||
fromWGS84(coords[lhs.u]), fromWGS84(coords[lhs.v]), projected_input);
|
||||
const auto rhs_result = coordinate_calculation::projectPointOnSegment(
|
||||
fromWGS84(coords->at(rhs.u)), fromWGS84(coords->at(rhs.v)), projected_input);
|
||||
fromWGS84(coords[rhs.u]), fromWGS84(coords[rhs.v]), projected_input);
|
||||
const auto lhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
|
||||
lhs_result.second, projected_input);
|
||||
const auto rhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
|
||||
@@ -85,7 +85,7 @@ template <typename DataT> class LinearSearchNN
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<std::vector<Coordinate>> &coords;
|
||||
const std::vector<Coordinate> &coords;
|
||||
const std::vector<TestData> &edges;
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
|
||||
}
|
||||
};
|
||||
|
||||
RandomGraphFixture() : coords(std::make_shared<std::vector<Coordinate>>())
|
||||
RandomGraphFixture()
|
||||
{
|
||||
std::mt19937 g(RANDOM_SEED);
|
||||
|
||||
@@ -116,10 +116,10 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
|
||||
{
|
||||
int lon = lon_udist(g);
|
||||
int lat = lat_udist(g);
|
||||
coords->emplace_back(Coordinate(FixedLongitude(lon), FixedLatitude(lat)));
|
||||
coords.emplace_back(Coordinate(FixedLongitude(lon), FixedLatitude(lat)));
|
||||
}
|
||||
|
||||
std::uniform_int_distribution<> edge_udist(0, coords->size() - 1);
|
||||
std::uniform_int_distribution<> edge_udist(0, coords.size() - 1);
|
||||
|
||||
std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
|
||||
|
||||
@@ -138,7 +138,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<Coordinate>> coords;
|
||||
std::vector<Coordinate> coords;
|
||||
std::vector<TestData> edges;
|
||||
};
|
||||
|
||||
@@ -146,12 +146,11 @@ struct GraphFixture
|
||||
{
|
||||
GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords,
|
||||
const std::vector<std::pair<unsigned, unsigned>> &input_edges)
|
||||
: coords(std::make_shared<std::vector<Coordinate>>())
|
||||
{
|
||||
|
||||
for (unsigned i = 0; i < input_coords.size(); i++)
|
||||
{
|
||||
coords->emplace_back(input_coords[i].first, input_coords[i].second);
|
||||
coords.emplace_back(input_coords[i].first, input_coords[i].second);
|
||||
}
|
||||
|
||||
for (const auto &pair : input_edges)
|
||||
@@ -169,7 +168,7 @@ struct GraphFixture
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<Coordinate>> coords;
|
||||
std::vector<Coordinate> coords;
|
||||
std::vector<TestData> edges;
|
||||
};
|
||||
|
||||
@@ -189,13 +188,13 @@ typedef RandomGraphFixture<10, 30> TestRandomGraphFixture_10_30;
|
||||
|
||||
template <typename RTreeT>
|
||||
void simple_verify_rtree(RTreeT &rtree,
|
||||
const std::shared_ptr<std::vector<Coordinate>> &coords,
|
||||
const std::vector<Coordinate> &coords,
|
||||
const std::vector<TestData> &edges)
|
||||
{
|
||||
for (const auto &e : edges)
|
||||
{
|
||||
const Coordinate &pu = coords->at(e.u);
|
||||
const Coordinate &pv = coords->at(e.v);
|
||||
const Coordinate &pu = coords[e.u];
|
||||
const Coordinate &pv = coords[e.v];
|
||||
auto result_u = rtree.Nearest(pu, 1);
|
||||
auto result_v = rtree.Nearest(pv, 1);
|
||||
BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
|
||||
@@ -248,7 +247,7 @@ void build_rtree(const std::string &prefix,
|
||||
nodes_path = prefix + ".ramIndex";
|
||||
leaves_path = prefix + ".fileIndex";
|
||||
|
||||
RTreeT r(fixture->edges, nodes_path, leaves_path, *fixture->coords);
|
||||
RTreeT r(fixture->edges, nodes_path, leaves_path, fixture->coords);
|
||||
}
|
||||
|
||||
template <typename RTreeT = TestStaticRTree, typename FixtureT>
|
||||
@@ -261,12 +260,12 @@ void construction_test(const std::string &prefix, FixtureT *fixture)
|
||||
LinearSearchNN<TestData> lsnn(fixture->coords, fixture->edges);
|
||||
|
||||
simple_verify_rtree(rtree, fixture->coords, fixture->edges);
|
||||
sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100);
|
||||
sampling_verify_rtree(rtree, lsnn, fixture->coords, 100);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(construct_tiny, TestRandomGraphFixture_10_30)
|
||||
{
|
||||
using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 1>;
|
||||
using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 64>;
|
||||
construction_test<TinyTestTree>("test_tiny", this);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user