From cdb1918973cc288876a43b8f28b830582f2cadac Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Thu, 3 Dec 2015 20:04:23 +0100 Subject: [PATCH] Refactor StaticRTree to remove application dependent code StaticRTree now acts like a container, just returning the input data (NodeBasedEdge) and not PhantomNodes. --- .travis.yml | 1 + CMakeLists.txt | 5 +- algorithms/geospatial_query.hpp | 180 ++++ data_structures/hidden_markov_model.hpp | 2 +- data_structures/phantom_node.hpp | 12 +- data_structures/rectangle.hpp | 24 +- data_structures/static_rtree.hpp | 852 ++---------------- extractor/extractor.cpp | 11 +- features/locate/locate.feature | 197 ---- features/step_definitions/locate.rb | 51 -- features/support/route.rb | 8 - features/testbot/post.feature | 18 - library/osrm_impl.cpp | 2 - plugins/distance_table.hpp | 43 +- plugins/locate.hpp | 79 -- plugins/match.hpp | 37 +- plugins/nearest.hpp | 22 +- plugins/trip.hpp | 31 +- plugins/viaroute.hpp | 32 +- routing_algorithms/many_to_many.hpp | 81 +- routing_algorithms/map_matching.hpp | 10 +- server/data_structures/datafacade_base.hpp | 30 +- .../data_structures/internal_datafacade.hpp | 79 +- server/data_structures/shared_datafacade.hpp | 59 +- unit_tests/data_structures/static_rtree.cpp | 333 +++---- unit_tests/util/bearing.cpp | 72 ++ unit_tests/util_tests.cpp | 34 + util/bearing.hpp | 39 + util/matching_debug_info.hpp | 4 +- 29 files changed, 742 insertions(+), 1606 deletions(-) create mode 100644 algorithms/geospatial_query.hpp delete mode 100644 features/locate/locate.feature delete mode 100644 features/step_definitions/locate.rb delete mode 100644 plugins/locate.hpp create mode 100644 unit_tests/util/bearing.cpp create mode 100644 unit_tests/util_tests.cpp diff --git a/.travis.yml b/.travis.yml index ede60ce10..c0659495b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -141,5 +141,6 @@ script: - make benchmarks - ./algorithm-tests - ./datastructure-tests + - ./util-tests - cd .. - cucumber -p verify diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7a652be..e0d001a40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND} COMMENT "Configuring revision fingerprint" VERBATIM) -add_custom_target(tests DEPENDS datastructure-tests algorithm-tests) +add_custom_target(tests DEPENDS datastructure-tests algorithm-tests util-tests) add_custom_target(benchmarks DEPENDS rtree-bench) set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework) @@ -85,6 +85,7 @@ file(GLOB HttpGlob server/http/*.cpp) file(GLOB LibOSRMGlob library/*.cpp) file(GLOB DataStructureTestsGlob unit_tests/data_structures/*.cpp data_structures/hilbert_value.cpp) file(GLOB AlgorithmTestsGlob unit_tests/algorithms/*.cpp algorithms/graph_compressor.cpp) +file(GLOB UtilTestsGlob unit_tests/util/*.cpp) set( OSRMSources @@ -109,6 +110,7 @@ add_executable(osrm-datastore datastore.cpp $ $ $ $ $ $ $ $ $ $) add_executable(algorithm-tests EXCLUDE_FROM_ALL unit_tests/algorithm_tests.cpp ${AlgorithmTestsGlob} $ $ $ $ $ $) +add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob}) # Benchmarks add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $ $ $ $ $) @@ -262,6 +264,7 @@ target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSR target_link_libraries(osrm-datastore ${Boost_LIBRARIES}) target_link_libraries(datastructure-tests ${Boost_LIBRARIES}) target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM) +target_link_libraries(util-tests ${Boost_LIBRARIES}) target_link_libraries(rtree-bench ${Boost_LIBRARIES}) find_package(Threads REQUIRED) diff --git a/algorithms/geospatial_query.hpp b/algorithms/geospatial_query.hpp new file mode 100644 index 000000000..cef178f5e --- /dev/null +++ b/algorithms/geospatial_query.hpp @@ -0,0 +1,180 @@ +#ifndef GEOSPATIAL_QUERY_HPP +#define GEOSPATIAL_QUERY_HPP + +#include "coordinate_calculation.hpp" +#include "../typedefs.h" +#include "../data_structures/phantom_node.hpp" +#include "../util/bearing.hpp" + +#include + +#include +#include +#include + +// Implements complex queries on top of an RTree and builds PhantomNodes from it. +// +// Only holds a weak reference on the RTree! +template class GeospatialQuery +{ + using EdgeData = typename RTreeT::EdgeData; + using CoordinateList = typename RTreeT::CoordinateList; + + public: + GeospatialQuery(RTreeT &rtree_, std::shared_ptr coordinates_) + : rtree(rtree_), coordinates(coordinates_) + { + } + + // Returns nearest PhantomNodes in the given bearing range within max_distance. + // Does not filter by small/big component! + std::vector> + NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate, + const float max_distance, + const int bearing = 0, + const int bearing_range = 180) + { + auto results = + rtree.Nearest(input_coordinate, + [this, bearing, bearing_range, max_distance](const EdgeData &data) + { + return checkSegmentBearing(data, bearing, bearing_range); + }, + [max_distance](const std::size_t, const float min_dist) + { + return min_dist > max_distance; + }); + + return MakePhantomNodes(input_coordinate, results); + } + + // Returns max_results nearest PhantomNodes in the given bearing range. + // Does not filter by small/big component! + std::vector> + NearestPhantomNodes(const FixedPointCoordinate &input_coordinate, + const unsigned max_results, + const int bearing = 0, + const int bearing_range = 180) + { + auto results = rtree.Nearest(input_coordinate, + [this, bearing, bearing_range](const EdgeData &data) + { + return checkSegmentBearing(data, bearing, bearing_range); + }, + [max_results](const std::size_t num_results, const float) + { + return num_results >= max_results; + }); + + return MakePhantomNodes(input_coordinate, results); + } + + // 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 + NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate, + const int bearing = 0, + const int bearing_range = 180) + { + bool has_small_component = false; + bool has_big_component = false; + auto results = rtree.Nearest( + input_coordinate, + [this, bearing, bearing_range, &has_big_component, + &has_small_component](const EdgeData &data) + { + auto use_segment = + (!has_small_component || (!has_big_component && !data.component.is_tiny)) ; + auto use_directions = std::make_pair(use_segment, use_segment); + + if (use_segment) + { + use_directions = checkSegmentBearing(data, bearing, bearing_range); + if (use_directions.first || use_directions.second) + { + has_big_component = has_big_component || !data.component.is_tiny; + has_small_component = has_small_component || data.component.is_tiny; + } + } + + return use_directions; + }, + [&has_big_component](const std::size_t num_results, const float) + { + return num_results > 0 && has_big_component; + }); + + + if (results.size() == 0) + { + return std::make_pair(PhantomNode {}, PhantomNode {}); + } + + BOOST_ASSERT(results.size() > 0); + return std::make_pair(MakePhantomNode(input_coordinate, results.front()).second, MakePhantomNode(input_coordinate, results.back()).second); + } + + private: + inline std::vector> + MakePhantomNodes(const FixedPointCoordinate &input_coordinate, + const std::vector &results) const + { + std::vector> distance_and_phantoms(results.size()); + std::transform(results.begin(), results.end(), distance_and_phantoms.begin(), + [this, &input_coordinate](const EdgeData &data) + { + return MakePhantomNode(input_coordinate, data); + }); + return distance_and_phantoms; + } + + inline std::pair + MakePhantomNode(const FixedPointCoordinate &input_coordinate, const EdgeData &data) const + { + FixedPointCoordinate point_on_segment; + float ratio; + const auto current_perpendicular_distance = coordinate_calculation::perpendicular_distance( + coordinates->at(data.u), coordinates->at(data.v), input_coordinate, point_on_segment, + ratio); + + auto transformed = + std::make_pair(current_perpendicular_distance, PhantomNode{data, point_on_segment}); + + ratio = std::min(1.f, std::max(0.f, ratio)); + + if (SPECIAL_NODEID != transformed.second.forward_node_id) + { + transformed.second.forward_weight *= ratio; + } + if (SPECIAL_NODEID != transformed.second.reverse_node_id) + { + transformed.second.reverse_weight *= 1.f - ratio; + } + return transformed; + } + + inline std::pair checkSegmentBearing(const EdgeData &segment, + const float filter_bearing, + const float filter_bearing_range) + { + const float forward_edge_bearing = + coordinate_calculation::bearing(coordinates->at(segment.u), coordinates->at(segment.v)); + + const float backward_edge_bearing = (forward_edge_bearing + 180) > 360 + ? (forward_edge_bearing - 180) + : (forward_edge_bearing + 180); + + const bool forward_bearing_valid = + bearing::CheckInBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) && + segment.forward_edge_based_node_id != SPECIAL_NODEID; + const bool backward_bearing_valid = + bearing::CheckInBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) && + segment.reverse_edge_based_node_id != SPECIAL_NODEID; + return std::make_pair(forward_bearing_valid, backward_bearing_valid); + } + + RTreeT &rtree; + const std::shared_ptr coordinates; +}; + +#endif diff --git a/data_structures/hidden_markov_model.hpp b/data_structures/hidden_markov_model.hpp index 15aa35b8b..0e8d8a464 100644 --- a/data_structures/hidden_markov_model.hpp +++ b/data_structures/hidden_markov_model.hpp @@ -140,7 +140,7 @@ template struct HiddenMarkovModel for (const auto s : osrm::irange(0u, viterbi[initial_timestamp].size())) { viterbi[initial_timestamp][s] = - emission_log_probability(candidates_list[initial_timestamp][s].second); + emission_log_probability(candidates_list[initial_timestamp][s].first); parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s); pruned[initial_timestamp][s] = viterbi[initial_timestamp][s] < osrm::matching::MINIMAL_LOG_PROB; diff --git a/data_structures/phantom_node.hpp b/data_structures/phantom_node.hpp index 4958c0185..af5632227 100644 --- a/data_structures/phantom_node.hpp +++ b/data_structures/phantom_node.hpp @@ -122,17 +122,7 @@ struct PhantomNode static_assert(sizeof(PhantomNode) == 48, "PhantomNode has more padding then expected"); #endif -using PhantomNodeArray = std::vector>; - -class phantom_node_pair : public std::pair -{ -}; - -struct PhantomNodeLists -{ - std::vector source_phantom_list; - std::vector target_phantom_list; -}; +using PhantomNodePair = std::pair; struct PhantomNodes { diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp index b65c81426..7f6704a9b 100644 --- a/data_structures/rectangle.hpp +++ b/data_structures/rectangle.hpp @@ -170,15 +170,15 @@ struct RectangleInt2D const FixedPointCoordinate lower_right(min_lat, max_lon); const FixedPointCoordinate lower_left(min_lat, min_lon); - min_max_dist = - std::min(min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, upper_left), - coordinate_calculation::great_circle_distance(location, upper_right))); + min_max_dist = std::min( + min_max_dist, + std::max(coordinate_calculation::great_circle_distance(location, upper_left), + coordinate_calculation::great_circle_distance(location, upper_right))); - min_max_dist = - std::min(min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, upper_right), - coordinate_calculation::great_circle_distance(location, lower_right))); + min_max_dist = std::min( + min_max_dist, + std::max(coordinate_calculation::great_circle_distance(location, upper_right), + coordinate_calculation::great_circle_distance(location, lower_right))); min_max_dist = std::min(min_max_dist, @@ -198,14 +198,6 @@ struct RectangleInt2D const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon); return lats_contained && lons_contained; } - - friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect) - { - out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION - << " " << rect.max_lat / COORDINATE_PRECISION << "," - << rect.max_lon / COORDINATE_PRECISION; - return out; - } }; #endif diff --git a/data_structures/static_rtree.hpp b/data_structures/static_rtree.hpp index 9d2ca7804..0e0aaf781 100644 --- a/data_structures/static_rtree.hpp +++ b/data_structures/static_rtree.hpp @@ -30,19 +30,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "deallocating_vector.hpp" #include "hilbert_value.hpp" -#include "phantom_node.hpp" -#include "query_node.hpp" #include "rectangle.hpp" #include "shared_memory_factory.hpp" #include "shared_memory_vector_wrapper.hpp" -#include "upper_bound.hpp" -#include "../util/floating_point.hpp" +#include "../util/bearing.hpp" #include "../util/integer_range.hpp" #include "../util/mercator.hpp" #include "../util/osrm_exception.hpp" -#include "../util/simple_logger.hpp" -#include "../util/timing_util.hpp" #include "../typedefs.h" #include @@ -50,7 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #include @@ -65,7 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -// Implements a static, i.e. packed, R-tree +// Static RTree for serving nearest neighbour queries template , bool UseSharedMemory = false, @@ -74,198 +68,16 @@ template &objects, - const uint32_t element_count, - const std::vector &coordinate_list) - { - for (uint32_t i = 0; i < element_count; ++i) - { - min_lon = std::min(min_lon, std::min(coordinate_list.at(objects[i].u).lon, - coordinate_list.at(objects[i].v).lon)); - max_lon = std::max(max_lon, std::max(coordinate_list.at(objects[i].u).lon, - coordinate_list.at(objects[i].v).lon)); - - min_lat = std::min(min_lat, std::min(coordinate_list.at(objects[i].u).lat, - coordinate_list.at(objects[i].v).lat)); - max_lat = std::max(max_lat, std::max(coordinate_list.at(objects[i].u).lat, - coordinate_list.at(objects[i].v).lat)); - } - BOOST_ASSERT(min_lat != std::numeric_limits::min()); - BOOST_ASSERT(min_lon != std::numeric_limits::min()); - BOOST_ASSERT(max_lat != std::numeric_limits::min()); - BOOST_ASSERT(max_lon != std::numeric_limits::min()); - } - - inline void MergeBoundingBoxes(const RectangleInt2D &other) - { - min_lon = std::min(min_lon, other.min_lon); - max_lon = std::max(max_lon, other.max_lon); - min_lat = std::min(min_lat, other.min_lat); - max_lat = std::max(max_lat, other.max_lat); - BOOST_ASSERT(min_lat != std::numeric_limits::min()); - BOOST_ASSERT(min_lon != std::numeric_limits::min()); - BOOST_ASSERT(max_lat != std::numeric_limits::min()); - BOOST_ASSERT(max_lon != std::numeric_limits::min()); - } - - inline FixedPointCoordinate Centroid() const - { - FixedPointCoordinate centroid; - // The coordinates of the midpoints are given by: - // x = (x1 + x2) /2 and y = (y1 + y2) /2. - centroid.lon = (min_lon + max_lon) / 2; - centroid.lat = (min_lat + max_lat) / 2; - return centroid; - } - - inline bool Intersects(const RectangleInt2D &other) const - { - FixedPointCoordinate upper_left(other.max_lat, other.min_lon); - FixedPointCoordinate upper_right(other.max_lat, other.max_lon); - FixedPointCoordinate lower_right(other.min_lat, other.max_lon); - FixedPointCoordinate lower_left(other.min_lat, other.min_lon); - - return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) || - Contains(lower_left)); - } - - inline float GetMinDist(const FixedPointCoordinate &location) const - { - const bool is_contained = Contains(location); - if (is_contained) - { - return 0.; - } - - enum Direction - { - INVALID = 0, - NORTH = 1, - SOUTH = 2, - EAST = 4, - NORTH_EAST = 5, - SOUTH_EAST = 6, - WEST = 8, - NORTH_WEST = 9, - SOUTH_WEST = 10 - }; - - Direction d = INVALID; - if (location.lat > max_lat) - d = (Direction)(d | NORTH); - else if (location.lat < min_lat) - d = (Direction)(d | SOUTH); - if (location.lon > max_lon) - d = (Direction)(d | EAST); - else if (location.lon < min_lon) - d = (Direction)(d | WEST); - - BOOST_ASSERT(d != INVALID); - - float min_dist = std::numeric_limits::max(); - switch (d) - { - case NORTH: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(max_lat, location.lon)); - break; - case SOUTH: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(min_lat, location.lon)); - break; - case WEST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(location.lat, min_lon)); - break; - case EAST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(location.lat, max_lon)); - break; - case NORTH_EAST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(max_lat, max_lon)); - break; - case NORTH_WEST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(max_lat, min_lon)); - break; - case SOUTH_EAST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(min_lat, max_lon)); - break; - case SOUTH_WEST: - min_dist = coordinate_calculation::great_circle_distance( - location, FixedPointCoordinate(min_lat, min_lon)); - break; - default: - break; - } - - BOOST_ASSERT(min_dist != std::numeric_limits::max()); - - return min_dist; - } - - inline float GetMinMaxDist(const FixedPointCoordinate &location) const - { - float min_max_dist = std::numeric_limits::max(); - // Get minmax distance to each of the four sides - const FixedPointCoordinate upper_left(max_lat, min_lon); - const FixedPointCoordinate upper_right(max_lat, max_lon); - const FixedPointCoordinate lower_right(min_lat, max_lon); - const FixedPointCoordinate lower_left(min_lat, min_lon); - - min_max_dist = std::min( - min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, upper_left), - coordinate_calculation::great_circle_distance(location, upper_right))); - - min_max_dist = std::min( - min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, upper_right), - coordinate_calculation::great_circle_distance(location, lower_right))); - - min_max_dist = std::min( - min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, lower_right), - coordinate_calculation::great_circle_distance(location, lower_left))); - - min_max_dist = std::min( - min_max_dist, - std::max(coordinate_calculation::great_circle_distance(location, lower_left), - coordinate_calculation::great_circle_distance(location, upper_left))); - return min_max_dist; - } - - inline bool Contains(const FixedPointCoordinate &location) const - { - const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat); - const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon); - return lats_contained && lons_contained; - } - - inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect) - { - out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION - << " " << rect.max_lat / COORDINATE_PRECISION << "," - << rect.max_lon / COORDINATE_PRECISION; - return out; - } - }; - - using RectangleT = RectangleInt2D; + static constexpr std::size_t MAX_CHECKED_ELEMENTS = 4 * LEAF_NODE_SIZE; struct TreeNode { TreeNode() : child_count(0), child_is_on_disk(false) {} - RectangleT minimum_bounding_rectangle; + Rectangle minimum_bounding_rectangle; uint32_t child_count : 31; bool child_is_on_disk : 1; uint32_t children[BRANCHING_FACTOR]; @@ -297,40 +109,17 @@ class StaticRTree std::array objects; }; + using QueryNodeType = mapbox::util::variant; struct QueryCandidate { - explicit QueryCandidate(const float dist, const uint32_t n_id) - : min_dist(dist), node_id(n_id) - { - } - QueryCandidate() : min_dist(std::numeric_limits::max()), node_id(UINT_MAX) {} - float min_dist; - uint32_t node_id; inline bool operator<(const QueryCandidate &other) const { // Attn: this is reversed order. std::pq is a max pq! return other.min_dist < min_dist; } - }; - - using IncrementalQueryNodeType = mapbox::util::variant; - struct IncrementalQueryCandidate - { - explicit IncrementalQueryCandidate(const float dist, IncrementalQueryNodeType node) - : min_dist(dist), node(std::move(node)) - { - } - - IncrementalQueryCandidate() : min_dist(std::numeric_limits::max()) {} - - inline bool operator<(const IncrementalQueryCandidate &other) const - { - // Attn: this is reversed order. std::pq is a max pq! - return other.min_dist < min_dist; - } float min_dist; - IncrementalQueryNodeType node; + QueryNodeType node; }; typename ShM::vector m_search_tree; @@ -343,18 +132,14 @@ class StaticRTree StaticRTree() = delete; StaticRTree(const StaticRTree &) = delete; + template // Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1] explicit StaticRTree(const std::vector &input_data_vector, const std::string &tree_node_filename, const std::string &leaf_node_filename, - const std::vector &coordinate_list) + const std::vector &coordinate_list) : m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename) { - SimpleLogger().Write() << "constructing r-tree of " << m_element_count - << " edge elements build on-top of " << coordinate_list.size() - << " coordinates"; - - TIMER_START(construction); std::vector input_wrapper_vector(m_element_count); HilbertCode get_hilbert_number; @@ -362,8 +147,8 @@ class StaticRTree // generate auxiliary vector of hilbert-values tbb::parallel_for( tbb::blocked_range(0, m_element_count), - [&input_data_vector, &input_wrapper_vector, &get_hilbert_number, &coordinate_list]( - const tbb::blocked_range &range) + [&input_data_vector, &input_wrapper_vector, &get_hilbert_number, + &coordinate_list](const tbb::blocked_range &range) { for (uint64_t element_counter = range.begin(), end = range.end(); element_counter != end; ++element_counter) @@ -402,8 +187,6 @@ class StaticRTree LeafNode current_leaf; TreeNode current_node; - // SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << - // (sizeof(TreeNode)*tree_size) << " bytes"; for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index; ++current_element_index) { @@ -497,13 +280,8 @@ class StaticRTree tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree); // close tree node file. tree_node_file.close(); - - TIMER_STOP(construction); - SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction) - << " seconds"; } - // Read-only operation for queries explicit StaticRTree(const boost::filesystem::path &node_file, const boost::filesystem::path &leaf_file, const std::shared_ptr coordinate_list) @@ -543,9 +321,6 @@ class StaticRTree leaves_stream.open(leaf_file, std::ios::binary); leaves_stream.read((char *)&m_element_count, sizeof(uint64_t)); - - // SimpleLogger().Write() << tree_size << " nodes in search tree"; - // SimpleLogger().Write() << m_element_count << " elements in leafs"; } explicit StaticRTree(TreeNode *tree_node_ptr, @@ -567,153 +342,47 @@ class StaticRTree leaves_stream.open(leaf_file, std::ios::binary); leaves_stream.read((char *)&m_element_count, sizeof(uint64_t)); - - // SimpleLogger().Write() << tree_size << " nodes in search tree"; - // SimpleLogger().Write() << m_element_count << " elements in leafs"; - } - // Read-only operation for queries - - bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate, - FixedPointCoordinate &result_coordinate, - const unsigned zoom_level) - { - bool ignore_tiny_components = (zoom_level <= 14); - - float min_dist = std::numeric_limits::max(); - float min_max_dist = std::numeric_limits::max(); - - // initialize queue with root element - std::priority_queue traversal_queue; - traversal_queue.emplace(0.f, 0); - - while (!traversal_queue.empty()) - { - const QueryCandidate current_query_node = traversal_queue.top(); - traversal_queue.pop(); - - const bool prune_downward = (current_query_node.min_dist >= min_max_dist); - const bool prune_upward = (current_query_node.min_dist >= min_dist); - if (!prune_downward && !prune_upward) - { // downward pruning - TreeNode ¤t_tree_node = m_search_tree[current_query_node.node_id]; - if (current_tree_node.child_is_on_disk) - { - LeafNode current_leaf_node; - LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node); - for (uint32_t i = 0; i < current_leaf_node.object_count; ++i) - { - EdgeDataT const ¤t_edge = current_leaf_node.objects[i]; - if (ignore_tiny_components && current_edge.component.is_tiny) - { - continue; - } - - float current_minimum_distance = coordinate_calculation::great_circle_distance( - input_coordinate.lat, input_coordinate.lon, - m_coordinate_list->at(current_edge.u).lat, - m_coordinate_list->at(current_edge.u).lon); - if (current_minimum_distance < min_dist) - { - // found a new minimum - min_dist = current_minimum_distance; - result_coordinate = m_coordinate_list->at(current_edge.u); - } - - current_minimum_distance = coordinate_calculation::great_circle_distance( - input_coordinate.lat, input_coordinate.lon, - m_coordinate_list->at(current_edge.v).lat, - m_coordinate_list->at(current_edge.v).lon); - - if (current_minimum_distance < min_dist) - { - // found a new minimum - min_dist = current_minimum_distance; - result_coordinate = m_coordinate_list->at(current_edge.v); - } - } - } - else - { - min_max_dist = ExploreTreeNode(current_tree_node, input_coordinate, min_dist, - min_max_dist, traversal_queue); - } - } - } - return result_coordinate.is_valid(); } - /** - * Checks whether A is between B-range and B+range, all modulo 360 - * e.g. A = 5, B = 5, range = 10 == true - * A = -6, B = 5, range = 10 == false - * A = -2, B = 355, range = 10 == true - * A = 6, B = 355, range = 10 == false - * A = 355, B = -2, range = 10 == true - * - * @param A the bearing to check, in degrees, 0-359, 0=north - * @param B the bearing to check against, in degrees, 0-359, 0=north - * @param range the number of degrees either side of B that A will still match - * @return true if B-range <= A <= B+range, modulo 360 - * */ - static bool IsBearingWithinBounds(const int A, - const int B, - const int range) + // Override filter and terminator for the desired behaviour. + std::vector Nearest(const FixedPointCoordinate &input_coordinate, + const std::size_t max_results) { - - if (range >= 180) return true; - if (range <= 0) return false; - - // Map both bearings into positive modulo 360 space - const int normalized_B = (B < 0)?(B % 360)+360:(B % 360); - const int normalized_A = (A < 0)?(A % 360)+360:(A % 360); - - if (normalized_B - range < 0) - { - return (normalized_B - range + 360 <= normalized_A && normalized_A < 360) || - (0 <= normalized_A && normalized_A <= normalized_B + range); - } - else if (normalized_B + range > 360) - { - return (normalized_B - range <= normalized_A && normalized_A < 360) || - (0 <= normalized_A && normalized_A <= normalized_B + range - 360); - } - else - { - return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range; - } + return Nearest(input_coordinate, + [](const EdgeDataT &) + { + return std::make_pair(true, true); + }, + [max_results](const std::size_t num_results, const float) + { + return num_results >= max_results; + }); } - - - bool IncrementalFindPhantomNodeForCoordinate( - const FixedPointCoordinate &input_coordinate, - std::vector &result_phantom_node_vector, - const unsigned max_number_of_phantom_nodes, - const int filter_bearing = 0, - const int filter_bearing_range = 180, - const float max_distance = 1100, - const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE) + // Override filter and terminator for the desired behaviour. + template + std::vector Nearest(const FixedPointCoordinate &input_coordinate, + const FilterT filter, + const TerminationT terminate) { - unsigned inspected_elements = 0; - unsigned number_of_elements_from_big_cc = 0; - unsigned number_of_elements_from_tiny_cc = 0; - + std::vector results; std::pair projected_coordinate = { mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION), input_coordinate.lon / COORDINATE_PRECISION}; // initialize queue with root element - std::priority_queue traversal_queue; - traversal_queue.emplace(0.f, m_search_tree[0]); + std::priority_queue traversal_queue; + traversal_queue.push(QueryCandidate {0.f, m_search_tree[0]}); while (!traversal_queue.empty()) { - const IncrementalQueryCandidate current_query_node = traversal_queue.top(); - if (current_query_node.min_dist > max_distance && - inspected_elements > max_checked_elements) + const QueryCandidate current_query_node = traversal_queue.top(); + if (terminate(results.size(), current_query_node.min_dist)) { + traversal_queue = std::priority_queue{}; break; } + traversal_queue.pop(); if (current_query_node.node.template is()) @@ -722,434 +391,81 @@ class StaticRTree current_query_node.node.template get(); if (current_tree_node.child_is_on_disk) { - LeafNode current_leaf_node; - LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node); - - // current object represents a block on disk - for (const auto i : osrm::irange(0u, current_leaf_node.object_count)) - { - const auto ¤t_edge = current_leaf_node.objects[i]; - const float current_perpendicular_distance = coordinate_calculation:: - perpendicular_distance_from_projected_coordinate( - m_coordinate_list->at(current_edge.u), - m_coordinate_list->at(current_edge.v), input_coordinate, - projected_coordinate); - // distance must be non-negative - BOOST_ASSERT(0.f <= current_perpendicular_distance); - - traversal_queue.emplace(current_perpendicular_distance, current_edge); - } + ExploreLeafNode(current_tree_node.children[0], input_coordinate, + projected_coordinate, traversal_queue); } else { - // for each child mbr get a lower bound and enqueue it - for (const auto i : osrm::irange(0u, current_tree_node.child_count)) - { - const int32_t child_id = current_tree_node.children[i]; - const TreeNode &child_tree_node = m_search_tree[child_id]; - const RectangleT &child_rectangle = - child_tree_node.minimum_bounding_rectangle; - const float lower_bound_to_element = - child_rectangle.GetMinDist(input_coordinate); - BOOST_ASSERT(0.f <= lower_bound_to_element); - - traversal_queue.emplace(lower_bound_to_element, child_tree_node); - } + ExploreTreeNode(current_tree_node, input_coordinate, traversal_queue); } } else - { // current object is a leaf node - ++inspected_elements; + { // inspecting an actual road segment - const EdgeDataT ¤t_segment = - current_query_node.node.template get(); + const auto ¤t_segment = current_query_node.node.template get(); - // continue searching for the first segment from a big component - if (number_of_elements_from_big_cc == 0 && - number_of_elements_from_tiny_cc >= max_number_of_phantom_nodes && - current_segment.component.is_tiny) - { - continue; - } - // check if it is smaller than what we had before - float current_ratio = 0.f; - FixedPointCoordinate foot_point_coordinate_on_segment; - - // const float current_perpendicular_distance = - coordinate_calculation::perpendicular_distance_from_projected_coordinate( - m_coordinate_list->at(current_segment.u), - m_coordinate_list->at(current_segment.v), input_coordinate, - projected_coordinate, foot_point_coordinate_on_segment, current_ratio); - - const float forward_edge_bearing = coordinate_calculation::bearing( - m_coordinate_list->at(current_segment.u), - m_coordinate_list->at(current_segment.v)); - - const float backward_edge_bearing = (forward_edge_bearing + 180) > 360 - ? (forward_edge_bearing - 180) - : (forward_edge_bearing + 180); - - const bool forward_bearing_valid = IsBearingWithinBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) - && current_segment.forward_edge_based_node_id != SPECIAL_NODEID; - const bool backward_bearing_valid = IsBearingWithinBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) - && current_segment.reverse_edge_based_node_id != SPECIAL_NODEID; - - if (!forward_bearing_valid && !backward_bearing_valid) + auto use_segment = filter(current_segment); + if (!use_segment.first && !use_segment.second) { continue; } // store phantom node in result vector - result_phantom_node_vector.emplace_back(current_segment, - foot_point_coordinate_on_segment); + results.emplace_back(std::move(current_segment)); - if (!forward_bearing_valid) + if (!use_segment.first) { - result_phantom_node_vector.back().forward_node_id = SPECIAL_NODEID; - } - else if (!backward_bearing_valid) + results.back().forward_edge_based_node_id = SPECIAL_NODEID; + } + else if (!use_segment.second) { - result_phantom_node_vector.back().reverse_node_id = SPECIAL_NODEID; - } - - // Hack to fix rounding errors and wandering via nodes. - FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back()); - - // set forward and reverse weights on the phantom node - SetForwardAndReverseWeightsOnPhantomNode(current_segment, - result_phantom_node_vector.back()); - - // update counts on what we found from which result class - if (current_segment.component.is_tiny) - { // found an element in tiny component - ++number_of_elements_from_tiny_cc; - } - else - { // found an element in a big component - ++number_of_elements_from_big_cc; - } - } - - // stop the search by flushing the queue - if (result_phantom_node_vector.size() >= max_number_of_phantom_nodes && - number_of_elements_from_big_cc > 0) - { - traversal_queue = std::priority_queue{}; - } - } -#ifdef NDEBUG -// SimpleLogger().Write() << "result_phantom_node_vector.size(): " << -// result_phantom_node_vector.size(); -// SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes; -// SimpleLogger().Write() << "number_of_elements_from_big_cc: " << -// number_of_elements_from_big_cc; -// SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " << -// number_of_elements_from_tiny_cc; -// SimpleLogger().Write() << "inspected_elements: " << inspected_elements; -// SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements; -// SimpleLogger().Write() << "pruned_elements: " << pruned_elements; -#endif - return !result_phantom_node_vector.empty(); - } - - // Returns elements within max_distance. - // If the minium of elements could not be found in the search radius, widen - // it until the minimum can be satisfied. - bool IncrementalFindPhantomNodeForCoordinateWithDistance( - const FixedPointCoordinate &input_coordinate, - std::vector> &result_phantom_node_vector, - const double max_distance, - const int filter_bearing = 0, - const int filter_bearing_range = 180, - const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE) - { - unsigned inspected_elements = 0; - - std::pair projected_coordinate = { - mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION), - input_coordinate.lon / COORDINATE_PRECISION}; - - // initialize queue with root element - std::priority_queue traversal_queue; - traversal_queue.emplace(0.f, m_search_tree[0]); - - while (!traversal_queue.empty()) - { - const IncrementalQueryCandidate current_query_node = traversal_queue.top(); - traversal_queue.pop(); - - if (current_query_node.min_dist > max_distance || - inspected_elements >= max_checked_elements) - { - break; - } - - if (current_query_node.node.template is()) - { // current object is a tree node - const TreeNode ¤t_tree_node = - current_query_node.node.template get(); - if (current_tree_node.child_is_on_disk) - { - LeafNode current_leaf_node; - LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node); - - // current object represents a block on disk - for (const auto i : osrm::irange(0u, current_leaf_node.object_count)) - { - const auto ¤t_edge = current_leaf_node.objects[i]; - const float current_perpendicular_distance = coordinate_calculation:: - perpendicular_distance_from_projected_coordinate( - m_coordinate_list->at(current_edge.u), - m_coordinate_list->at(current_edge.v), input_coordinate, - projected_coordinate); - // distance must be non-negative - BOOST_ASSERT(0.f <= current_perpendicular_distance); - - if (current_perpendicular_distance <= max_distance) - { - traversal_queue.emplace(current_perpendicular_distance, current_edge); - } - } - } - else - { - // for each child mbr get a lower bound and enqueue it - for (const auto i : osrm::irange(0u, current_tree_node.child_count)) - { - const int32_t child_id = current_tree_node.children[i]; - const TreeNode &child_tree_node = m_search_tree[child_id]; - const RectangleT &child_rectangle = - child_tree_node.minimum_bounding_rectangle; - const float lower_bound_to_element = - child_rectangle.GetMinDist(input_coordinate); - BOOST_ASSERT(0.f <= lower_bound_to_element); - - if (lower_bound_to_element <= max_distance) - { - traversal_queue.emplace(lower_bound_to_element, child_tree_node); - } - } - } - } - else - { // current object is a leaf node - ++inspected_elements; - // inspecting an actual road segment - const EdgeDataT ¤t_segment = - current_query_node.node.template get(); - - // check if it is smaller than what we had before - float current_ratio = 0.f; - FixedPointCoordinate foot_point_coordinate_on_segment; - - const float current_perpendicular_distance = - coordinate_calculation::perpendicular_distance_from_projected_coordinate( - m_coordinate_list->at(current_segment.u), - m_coordinate_list->at(current_segment.v), input_coordinate, - projected_coordinate, foot_point_coordinate_on_segment, current_ratio); - - if (current_perpendicular_distance >= max_distance) - { - traversal_queue = std::priority_queue{}; - continue; - } - - const float forward_edge_bearing = coordinate_calculation::bearing( - m_coordinate_list->at(current_segment.u), - m_coordinate_list->at(current_segment.v)); - - const float backward_edge_bearing = (forward_edge_bearing + 180) > 360 - ? (forward_edge_bearing - 180) - : (forward_edge_bearing + 180); - - const bool forward_bearing_valid = IsBearingWithinBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) - && current_segment.forward_edge_based_node_id != SPECIAL_NODEID; - const bool backward_bearing_valid = IsBearingWithinBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) - && current_segment.reverse_edge_based_node_id != SPECIAL_NODEID; - - if (!forward_bearing_valid && !backward_bearing_valid) - { - // This edge doesn't fall within our bearing filter - continue; - } - - // store phantom node in result vector - result_phantom_node_vector.emplace_back( - PhantomNode {current_segment, foot_point_coordinate_on_segment}, - current_perpendicular_distance); - - if (!forward_bearing_valid) - { - result_phantom_node_vector.back().first.forward_node_id = SPECIAL_NODEID; - } - if (!backward_bearing_valid) - { - result_phantom_node_vector.back().first.reverse_node_id = SPECIAL_NODEID; - } - - // Hack to fix rounding errors and wandering via nodes. - FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back().first); - - // set forward and reverse weights on the phantom node - SetForwardAndReverseWeightsOnPhantomNode(current_segment, - result_phantom_node_vector.back().first); - } - - // stop the search by flushing the queue - if (inspected_elements >= max_checked_elements) - { - traversal_queue = std::priority_queue{}; - } - } - - return !result_phantom_node_vector.empty(); - } - - bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - PhantomNode &result_phantom_node, - const unsigned zoom_level) - { - const bool ignore_tiny_components = (zoom_level <= 14); - EdgeDataT nearest_edge; - - float min_dist = std::numeric_limits::max(); - float min_max_dist = std::numeric_limits::max(); - - std::priority_queue traversal_queue; - traversal_queue.emplace(0.f, 0); - - while (!traversal_queue.empty()) - { - const QueryCandidate current_query_node = traversal_queue.top(); - traversal_queue.pop(); - - const bool prune_downward = (current_query_node.min_dist > min_max_dist); - const bool prune_upward = (current_query_node.min_dist > min_dist); - if (!prune_downward && !prune_upward) - { // downward pruning - const TreeNode ¤t_tree_node = m_search_tree[current_query_node.node_id]; - if (current_tree_node.child_is_on_disk) - { - LeafNode current_leaf_node; - LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node); - for (uint32_t i = 0; i < current_leaf_node.object_count; ++i) - { - const EdgeDataT ¤t_edge = current_leaf_node.objects[i]; - if (ignore_tiny_components && current_edge.component.is_tiny != 0) - { - continue; - } - - float current_ratio = 0.; - FixedPointCoordinate nearest; - const float current_perpendicular_distance = - coordinate_calculation::perpendicular_distance( - m_coordinate_list->at(current_edge.u), - m_coordinate_list->at(current_edge.v), input_coordinate, nearest, - current_ratio); - - BOOST_ASSERT(0. <= current_perpendicular_distance); - - if ((current_perpendicular_distance < min_dist) && - !osrm::epsilon_compare(current_perpendicular_distance, min_dist)) - { // found a new minimum - min_dist = current_perpendicular_distance; - result_phantom_node = {current_edge, nearest}; - nearest_edge = current_edge; - } - } - } - else - { - min_max_dist = ExploreTreeNode(current_tree_node, input_coordinate, min_dist, - min_max_dist, traversal_queue); + results.back().reverse_edge_based_node_id = SPECIAL_NODEID; } } } - if (result_phantom_node.location.is_valid()) - { - // Hack to fix rounding errors and wandering via nodes. - FixUpRoundingIssue(input_coordinate, result_phantom_node); - - // set forward and reverse weights on the phantom node - SetForwardAndReverseWeightsOnPhantomNode(nearest_edge, result_phantom_node); - } - return result_phantom_node.location.is_valid(); + return results; } private: - inline void SetForwardAndReverseWeightsOnPhantomNode(const EdgeDataT &nearest_edge, - PhantomNode &result_phantom_node) const + template + void ExploreLeafNode(const std::uint32_t leaf_id, + const FixedPointCoordinate &input_coordinate, + const std::pair &projected_coordinate, + QueueT &traversal_queue) { - const float distance_1 = coordinate_calculation::great_circle_distance( - m_coordinate_list->at(nearest_edge.u), result_phantom_node.location); - const float distance_2 = coordinate_calculation::great_circle_distance( - m_coordinate_list->at(nearest_edge.u), m_coordinate_list->at(nearest_edge.v)); - const float ratio = std::min(1.f, distance_1 / distance_2); + LeafNode current_leaf_node; + LoadLeafFromDisk(leaf_id, current_leaf_node); - using TreeWeightType = decltype(result_phantom_node.forward_weight); - static_assert(std::is_same::value, - "forward and reverse weight type in tree must be the same"); + // current object represents a block on disk + for (const auto i : osrm::irange(0u, current_leaf_node.object_count)) + { + auto ¤t_edge = current_leaf_node.objects[i]; + const float current_perpendicular_distance = + coordinate_calculation::perpendicular_distance_from_projected_coordinate( + m_coordinate_list->at(current_edge.u), m_coordinate_list->at(current_edge.v), + input_coordinate, projected_coordinate); + // distance must be non-negative + BOOST_ASSERT(0.f <= current_perpendicular_distance); - if (SPECIAL_NODEID != result_phantom_node.forward_node_id) - { - const auto new_weight = - static_cast(result_phantom_node.forward_weight * ratio); - result_phantom_node.forward_weight = new_weight; - } - if (SPECIAL_NODEID != result_phantom_node.reverse_node_id) - { - const auto new_weight = - static_cast(result_phantom_node.reverse_weight * (1.f - ratio)); - result_phantom_node.reverse_weight = new_weight; - } - } - - // fixup locations if too close to inputs - inline void FixUpRoundingIssue(const FixedPointCoordinate &input_coordinate, - PhantomNode &result_phantom_node) const - { - if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon)) - { - result_phantom_node.location.lon = input_coordinate.lon; - } - if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat)) - { - result_phantom_node.location.lat = input_coordinate.lat; + traversal_queue.push(QueryCandidate {current_perpendicular_distance, std::move(current_edge)}); } } template - inline float ExploreTreeNode(const TreeNode &parent, - const FixedPointCoordinate &input_coordinate, - const float min_dist, - const float min_max_dist, - QueueT &traversal_queue) + void ExploreTreeNode(const TreeNode &parent, + const FixedPointCoordinate &input_coordinate, + QueueT &traversal_queue) { - float new_min_max_dist = min_max_dist; - // traverse children, prune if global mindist is smaller than local one for (uint32_t i = 0; i < parent.child_count; ++i) { const int32_t child_id = parent.children[i]; - const TreeNode &child_tree_node = m_search_tree[child_id]; - const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle; + const auto &child_tree_node = m_search_tree[child_id]; + const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle; const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate); - const float upper_bound_to_element = child_rectangle.GetMinMaxDist(input_coordinate); - new_min_max_dist = std::min(new_min_max_dist, upper_bound_to_element); - if (lower_bound_to_element > new_min_max_dist) - { - continue; - } - if (lower_bound_to_element > min_dist) - { - continue; - } - traversal_queue.emplace(lower_bound_to_element, child_id); + traversal_queue.push(QueryCandidate {lower_bound_to_element, m_search_tree[child_id]}); } - return new_min_max_dist; } inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node) @@ -1161,7 +477,6 @@ class StaticRTree if (!leaves_stream.good()) { leaves_stream.clear(std::ios::goodbit); - SimpleLogger().Write(logDEBUG) << "Resetting stale filestream"; } const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode); leaves_stream.seekg(seek_pos); @@ -1170,18 +485,11 @@ class StaticRTree BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed."); } - inline bool EdgesAreEquivalent(const FixedPointCoordinate &a, - const FixedPointCoordinate &b, - const FixedPointCoordinate &c, - const FixedPointCoordinate &d) const - { - return (a == b && c == d) || (a == c && b == d) || (a == d && b == c); - } - - inline void InitializeMBRectangle(RectangleT &rectangle, - const std::array &objects, - const uint32_t element_count, - const std::vector &coordinate_list) + template + void InitializeMBRectangle(Rectangle &rectangle, + const std::array &objects, + const uint32_t element_count, + const std::vector &coordinate_list) { for (uint32_t i = 0; i < element_count; ++i) { diff --git a/extractor/extractor.cpp b/extractor/extractor.cpp index a94795917..4fa6997aa 100644 --- a/extractor/extractor.cpp +++ b/extractor/extractor.cpp @@ -573,11 +573,20 @@ void extractor::WriteNodeMapping(const std::vector & internal_to_exte Saves tree into '.ramIndex' and leaves into '.fileIndex'. */ void extractor::BuildRTree(const std::vector &node_based_edge_list, - const std::vector &internal_to_external_node_map) + const std::vector &internal_to_external_node_map) { + SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size() + << " edge elements build on-top of " << internal_to_external_node_map.size() + << " coordinates"; + + TIMER_START(construction); StaticRTree(node_based_edge_list, config.rtree_nodes_output_path.c_str(), config.rtree_leafs_output_path.c_str(), internal_to_external_node_map); + + TIMER_STOP(construction); + SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction) + << " seconds"; } void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename, diff --git a/features/locate/locate.feature b/features/locate/locate.feature deleted file mode 100644 index 838bcd5cd..000000000 --- a/features/locate/locate.feature +++ /dev/null @@ -1,197 +0,0 @@ -@locate -Feature: Locate - return nearest node - - Background: - Given the profile "testbot" - - Scenario: Locate - two ways crossing - Given the node map - | | | 0 | c | 1 | | | - | | | | | | | | - | 7 | | | n | | | 2 | - | a | | k | x | m | | b | - | 6 | | | l | | | 3 | - | | | | | | | | - | | | 5 | d | 4 | | | - - And the ways - | nodes | - | axb | - | cxd | - - When I request locate I should get - | in | out | - | 0 | c | - | 1 | c | - | 2 | b | - | 3 | b | - | 4 | d | - | 5 | d | - | 6 | a | - | 7 | a | - | a | a | - | b | b | - | c | c | - | d | d | - | k | x | - | l | x | - | m | x | - | n | x | - - Scenario: Locate - inside a triangle - Given the node map - | | | | | | c | | | | | | - | | | | | | 7 | | | | | | - | | | | y | | | | z | | | | - | | | 5 | | 0 | | 1 | | 8 | | | - | 6 | | | 2 | | 3 | | 4 | | | 9 | - | a | | | x | | u | | w | | | b | - - And the ways - | nodes | - | ab | - | bc | - | ca | - - When I request locate I should get - | in | out | - | 0 | c | - | 1 | c | - | 2 | a | - | 3 | c | - | 4 | b | - | 5 | a | - | 6 | a | - | 7 | c | - | 8 | b | - | 9 | b | - | x | a | - | y | c | - | z | c | - | w | b | - - Scenario: Nearest - easy-west way - Given the node map - | 3 | 4 | | 5 | 6 | - | 2 | a | x | b | 7 | - | 1 | 0 | | 9 | 8 | - - And the ways - | nodes | - | ab | - - When I request locate I should get - | in | out | - | 0 | a | - | 1 | a | - | 2 | a | - | 3 | a | - | 4 | a | - | 5 | b | - | 6 | b | - | 7 | b | - | 8 | b | - | 9 | b | - - Scenario: Nearest - north-south way - Given the node map - | 1 | 2 | 3 | - | 0 | a | 4 | - | | x | | - | 9 | b | 5 | - | 8 | 7 | 6 | - - And the ways - | nodes | - | ab | - - When I request locate I should get - | in | out | - | 0 | a | - | 1 | a | - | 2 | a | - | 3 | a | - | 4 | a | - | 5 | b | - | 6 | b | - | 7 | b | - | 8 | b | - | 9 | b | - - Scenario: Nearest - diagonal 1 - Given the node map - | 2 | | 3 | | | | - | | a | | 4 | | | - | 1 | | x | | 5 | | - | | 0 | | y | | 6 | - | | | 9 | | b | | - | | | | 8 | | 7 | - - And the ways - | nodes | - | axyb | - - When I request locate I should get - | in | out | - | 0 | x | - | 1 | a | - | 2 | a | - | 3 | a | - | 4 | x | - | 5 | y | - | 6 | b | - | 7 | b | - | 8 | b | - | 9 | y | - | a | a | - | b | b | - | x | x | - | y | y | - - Scenario: Nearest - diagonal 2 - Given the node map - | | | | 6 | | 7 | - | | | 5 | | b | | - | | 4 | | y | | 8 | - | 3 | | x | | 9 | | - | | a | | 0 | | | - | 2 | | 1 | | | | - - And the ways - | nodes | - | ab | - - When I request nearest I should get - | in | out | - | 0 | x | - | 1 | a | - | 2 | a | - | 3 | a | - | 4 | x | - | 5 | y | - | 6 | b | - | 7 | b | - | 8 | b | - | 9 | y | - | a | a | - | b | b | - | x | x | - | y | y | - - Scenario: Locate - High lat/lon - Given the node locations - | node | lat | lon | - | a | -85 | -180 | - | b | 0 | 0 | - | c | 85 | 180 | - | x | -84 | -180 | - | y | 84 | 180 | - - And the ways - | nodes | - | abc | - - When I request locate I should get - | in | out | - | x | a | - | y | c | diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb deleted file mode 100644 index c9804b19d..000000000 --- a/features/step_definitions/locate.rb +++ /dev/null @@ -1,51 +0,0 @@ -When /^I request locate I should get$/ do |table| - reprocess - actual = [] - OSRMLoader.load(self,"#{prepared_file}.osrm") do - table.hashes.each_with_index do |row,ri| - in_node = find_node_by_name row['in'] - raise "*** unknown in-node '#{row['in']}" unless in_node - - out_node = find_node_by_name row['out'] - raise "*** unknown out-node '#{row['out']}" unless out_node - - response = request_locate in_node, @query_params - if response.code == "200" && response.body.empty? == false - json = JSON.parse response.body - if json['status'] == 0 - coord = json['mapped_coordinate'] - end - end - - got = {'in' => row['in'], 'out' => coord } - - ok = true - row.keys.each do |key| - if key=='out' - if FuzzyMatch.match_location coord, out_node - got[key] = row[key] - else - row[key] = "#{row[key]} [#{out_node.lat},#{out_node.lon}]" - ok = false - end - end - end - - unless ok - failed = { :attempt => 'locate', :query => @query, :response => response } - log_fail row,got,[failed] - end - - actual << got - end - end - table.diff! actual -end - -When /^I request locate (\d+) times I should get$/ do |n,table| - ok = true - n.to_i.times do - ok = false unless step "I request locate I should get", table - end - ok -end diff --git a/features/support/route.rb b/features/support/route.rb index 7086fe6a5..c13dc0e35 100644 --- a/features/support/route.rb +++ b/features/support/route.rb @@ -58,14 +58,6 @@ def request_route waypoints, bearings, user_params return request_path "viaroute", params end -def request_locate node, user_params - defaults = [['output', 'json']] - params = overwrite_params defaults, user_params - params << ["loc", "#{node.lat},#{node.lon}"] - - return request_path "locate", params -end - def request_nearest node, user_params defaults = [['output', 'json']] params = overwrite_params defaults, user_params diff --git a/features/testbot/post.feature b/features/testbot/post.feature index ceacbb0ee..ac53177c5 100644 --- a/features/testbot/post.feature +++ b/features/testbot/post.feature @@ -62,24 +62,6 @@ Feature: POST request | d | 200 | 300 | 0 | 300 | | e | 300 | 400 | 100 | 0 | - Scenario: Testbot - locate POST request - Given the node locations - | node | lat | lon | - | a | -85 | -180 | - | b | 0 | 0 | - | c | 85 | 180 | - | x | -84 | -180 | - | y | 84 | 180 | - - And the ways - | nodes | - | abc | - - When I request locate I should get - | in | out | - | x | a | - | y | c | - Scenario: Testbot - nearest POST request Given the node locations | node | lat | lon | diff --git a/library/osrm_impl.cpp b/library/osrm_impl.cpp index 075c65f79..df1e68fe1 100644 --- a/library/osrm_impl.cpp +++ b/library/osrm_impl.cpp @@ -38,7 +38,6 @@ class named_mutex; #include "../plugins/distance_table.hpp" #include "../plugins/hello_world.hpp" -#include "../plugins/locate.hpp" #include "../plugins/nearest.hpp" #include "../plugins/timestamp.hpp" #include "../plugins/trip.hpp" @@ -81,7 +80,6 @@ OSRM_impl::OSRM_impl(libosrm_config &lib_config) RegisterPlugin(new DistanceTablePlugin>( query_data_facade, lib_config.max_locations_distance_table)); RegisterPlugin(new HelloWorldPlugin()); - RegisterPlugin(new LocatePlugin>(query_data_facade)); RegisterPlugin(new NearestPlugin>(query_data_facade)); RegisterPlugin(new MapMatchingPlugin>( query_data_facade, lib_config.max_locations_map_matching)); diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp index f44c71fab..181493e1f 100644 --- a/plugins/distance_table.hpp +++ b/plugins/distance_table.hpp @@ -108,8 +108,8 @@ template class DistanceTablePlugin final : public BasePlugin const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); - PhantomNodeArray phantom_node_source_vector(number_of_sources); - PhantomNodeArray phantom_node_target_vector(number_of_destination); + std::vector phantom_node_source_vector(number_of_sources); + std::vector phantom_node_target_vector(number_of_destination); auto phantom_node_source_out_iter = phantom_node_source_vector.begin(); auto phantom_node_target_out_iter = phantom_node_target_vector.begin(); for (const auto i : osrm::irange(0u, route_parameters.coordinates.size())) @@ -123,7 +123,7 @@ template class DistanceTablePlugin final : public BasePlugin { if (route_parameters.is_source[i]) { - phantom_node_source_out_iter->emplace_back(std::move(current_phantom_node)); + *phantom_node_source_out_iter = std::make_pair(current_phantom_node, current_phantom_node); if (route_parameters.is_destination[i]) { *phantom_node_target_out_iter = *phantom_node_source_out_iter; @@ -134,7 +134,7 @@ template class DistanceTablePlugin final : public BasePlugin else { BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]); - phantom_node_target_out_iter->emplace_back(std::move(current_phantom_node)); + *phantom_node_target_out_iter = std::make_pair(current_phantom_node, current_phantom_node); phantom_node_target_out_iter++; } continue; @@ -146,11 +146,14 @@ template class DistanceTablePlugin final : public BasePlugin : 180; if (route_parameters.is_source[i]) { - facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], - *phantom_node_source_out_iter, 1, - bearing, range); - BOOST_ASSERT( - phantom_node_source_out_iter->front().is_valid(facade->GetNumberOfNodes())); + *phantom_node_source_out_iter = facade->NearestPhantomNodeWithAlternativeFromBigComponent(route_parameters.coordinates[i], bearing, range); + // we didn't found a fitting node, return error + if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes())) + { + json_result.values["status_message"] = std::string("Could not find matching road for via ") + std::to_string(i); + return 400; + } + if (route_parameters.is_destination[i]) { *phantom_node_target_out_iter = *phantom_node_source_out_iter; @@ -161,14 +164,16 @@ template class DistanceTablePlugin final : public BasePlugin else { BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]); - facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], - *phantom_node_target_out_iter, 1, - bearing, range); - BOOST_ASSERT( - phantom_node_target_out_iter->front().is_valid(facade->GetNumberOfNodes())); + + *phantom_node_target_out_iter = facade->NearestPhantomNodeWithAlternativeFromBigComponent(route_parameters.coordinates[i], bearing, range); + // we didn't found a fitting node, return error + if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes())) + { + json_result.values["status_message"] = std::string("Could not find matching road for via ") + std::to_string(i); + return 400; + } phantom_node_target_out_iter++; } - } BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) == number_of_sources); @@ -195,20 +200,20 @@ template class DistanceTablePlugin final : public BasePlugin } json_result.values["distance_table"] = matrix_json_array; osrm::json::Array target_coord_json_array; - for (const std::vector &phantom_node_vector : phantom_node_target_vector) + for (const auto &pair : phantom_node_target_vector) { osrm::json::Array json_coord; - FixedPointCoordinate coord = phantom_node_vector[0].location; + FixedPointCoordinate coord = pair.first.location; json_coord.values.push_back(coord.lat / COORDINATE_PRECISION); json_coord.values.push_back(coord.lon / COORDINATE_PRECISION); target_coord_json_array.values.push_back(json_coord); } json_result.values["destination_coordinates"] = target_coord_json_array; osrm::json::Array source_coord_json_array; - for (const std::vector &phantom_node_vector : phantom_node_source_vector) + for (const auto &pair : phantom_node_source_vector) { osrm::json::Array json_coord; - FixedPointCoordinate coord = phantom_node_vector[0].location; + FixedPointCoordinate coord = pair.first.location; json_coord.values.push_back(coord.lat / COORDINATE_PRECISION); json_coord.values.push_back(coord.lon / COORDINATE_PRECISION); source_coord_json_array.values.push_back(json_coord); diff --git a/plugins/locate.hpp b/plugins/locate.hpp deleted file mode 100644 index 144765ad8..000000000 --- a/plugins/locate.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - -Copyright (c) 2015, Project OSRM contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -#ifndef LOCATE_HPP -#define LOCATE_HPP - -#include "plugin_base.hpp" - -#include "../util/json_renderer.hpp" -#include "../util/string_util.hpp" - -#include - -#include - -// locates the nearest node in the road network for a given coordinate. -template class LocatePlugin final : public BasePlugin -{ - public: - explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {} - const std::string GetDescriptor() const override final { return descriptor_string; } - - int HandleRequest(const RouteParameters &route_parameters, - osrm::json::Object &json_result) override final - { - // check number of parameters - if (route_parameters.coordinates.empty() || - !route_parameters.coordinates.front().is_valid()) - { - return 400; - } - - FixedPointCoordinate result; - if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(), - result)) - { - json_result.values["status"] = 207; - } - else - { - json_result.values["status"] = 0; - osrm::json::Array json_coordinate; - json_coordinate.values.push_back(result.lat / COORDINATE_PRECISION); - json_coordinate.values.push_back(result.lon / COORDINATE_PRECISION); - json_result.values["mapped_coordinate"] = json_coordinate; - } - return 200; - } - - private: - std::string descriptor_string; - DataFacadeT *facade; -}; - -#endif /* LOCATE_HPP */ diff --git a/plugins/match.hpp b/plugins/match.hpp index cdf3e2017..79d479b81 100644 --- a/plugins/match.hpp +++ b/plugins/match.hpp @@ -128,28 +128,25 @@ template class MapMatchingPlugin : public BasePlugin } } - std::vector> candidates; // Use bearing values if supplied, otherwise fallback to 0,180 defaults auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0; auto range = input_bearings.size() > 0 ? (input_bearings[current_coordinate].second ? *input_bearings[current_coordinate].second : 10 ) : 180; - facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance( - input_coords[current_coordinate], candidates, query_radius, - bearing, range); + auto candidates = facade->NearestPhantomNodesInRange(input_coords[current_coordinate], query_radius, bearing, range); // sort by foward id, then by reverse id and then by distance std::sort(candidates.begin(), candidates.end(), - [](const std::pair& lhs, const std::pair& rhs) { - return lhs.first.forward_node_id < rhs.first.forward_node_id || - (lhs.first.forward_node_id == rhs.first.forward_node_id && - (lhs.first.reverse_node_id < rhs.first.reverse_node_id || - (lhs.first.reverse_node_id == rhs.first.reverse_node_id && - lhs.second < rhs.second))); + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.second.forward_node_id < rhs.second.forward_node_id || + (lhs.second.forward_node_id == rhs.second.forward_node_id && + (lhs.second.reverse_node_id < rhs.second.reverse_node_id || + (lhs.second.reverse_node_id == rhs.second.reverse_node_id && + lhs.first < rhs.first))); }); auto new_end = std::unique(candidates.begin(), candidates.end(), - [](const std::pair& lhs, const std::pair& rhs) { - return lhs.first.forward_node_id == rhs.first.forward_node_id && - lhs.first.reverse_node_id == rhs.first.reverse_node_id; + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.second.forward_node_id == rhs.second.forward_node_id && + lhs.second.reverse_node_id == rhs.second.reverse_node_id; }); candidates.resize(new_end - candidates.begin()); @@ -159,22 +156,22 @@ template class MapMatchingPlugin : public BasePlugin for (const auto i : osrm::irange(0, compact_size)) { // Split edge if it is bidirectional and append reverse direction to end of list - if (candidates[i].first.forward_node_id != SPECIAL_NODEID && - candidates[i].first.reverse_node_id != SPECIAL_NODEID) + if (candidates[i].second.forward_node_id != SPECIAL_NODEID && + candidates[i].second.reverse_node_id != SPECIAL_NODEID) { - PhantomNode reverse_node(candidates[i].first); + PhantomNode reverse_node(candidates[i].second); reverse_node.forward_node_id = SPECIAL_NODEID; - candidates.push_back(std::make_pair(reverse_node, candidates[i].second)); + candidates.push_back(std::make_pair(candidates[i].first, reverse_node)); - candidates[i].first.reverse_node_id = SPECIAL_NODEID; + candidates[i].second.reverse_node_id = SPECIAL_NODEID; } } } // sort by distance to make pruning effective std::sort(candidates.begin(), candidates.end(), - [](const std::pair& lhs, const std::pair& rhs) { - return lhs.second < rhs.second; + [](const std::pair& lhs, const std::pair& rhs) { + return lhs.first < rhs.first; }); candidates_lists.push_back(std::move(candidates)); diff --git a/plugins/nearest.hpp b/plugins/nearest.hpp index e3cf72ed5..87458b182 100644 --- a/plugins/nearest.hpp +++ b/plugins/nearest.hpp @@ -67,14 +67,11 @@ template class NearestPlugin final : public BasePlugin } auto number_of_results = static_cast(route_parameters.num_results); - std::vector phantom_node_vector; const int bearing = input_bearings.size() > 0 ? input_bearings.front().first : 0; const int range = input_bearings.size() > 0 ? (input_bearings.front().second?*input_bearings.front().second:10) : 180; - facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(), - phantom_node_vector, - static_cast(number_of_results), bearing, range); + auto phantom_node_vector = facade->NearestPhantomNodes(route_parameters.coordinates.front(), number_of_results, bearing, range); - if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid()) + if (phantom_node_vector.empty() || !phantom_node_vector.front().second.is_valid()) { json_result.values["status"] = 207; } @@ -91,15 +88,14 @@ template class NearestPlugin final : public BasePlugin for (const auto i : osrm::irange(0, std::min(number_of_results, vector_length))) { + const auto& node = phantom_node_vector[i].second; osrm::json::Array json_coordinate; osrm::json::Object result; - json_coordinate.values.push_back(phantom_node_vector.at(i).location.lat / - COORDINATE_PRECISION); - json_coordinate.values.push_back(phantom_node_vector.at(i).location.lon / - COORDINATE_PRECISION); + json_coordinate.values.push_back(node.location.lat / COORDINATE_PRECISION); + json_coordinate.values.push_back(node.location.lon / COORDINATE_PRECISION); result.values["mapped coordinate"] = json_coordinate; result.values["name"] = - facade->get_name_for_id(phantom_node_vector.at(i).name_id); + facade->get_name_for_id(node.name_id); results.values.push_back(result); } json_result.values["results"] = results; @@ -107,13 +103,13 @@ template class NearestPlugin final : public BasePlugin else { osrm::json::Array json_coordinate; - json_coordinate.values.push_back(phantom_node_vector.front().location.lat / + json_coordinate.values.push_back(phantom_node_vector.front().second.location.lat / COORDINATE_PRECISION); - json_coordinate.values.push_back(phantom_node_vector.front().location.lon / + json_coordinate.values.push_back(phantom_node_vector.front().second.location.lon / COORDINATE_PRECISION); json_result.values["mapped_coordinate"] = json_coordinate; json_result.values["name"] = - facade->get_name_for_id(phantom_node_vector.front().name_id); + facade->get_name_for_id(phantom_node_vector.front().second.name_id); } } return 200; diff --git a/plugins/trip.hpp b/plugins/trip.hpp index 3500b3f07..13e53fe83 100644 --- a/plugins/trip.hpp +++ b/plugins/trip.hpp @@ -73,7 +73,7 @@ template class RoundTripPlugin final : public BasePlugin const std::string GetDescriptor() const override final { return descriptor_string; } void GetPhantomNodes(const RouteParameters &route_parameters, - PhantomNodeArray &phantom_node_vector) + std::vector &phantom_node_pair_list) { const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); const auto &input_bearings = route_parameters.bearings; @@ -89,19 +89,16 @@ template class RoundTripPlugin final : public BasePlugin ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node); if (current_phantom_node.is_valid(facade->GetNumberOfNodes())) { - phantom_node_vector[i].emplace_back(std::move(current_phantom_node)); + phantom_node_pair_list[i] = std::make_pair(current_phantom_node, current_phantom_node); continue; } } const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180; - facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], - phantom_node_vector[i], 1, bearing, range); - if (phantom_node_vector[i].size() > 1) - { - phantom_node_vector[i].erase(std::begin(phantom_node_vector[i])); - } - BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); + auto phantom_nodes = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range); + // FIXME we only use the pair because that is what DistanceTable expects + phantom_node_pair_list[i] = std::make_pair(phantom_nodes.front().second, phantom_nodes.front().second); + BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())); } } @@ -206,7 +203,7 @@ template class RoundTripPlugin final : public BasePlugin json_result.values["permutation"] = json_permutation; } - InternalRouteResult ComputeRoute(const PhantomNodeArray &phantom_node_vector, + InternalRouteResult ComputeRoute(const std::vector &phantom_node_pair_list, const RouteParameters &route_parameters, const std::vector &trip) { @@ -223,7 +220,7 @@ template class RoundTripPlugin final : public BasePlugin const auto to_node = std::next(it) != end ? *std::next(it) : *start; viapoint = - PhantomNodes{phantom_node_vector[from_node][0], phantom_node_vector[to_node][0]}; + PhantomNodes{phantom_node_pair_list[from_node].first, phantom_node_pair_list[to_node].first}; min_route.segment_end_coordinates.emplace_back(viapoint); } BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size()); @@ -257,13 +254,13 @@ template class RoundTripPlugin final : public BasePlugin } // get phantom nodes - PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size()); - GetPhantomNodes(route_parameters, phantom_node_vector); - const auto number_of_locations = phantom_node_vector.size(); + std::vector phantom_node_pair_list(route_parameters.coordinates.size()); + GetPhantomNodes(route_parameters, phantom_node_pair_list); + const auto number_of_locations = phantom_node_pair_list.size(); // compute the distance table of all phantom nodes const auto result_table = DistTableWrapper( - *search_engine_ptr->distance_table(phantom_node_vector, phantom_node_vector), number_of_locations); + *search_engine_ptr->distance_table(phantom_node_pair_list, phantom_node_pair_list), number_of_locations); if (result_table.size() == 0) { @@ -331,7 +328,7 @@ template class RoundTripPlugin final : public BasePlugin comp_route.reserve(route_result.size()); for (auto &elem : route_result) { - comp_route.push_back(ComputeRoute(phantom_node_vector, route_parameters, elem)); + comp_route.push_back(ComputeRoute(phantom_node_pair_list, route_parameters, elem)); } TIMER_STOP(TRIP_TIMER); @@ -360,8 +357,6 @@ template class RoundTripPlugin final : public BasePlugin json_result.values["trips"] = std::move(trip); - - return 200; } }; diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp index 40b7ef63f..430424140 100644 --- a/plugins/viaroute.hpp +++ b/plugins/viaroute.hpp @@ -87,7 +87,7 @@ template class ViaRoutePlugin final : public BasePlugin return 400; } - std::vector phantom_node_pair_list(route_parameters.coordinates.size()); + std::vector phantom_node_pair_list(route_parameters.coordinates.size()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); for (const auto i : osrm::irange(0, route_parameters.coordinates.size())) @@ -96,34 +96,26 @@ template class ViaRoutePlugin final : public BasePlugin !route_parameters.hints[i].empty()) { ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], - phantom_node_pair_list[i]); + phantom_node_pair_list[i].first); if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) { continue; } } - std::vector phantom_node_vector; const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180; - if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], - phantom_node_vector, 1, bearing, range)) - { - BOOST_ASSERT(!phantom_node_vector.empty()); - phantom_node_pair_list[i].first = phantom_node_vector.front(); - if (phantom_node_vector.size() > 1) - { - phantom_node_pair_list[i].second = phantom_node_vector.back(); - } - - } - else + phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(route_parameters.coordinates[i], bearing, range); + // we didn't found a fitting node, return error + if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) { json_result.values["status_message"] = std::string("Could not find a matching segment for coordinate ") + std::to_string(i); return 400; } + BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())); + BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes())); } - const auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair) + const auto check_component_id_is_tiny = [](const PhantomNodePair &phantom_pair) { return phantom_pair.first.component.is_tiny; }; @@ -133,18 +125,18 @@ template class ViaRoutePlugin final : public BasePlugin check_component_id_is_tiny); // are all phantoms from a tiny cc? - const auto check_all_in_same_component = [](const std::vector &nodes) + const auto check_all_in_same_component = [](const std::vector &nodes) { const auto component_id = nodes.front().first.component.id; return std::all_of(std::begin(nodes), std::end(nodes), - [component_id](const phantom_node_pair &phantom_pair) + [component_id](const PhantomNodePair &phantom_pair) { return component_id == phantom_pair.first.component.id; }); }; - auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair) + auto swap_phantom_from_big_cc_into_front = [](PhantomNodePair &phantom_pair) { if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() && !phantom_pair.second.component.is_tiny) { @@ -167,7 +159,7 @@ template class ViaRoutePlugin final : public BasePlugin InternalRouteResult raw_route; auto build_phantom_pairs = - [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair) + [&raw_route](const PhantomNodePair &first_pair, const PhantomNodePair &second_pair) { raw_route.segment_end_coordinates.emplace_back( PhantomNodes{first_pair.first, second_pair.first}); diff --git a/routing_algorithms/many_to_many.hpp b/routing_algorithms/many_to_many.hpp index 343aafe76..192e140e1 100644 --- a/routing_algorithms/many_to_many.hpp +++ b/routing_algorithms/many_to_many.hpp @@ -67,7 +67,7 @@ class ManyToManyRouting final ~ManyToManyRouting() {} std::shared_ptr> - operator()(const PhantomNodeArray &phantom_sources_array, const PhantomNodeArray &phantom_targets_array) const + operator()(const std::vector &phantom_sources_array, const std::vector &phantom_targets_array) const { const auto number_of_sources = phantom_sources_array.size(); const auto number_of_targets = phantom_targets_array.size(); @@ -83,25 +83,35 @@ class ManyToManyRouting final SearchSpaceWithBuckets search_space_with_buckets; unsigned target_id = 0; - for (const std::vector &phantom_node_vector : phantom_targets_array) + for (const auto &pair : phantom_targets_array) { query_heap.Clear(); // insert target(s) at distance 0 - for (const PhantomNode &phantom_node : phantom_node_vector) + if (SPECIAL_NODEID != pair.first.forward_node_id) { - if (SPECIAL_NODEID != phantom_node.forward_node_id) - { - query_heap.Insert(phantom_node.forward_node_id, - phantom_node.GetForwardWeightPlusOffset(), - phantom_node.forward_node_id); - } - if (SPECIAL_NODEID != phantom_node.reverse_node_id) - { - query_heap.Insert(phantom_node.reverse_node_id, - phantom_node.GetReverseWeightPlusOffset(), - phantom_node.reverse_node_id); - } + query_heap.Insert(pair.first.forward_node_id, + pair.first.GetForwardWeightPlusOffset(), + pair.first.forward_node_id); + } + if (SPECIAL_NODEID != pair.first.reverse_node_id) + { + query_heap.Insert(pair.first.reverse_node_id, + pair.first.GetReverseWeightPlusOffset(), + pair.first.reverse_node_id); + } + + if (SPECIAL_NODEID != pair.second.forward_node_id) + { + query_heap.Insert(pair.second.forward_node_id, + pair.second.GetForwardWeightPlusOffset(), + pair.second.forward_node_id); + } + if (SPECIAL_NODEID != pair.second.reverse_node_id) + { + query_heap.Insert(pair.second.reverse_node_id, + pair.second.GetReverseWeightPlusOffset(), + pair.second.reverse_node_id); } // explore search space @@ -114,24 +124,35 @@ class ManyToManyRouting final // for each source do forward search unsigned source_id = 0; - for (const std::vector &phantom_node_vector : phantom_sources_array) + for (const auto &pair : phantom_sources_array) { query_heap.Clear(); - for (const PhantomNode &phantom_node : phantom_node_vector) + // insert target(s) at distance 0 + + if (SPECIAL_NODEID != pair.first.forward_node_id) { - // insert sources at distance 0 - if (SPECIAL_NODEID != phantom_node.forward_node_id) - { - query_heap.Insert(phantom_node.forward_node_id, - -phantom_node.GetForwardWeightPlusOffset(), - phantom_node.forward_node_id); - } - if (SPECIAL_NODEID != phantom_node.reverse_node_id) - { - query_heap.Insert(phantom_node.reverse_node_id, - -phantom_node.GetReverseWeightPlusOffset(), - phantom_node.reverse_node_id); - } + query_heap.Insert(pair.first.forward_node_id, + -pair.first.GetForwardWeightPlusOffset(), + pair.first.forward_node_id); + } + if (SPECIAL_NODEID != pair.first.reverse_node_id) + { + query_heap.Insert(pair.first.reverse_node_id, + -pair.first.GetReverseWeightPlusOffset(), + pair.first.reverse_node_id); + } + + if (SPECIAL_NODEID != pair.second.forward_node_id) + { + query_heap.Insert(pair.second.forward_node_id, + -pair.second.GetForwardWeightPlusOffset(), + pair.second.forward_node_id); + } + if (SPECIAL_NODEID != pair.second.reverse_node_id) + { + query_heap.Insert(pair.second.reverse_node_id, + -pair.second.GetReverseWeightPlusOffset(), + pair.second.reverse_node_id); } // explore search space diff --git a/routing_algorithms/map_matching.hpp b/routing_algorithms/map_matching.hpp index bc36947d4..02d9279b9 100644 --- a/routing_algorithms/map_matching.hpp +++ b/routing_algorithms/map_matching.hpp @@ -57,7 +57,7 @@ struct SubMatching double confidence; }; -using CandidateList = std::vector>; +using CandidateList = std::vector>; using CandidateLists = std::vector; using HMM = HiddenMarkovModel; using SubMatchingList = std::vector; @@ -232,7 +232,7 @@ class MapMatching final : public BasicRoutingInterface new_value) { @@ -244,8 +244,8 @@ class MapMatching final : public BasicRoutingInterface #include +#include using EdgeRange = osrm::range; @@ -92,23 +93,22 @@ template class BaseDataFacade virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0; - virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate, - FixedPointCoordinate &result, - const unsigned zoom_level = 18) = 0; + virtual std::vector> + NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate, + const float max_distance, + const int bearing = 0, + const int bearing_range = 180) = 0; - virtual bool - IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - std::vector &resulting_phantom_node_vector, - const unsigned number_of_results, - const int bearing = 0, const int bearing_range = 180) = 0; + virtual std::vector> + NearestPhantomNodes(const FixedPointCoordinate &input_coordinate, + const unsigned max_results, + const int bearing = 0, + const int bearing_range = 180) = 0; - virtual bool - IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - PhantomNode &resulting_phantom_node) = 0; - virtual bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( - const FixedPointCoordinate &input_coordinate, - std::vector> &resulting_phantom_node_vector, - const double max_distance, const int bearing = 0, const int bearing_range = 180) = 0; + virtual std::pair + NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate, + const int bearing = 0, + const int bearing_range = 180) = 0; virtual unsigned GetCheckSum() const = 0; diff --git a/server/data_structures/internal_datafacade.hpp b/server/data_structures/internal_datafacade.hpp index b8c8e97e6..9bdb5f2d2 100644 --- a/server/data_structures/internal_datafacade.hpp +++ b/server/data_structures/internal_datafacade.hpp @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "datafacade_base.hpp" +#include "../../algorithms/geospatial_query.hpp" #include "../../data_structures/original_edge_data.hpp" #include "../../data_structures/query_node.hpp" #include "../../data_structures/query_edge.hpp" @@ -45,6 +46,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + #include template class InternalDataFacade final : public BaseDataFacade @@ -55,12 +58,14 @@ template class InternalDataFacade final : public BaseDataFacad using QueryGraph = StaticGraph; using InputEdge = typename QueryGraph::InputEdge; using RTreeLeaf = typename super::RTreeLeaf; + using InternalRTree = StaticRTree::vector, false>; + using InternalGeospatialQuery = GeospatialQuery; InternalDataFacade() {} unsigned m_check_sum; unsigned m_number_of_nodes; - QueryGraph *m_query_graph; + std::unique_ptr m_query_graph; std::string m_timestamp; std::shared_ptr::vector> m_coordinate_list; @@ -74,8 +79,8 @@ template class InternalDataFacade final : public BaseDataFacad ShM::vector m_geometry_list; ShM::vector m_is_core_node; - boost::thread_specific_ptr< - StaticRTree::vector, false>> m_static_rtree; + boost::thread_specific_ptr m_static_rtree; + boost::thread_specific_ptr m_geospatial_query; boost::filesystem::path ram_index_path; boost::filesystem::path file_index_path; RangeTable<16, false> m_name_table; @@ -116,7 +121,7 @@ template class InternalDataFacade final : public BaseDataFacad // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty"); SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size() << " edges"; - m_query_graph = new QueryGraph(node_list, edge_list); + m_query_graph = std::unique_ptr(new QueryGraph(node_list, edge_list)); BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed"); BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed"); @@ -226,8 +231,8 @@ template class InternalDataFacade final : public BaseDataFacad { BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree"); - m_static_rtree.reset( - new StaticRTree(ram_index_path, file_index_path, m_coordinate_list)); + m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list)); + m_geospatial_query.reset(new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list)); } void LoadStreetNames(const boost::filesystem::path &names_file) @@ -251,8 +256,8 @@ template class InternalDataFacade final : public BaseDataFacad public: virtual ~InternalDataFacade() { - delete m_query_graph; m_static_rtree.reset(); + m_geospatial_query.reset(); } explicit InternalDataFacade(const ServerPaths &server_paths) @@ -283,9 +288,6 @@ template class InternalDataFacade final : public BaseDataFacad SimpleLogger().Write() << "loading geometries"; LoadGeometries(file_for("geometries")); - SimpleLogger().Write() << "loading r-tree"; - // XXX(daniel-j-h): it says this ^ but doesn't load the rtree here - SimpleLogger().Write() << "loading timestamp"; LoadTimestamp(file_for("timestamp")); @@ -357,65 +359,52 @@ template class InternalDataFacade final : public BaseDataFacad return m_travel_mode_list.at(id); } - bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate, - FixedPointCoordinate &result, - const unsigned zoom_level = 18) override final + + std::vector> + NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate, + const float max_distance, + const int bearing = 0, + const int bearing_range = 180) override final { if (!m_static_rtree.get()) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->LocateClosestEndPointForCoordinate(input_coordinate, result, - zoom_level); + return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range); } - bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - PhantomNode &resulting_phantom_node) override final - { - std::vector resulting_phantom_node_vector; - auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate, - resulting_phantom_node_vector, 1); - if (result) - { - BOOST_ASSERT(!resulting_phantom_node_vector.empty()); - resulting_phantom_node = resulting_phantom_node_vector.front(); - } - - return result; - } - - bool - IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - std::vector &resulting_phantom_node_vector, - const unsigned number_of_results, - const int bearing = 0, const int range = 180) override final + std::vector> + NearestPhantomNodes(const FixedPointCoordinate &input_coordinate, + const unsigned max_results, + const int bearing = 0, + const int bearing_range = 180) override final { if (!m_static_rtree.get()) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->IncrementalFindPhantomNodeForCoordinate( - input_coordinate, resulting_phantom_node_vector, number_of_results, bearing, range); + return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range); } - bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( - const FixedPointCoordinate &input_coordinate, - std::vector> &resulting_phantom_node_vector, - const double max_distance, - const int bearing = 0, - const int bearing_range = 180) override final + std::pair + NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate, + const int bearing = 0, + const int bearing_range = 180) { if (!m_static_rtree.get()) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->IncrementalFindPhantomNodeForCoordinateWithDistance( - input_coordinate, resulting_phantom_node_vector, max_distance, bearing, bearing_range); + return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range); } + unsigned GetCheckSum() const override final { return m_check_sum; } unsigned GetNameIndexFromEdgeID(const unsigned id) const override final diff --git a/server/data_structures/shared_datafacade.hpp b/server/data_structures/shared_datafacade.hpp index f3e02fc3f..b7ac21a66 100644 --- a/server/data_structures/shared_datafacade.hpp +++ b/server/data_structures/shared_datafacade.hpp @@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "datafacade_base.hpp" #include "shared_datatype.hpp" +#include "../../algorithms/geospatial_query.hpp" #include "../../data_structures/range_table.hpp" #include "../../data_structures/static_graph.hpp" #include "../../data_structures/static_rtree.hpp" @@ -56,6 +57,7 @@ template class SharedDataFacade final : public BaseDataFacade< using InputEdge = typename QueryGraph::InputEdge; using RTreeLeaf = typename super::RTreeLeaf; using SharedRTree = StaticRTree::vector, true>; + using SharedGeospatialQuery = GeospatialQuery; using TimeStampedRTreePair = std::pair>; using RTreeNode = typename SharedRTree::TreeNode; @@ -86,6 +88,7 @@ template class SharedDataFacade final : public BaseDataFacade< ShM::vector m_is_core_node; boost::thread_specific_ptr>> m_static_rtree; + boost::thread_specific_ptr m_geospatial_query; boost::filesystem::path file_index_path; std::shared_ptr> m_name_table; @@ -118,6 +121,7 @@ template class SharedDataFacade final : public BaseDataFacade< osrm::make_unique( tree_ptr, data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE], file_index_path, m_coordinate_list))); + m_geospatial_query.reset(new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list)); } void LoadGraph() @@ -378,63 +382,48 @@ template class SharedDataFacade final : public BaseDataFacade< return m_travel_mode_list.at(id); } - bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate, - FixedPointCoordinate &result, - const unsigned zoom_level = 18) override final + std::vector> + NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate, + const float max_distance, + const int bearing = 0, + const int bearing_range = 180) override final { if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->second->LocateClosestEndPointForCoordinate(input_coordinate, result, - zoom_level); + return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range); } - bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - PhantomNode &resulting_phantom_node) override final - { - std::vector resulting_phantom_node_vector; - auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate, - resulting_phantom_node_vector, 1); - if (result) - { - BOOST_ASSERT(!resulting_phantom_node_vector.empty()); - resulting_phantom_node = resulting_phantom_node_vector.front(); - } - - return result; - } - - bool - IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - std::vector &resulting_phantom_node_vector, - const unsigned number_of_results, - const int bearing = 0, const int range = 180) override final + std::vector> + NearestPhantomNodes(const FixedPointCoordinate &input_coordinate, + const unsigned max_results, + const int bearing = 0, + const int bearing_range = 180) override final { if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinate( - input_coordinate, resulting_phantom_node_vector, number_of_results, bearing, range); + return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range); } - bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance( - const FixedPointCoordinate &input_coordinate, - std::vector> &resulting_phantom_node_vector, - const double max_distance, - const int bearing = 0, - const int bearing_range = 180) override final + std::pair + NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate, + const int bearing = 0, + const int bearing_range = 180) { if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) { LoadRTree(); + BOOST_ASSERT(m_geospatial_query.get()); } - return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinateWithDistance( - input_coordinate, resulting_phantom_node_vector, max_distance, bearing, bearing_range); + return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range); } unsigned GetCheckSum() const override final { return m_check_sum; } diff --git a/unit_tests/data_structures/static_rtree.cpp b/unit_tests/data_structures/static_rtree.cpp index 62295407d..373824a5f 100644 --- a/unit_tests/data_structures/static_rtree.cpp +++ b/unit_tests/data_structures/static_rtree.cpp @@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../../algorithms/coordinate_calculation.hpp" +#include "../../algorithms/geospatial_query.hpp" #include "../../data_structures/static_rtree.hpp" #include "../../data_structures/query_node.hpp" #include "../../data_structures/edge_based_node.hpp" @@ -55,11 +56,12 @@ constexpr uint32_t TEST_BRANCHING_FACTOR = 8; constexpr uint32_t TEST_LEAF_NODE_SIZE = 64; typedef EdgeBasedNode TestData; -typedef StaticRTree, - false, - TEST_BRANCHING_FACTOR, - TEST_LEAF_NODE_SIZE> TestStaticRTree; +using TestStaticRTree = StaticRTree, + false, + TEST_BRANCHING_FACTOR, + TEST_LEAF_NODE_SIZE>; +using MiniStaticRTree = StaticRTree, false, 2, 3>; // Choosen by a fair W20 dice roll (this value is completely arbitrary) constexpr unsigned RANDOM_SEED = 42; @@ -68,113 +70,35 @@ static const int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION; static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION; static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION; -class LinearSearchNN +template class LinearSearchNN { public: LinearSearchNN(const std::shared_ptr> &coords, - const std::vector &edges) + const std::vector &edges) : coords(coords), edges(edges) { } - bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate, - FixedPointCoordinate &result_coordinate) + std::vector Nearest(const FixedPointCoordinate &input_coordinate, + const unsigned num_results) { - float min_dist = std::numeric_limits::max(); - FixedPointCoordinate min_coord; - for (const TestData &e : edges) - { - const FixedPointCoordinate &start = coords->at(e.u); - const FixedPointCoordinate &end = coords->at(e.v); - float distance = coordinate_calculation::great_circle_distance( - input_coordinate.lat, input_coordinate.lon, start.lat, start.lon); - if (distance < min_dist) + std::vector local_edges(edges); + + std::nth_element( + local_edges.begin(), local_edges.begin() + num_results, local_edges.end(), + [this, &input_coordinate](const DataT &lhs, const DataT &rhs) { - min_coord = start; - min_dist = distance; - } + float current_ratio = 0.; + FixedPointCoordinate nearest; + const float lhs_dist = coordinate_calculation::perpendicular_distance( + coords->at(lhs.u), coords->at(lhs.v), input_coordinate, nearest, current_ratio); + const float rhs_dist = coordinate_calculation::perpendicular_distance( + coords->at(rhs.u), coords->at(rhs.v), input_coordinate, nearest, current_ratio); + return lhs_dist < rhs_dist; + }); + local_edges.resize(num_results); - distance = coordinate_calculation::great_circle_distance( - input_coordinate.lat, input_coordinate.lon, end.lat, end.lon); - if (distance < min_dist) - { - min_coord = end; - min_dist = distance; - } - } - - result_coordinate = min_coord; - return result_coordinate.is_valid(); - } - - bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate, - PhantomNode &result_phantom_node, - const unsigned) - { - float min_dist = std::numeric_limits::max(); - TestData nearest_edge; - for (const TestData &e : edges) - { - if (e.component.is_tiny) - continue; - - float current_ratio = 0.; - FixedPointCoordinate nearest; - const float current_perpendicular_distance = - coordinate_calculation::perpendicular_distance( - coords->at(e.u), coords->at(e.v), input_coordinate, nearest, current_ratio); - - if ((current_perpendicular_distance < min_dist) && - !osrm::epsilon_compare(current_perpendicular_distance, min_dist)) - { // found a new minimum - min_dist = current_perpendicular_distance; - result_phantom_node = {e.forward_edge_based_node_id, - e.reverse_edge_based_node_id, - e.name_id, - e.forward_weight, - e.reverse_weight, - e.forward_offset, - e.reverse_offset, - e.packed_geometry_id, - e.component.is_tiny, - e.component.id, - nearest, - e.fwd_segment_position, - e.forward_travel_mode, - e.backward_travel_mode}; - nearest_edge = e; - } - } - - if (result_phantom_node.location.is_valid()) - { - // Hack to fix rounding errors and wandering via nodes. - if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon)) - { - result_phantom_node.location.lon = input_coordinate.lon; - } - if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat)) - { - result_phantom_node.location.lat = input_coordinate.lat; - } - - const float distance_1 = coordinate_calculation::great_circle_distance( - coords->at(nearest_edge.u), result_phantom_node.location); - const float distance_2 = coordinate_calculation::great_circle_distance( - coords->at(nearest_edge.u), coords->at(nearest_edge.v)); - const float ratio = std::min(1.f, distance_1 / distance_2); - - if (SPECIAL_NODEID != result_phantom_node.forward_node_id) - { - result_phantom_node.forward_weight *= ratio; - } - if (SPECIAL_NODEID != result_phantom_node.reverse_node_id) - { - result_phantom_node.reverse_weight *= (1. - ratio); - } - } - - return result_phantom_node.location.is_valid(); + return local_edges; } private: @@ -295,23 +219,18 @@ void simple_verify_rtree(RTreeT &rtree, BOOST_TEST_MESSAGE("Verify end points"); for (const auto &e : edges) { - FixedPointCoordinate result_u, result_v; const FixedPointCoordinate &pu = coords->at(e.u); const FixedPointCoordinate &pv = coords->at(e.v); - bool found_u = rtree.LocateClosestEndPointForCoordinate(pu, result_u, 1); - bool found_v = rtree.LocateClosestEndPointForCoordinate(pv, result_v, 1); - BOOST_CHECK(found_u && found_v); - float dist_u = - coordinate_calculation::great_circle_distance(result_u.lat, result_u.lon, pu.lat, pu.lon); - BOOST_CHECK_LE(dist_u, std::numeric_limits::epsilon()); - float dist_v = - coordinate_calculation::great_circle_distance(result_v.lat, result_v.lon, pv.lat, pv.lon); - BOOST_CHECK_LE(dist_v, std::numeric_limits::epsilon()); + auto result_u = rtree.Nearest(pu, 1); + auto result_v = rtree.Nearest(pv, 1); + BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1); + BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u); + BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v); } } template -void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_samples) +void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, const std::vector& coords, unsigned num_samples) { std::mt19937 g(RANDOM_SEED); std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT); @@ -325,17 +244,22 @@ void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_sam BOOST_TEST_MESSAGE("Sampling queries"); for (const auto &q : queries) { - FixedPointCoordinate result_rtree; - rtree.LocateClosestEndPointForCoordinate(q, result_rtree, 1); - FixedPointCoordinate result_ln; - lsnn.LocateClosestEndPointForCoordinate(q, result_ln); - BOOST_CHECK_EQUAL(result_ln, result_rtree); + auto result_rtree = rtree.Nearest(q, 1); + auto result_lsnn = lsnn.Nearest(q, 1); + BOOST_CHECK(result_rtree.size() == 1); + BOOST_CHECK(result_lsnn.size() == 1); + auto rtree_u = result_rtree.back().u; + auto rtree_v = result_rtree.back().v; + auto lsnn_u = result_lsnn.back().u; + auto lsnn_v = result_lsnn.back().v; - PhantomNode phantom_rtree; - rtree.FindPhantomNodeForCoordinate(q, phantom_rtree, 1); - PhantomNode phantom_ln; - lsnn.FindPhantomNodeForCoordinate(q, phantom_ln, 1); - BOOST_CHECK_EQUAL(phantom_rtree, phantom_ln); + float current_ratio = 0.; + FixedPointCoordinate nearest; + const float rtree_dist = coordinate_calculation::perpendicular_distance( + coords[rtree_u], coords[rtree_v], q, nearest, current_ratio); + const float lsnn_dist = coordinate_calculation::perpendicular_distance( + coords[lsnn_u], coords[lsnn_v], q, nearest, current_ratio); + BOOST_CHECK_LE(std::abs(rtree_dist - lsnn_dist), std::numeric_limits::epsilon()); } } @@ -365,10 +289,10 @@ void construction_test(const std::string &prefix, FixtureT *fixture) std::string nodes_path; build_rtree(prefix, fixture, leaves_path, nodes_path); RTreeT rtree(nodes_path, leaves_path, fixture->coords); - LinearSearchNN lsnn(fixture->coords, fixture->edges); + LinearSearchNN lsnn(fixture->coords, fixture->edges); simple_verify_rtree(rtree, fixture->coords, fixture->edges); - sampling_verify_rtree(rtree, lsnn, 100); + sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100); } BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull) @@ -396,51 +320,43 @@ BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_M construction_test("test_5", this); } -/* - * Bug: If you querry a point that lies between two BBs that have a gap, - * one BB will be pruned, even if it could contain a nearer match. - */ +// Bug: If you querry a point that lies between two BBs that have a gap, +// one BB will be pruned, even if it could contain a nearer match. BOOST_AUTO_TEST_CASE(regression_test) { - typedef std::pair Coord; - typedef std::pair Edge; + using Coord = std::pair; + using Edge = std::pair; GraphFixture fixture( { - Coord(40.0, 0.0), - Coord(35.0, 5.0), + Coord(40.0, 0.0), Coord(35.0, 5.0), - Coord(5.0, 5.0), - Coord(0.0, 10.0), + Coord(5.0, 5.0), Coord(0.0, 10.0), - Coord(20.0, 10.0), - Coord(20.0, 5.0), + Coord(20.0, 10.0), Coord(20.0, 5.0), - Coord(40.0, 100.0), - Coord(35.0, 105.0), + Coord(40.0, 100.0), Coord(35.0, 105.0), - Coord(5.0, 105.0), - Coord(0.0, 110.0), + Coord(5.0, 105.0), Coord(0.0, 110.0), }, {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)}); - typedef StaticRTree, false, 2, 3> MiniStaticRTree; - std::string leaves_path; std::string nodes_path; build_rtree("test_regression", &fixture, leaves_path, nodes_path); MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords); + LinearSearchNN lsnn(fixture.coords, fixture.edges); // query a node just right of the center of the gap FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION); - FixedPointCoordinate result; - rtree.LocateClosestEndPointForCoordinate(input, result, 1); - FixedPointCoordinate result_ln; - LinearSearchNN lsnn(fixture.coords, fixture.edges); - lsnn.LocateClosestEndPointForCoordinate(input, result_ln); + auto result_rtree = rtree.Nearest(input, 1); + auto result_ls = lsnn.Nearest(input, 1); - // TODO: reactivate - // BOOST_CHECK_EQUAL(result_ln, result); + BOOST_CHECK(result_rtree.size() == 1); + BOOST_CHECK(result_ls.size() == 1); + + BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u); + BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v); } void TestRectangle(double width, double height, double center_lat, double center_lon) @@ -448,7 +364,7 @@ void TestRectangle(double width, double height, double center_lat, double center FixedPointCoordinate center(center_lat * COORDINATE_PRECISION, center_lon * COORDINATE_PRECISION); - TestStaticRTree::RectangleT rect; + TestStaticRTree::Rectangle rect; rect.min_lat = center.lat - height / 2.0 * COORDINATE_PRECISION; rect.max_lat = center.lat + height / 2.0 * COORDINATE_PRECISION; rect.min_lon = center.lon - width / 2.0 * COORDINATE_PRECISION; @@ -502,100 +418,63 @@ BOOST_AUTO_TEST_CASE(rectangle_test) TestRectangle(10, 10, 0, 0); } -/* Verify that the bearing-bounds checking function behaves as expected */ -BOOST_AUTO_TEST_CASE(bearing_range_test) -{ - // Simple, non-edge-case checks - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(45, 45, 10)); - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(35, 45, 10)); - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(55, 45, 10)); - - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(34, 45, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(56, 45, 10)); - - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(34, 45, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(56, 45, 10)); - - // When angle+limit goes > 360 - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, 355, 10)); - - // When angle-limit goes < 0 - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, 5, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(354, 5, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(16, 5, 10)); - - - // Checking other cases of wraparound - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, -5, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(344, -5, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(6, -5, 10)); - - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(-1, 5, 10)); - BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(-6, 5, 10)); - - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(-721, 5, 10)); - BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(719, 5, 10)); - -} - BOOST_AUTO_TEST_CASE(bearing_tests) { - - typedef std::pair Coord; - typedef std::pair Edge; + using Coord = std::pair; + using Edge = std::pair; GraphFixture fixture( { - Coord(0.0, 0.0), - Coord(10.0, 10.0), + Coord(0.0, 0.0), Coord(10.0, 10.0), }, - {Edge(0, 1), Edge(1,0)}); - - typedef StaticRTree, false, 2, 3> MiniStaticRTree; + {Edge(0, 1), Edge(1, 0)}); std::string leaves_path; std::string nodes_path; build_rtree("test_bearing", &fixture, leaves_path, nodes_path); MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords); + GeospatialQuery query(rtree, fixture.coords); FixedPointCoordinate input(5.0 * COORDINATE_PRECISION, 5.1 * COORDINATE_PRECISION); - std::vector results; - rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5); - BOOST_CHECK_EQUAL(results.size(), 2); - BOOST_CHECK_EQUAL(results.back().forward_node_id, 0); - BOOST_CHECK_EQUAL(results.back().reverse_node_id, 1); + { + auto results = query.NearestPhantomNodes(input, 5); + BOOST_CHECK_EQUAL(results.size(), 2); + BOOST_CHECK_EQUAL(results.back().second.forward_node_id, 0); + BOOST_CHECK_EQUAL(results.back().second.reverse_node_id, 1); + } - results.clear(); - rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5, 270, 10); - BOOST_CHECK_EQUAL(results.size(), 0); + { + auto results = query.NearestPhantomNodes(input, 5, 270, 10); + BOOST_CHECK_EQUAL(results.size(), 0); + } - results.clear(); - rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5, 45, 10); - BOOST_CHECK_EQUAL(results.size(), 2); - BOOST_CHECK_EQUAL(results[0].forward_node_id, 1); - BOOST_CHECK_EQUAL(results[0].reverse_node_id, SPECIAL_NODEID); - BOOST_CHECK_EQUAL(results[1].forward_node_id, SPECIAL_NODEID); - BOOST_CHECK_EQUAL(results[1].reverse_node_id, 1); + { + auto results = query.NearestPhantomNodes(input, 5, 45, 10); + BOOST_CHECK_EQUAL(results.size(), 2); + BOOST_CHECK_EQUAL(results[0].second.forward_node_id, 1); + BOOST_CHECK_EQUAL(results[0].second.reverse_node_id, SPECIAL_NODEID); + BOOST_CHECK_EQUAL(results[1].second.forward_node_id, SPECIAL_NODEID); + BOOST_CHECK_EQUAL(results[1].second.reverse_node_id, 1); + } + { + auto results = query.NearestPhantomNodesInRange(input, 11000); + BOOST_CHECK_EQUAL(results.size(), 2); + } - std::vector> distance_results; - rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000 ); - BOOST_CHECK_EQUAL(distance_results.size(), 2); - - distance_results.clear(); - rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000, 270, 10 ); - BOOST_CHECK_EQUAL(distance_results.size(), 0); - - distance_results.clear(); - rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000, 45, 10 ); - BOOST_CHECK_EQUAL(distance_results.size(), 2); - BOOST_CHECK_EQUAL(distance_results[0].first.forward_node_id, 1); - BOOST_CHECK_EQUAL(distance_results[0].first.reverse_node_id, SPECIAL_NODEID); - BOOST_CHECK_EQUAL(distance_results[1].first.forward_node_id, SPECIAL_NODEID); - BOOST_CHECK_EQUAL(distance_results[1].first.reverse_node_id, 1); + { + auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10); + BOOST_CHECK_EQUAL(results.size(), 0); + } + { + auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10); + BOOST_CHECK_EQUAL(results.size(), 2); + BOOST_CHECK_EQUAL(results[0].second.forward_node_id, 1); + BOOST_CHECK_EQUAL(results[0].second.reverse_node_id, SPECIAL_NODEID); + BOOST_CHECK_EQUAL(results[1].second.forward_node_id, SPECIAL_NODEID); + BOOST_CHECK_EQUAL(results[1].second.reverse_node_id, 1); + } } - - BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/util/bearing.cpp b/unit_tests/util/bearing.cpp new file mode 100644 index 000000000..f0866de33 --- /dev/null +++ b/unit_tests/util/bearing.cpp @@ -0,0 +1,72 @@ +/* + +Copyright (c) 2015, Project OSRM contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "../../util/bearing.hpp" +#include "../../typedefs.h" + +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(bearing) + +// Verify that the bearing-bounds checking function behaves as expected +BOOST_AUTO_TEST_CASE(bearing_range_test) +{ + // Simple, non-edge-case checks + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(45, 45, 10)); + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(35, 45, 10)); + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(55, 45, 10)); + + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(34, 45, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(56, 45, 10)); + + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(34, 45, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(56, 45, 10)); + + // When angle+limit goes > 360 + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, 355, 10)); + + // When angle-limit goes < 0 + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, 5, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(354, 5, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(16, 5, 10)); + + + // Checking other cases of wraparound + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, -5, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(344, -5, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(6, -5, 10)); + + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(-1, 5, 10)); + BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(-6, 5, 10)); + + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(-721, 5, 10)); + BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(719, 5, 10)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/util_tests.cpp b/unit_tests/util_tests.cpp new file mode 100644 index 000000000..26275ab6b --- /dev/null +++ b/unit_tests/util_tests.cpp @@ -0,0 +1,34 @@ +/* + +Copyright (c) 2014, Project OSRM contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#define BOOST_TEST_MODULE util tests + +#include + +/* + * This file will contain an automatically generated main function. + */ diff --git a/util/bearing.hpp b/util/bearing.hpp index 2b05972f3..5f3036a85 100644 --- a/util/bearing.hpp +++ b/util/bearing.hpp @@ -72,6 +72,45 @@ inline std::string get(const double heading) } return "N"; } + +// Checks whether A is between B-range and B+range, all modulo 360 +// e.g. A = 5, B = 5, range = 10 == true +// A = -6, B = 5, range = 10 == false +// A = -2, B = 355, range = 10 == true +// A = 6, B = 355, range = 10 == false +// A = 355, B = -2, range = 10 == true +// +// @param A the bearing to check, in degrees, 0-359, 0=north +// @param B the bearing to check against, in degrees, 0-359, 0=north +// @param range the number of degrees either side of B that A will still match +// @return true if B-range <= A <= B+range, modulo 360 +inline bool CheckInBounds(const int A, const int B, const int range) +{ + + if (range >= 180) + return true; + if (range <= 0) + return false; + + // Map both bearings into positive modulo 360 space + const int normalized_B = (B < 0) ? (B % 360) + 360 : (B % 360); + const int normalized_A = (A < 0) ? (A % 360) + 360 : (A % 360); + + if (normalized_B - range < 0) + { + return (normalized_B - range + 360 <= normalized_A && normalized_A < 360) || + (0 <= normalized_A && normalized_A <= normalized_B + range); + } + else if (normalized_B + range > 360) + { + return (normalized_B - range <= normalized_A && normalized_A < 360) || + (0 <= normalized_A && normalized_A <= normalized_B + range - 360); + } + else + { + return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range; + } +} } #endif // BEARING_HPP diff --git a/util/matching_debug_info.hpp b/util/matching_debug_info.hpp index aad47b209..da8ca819e 100644 --- a/util/matching_debug_info.hpp +++ b/util/matching_debug_info.hpp @@ -62,8 +62,8 @@ struct MatchingDebugInfo osrm::json::Object state; state.values["transitions"] = osrm::json::Array(); state.values["coordinate"] = - osrm::json::make_array(elem_s.first.location.lat / COORDINATE_PRECISION, - elem_s.first.location.lon / COORDINATE_PRECISION); + osrm::json::make_array(elem_s.second.location.lat / COORDINATE_PRECISION, + elem_s.second.location.lon / COORDINATE_PRECISION); state.values["viterbi"] = osrm::json::clamp_float(osrm::matching::IMPOSSIBLE_LOG_PROB); state.values["pruned"] = 0u;