From 81bc2f41a63be4de4ed1740c5034ce70fa5d1980 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Thu, 13 Dec 2018 17:10:32 -0700 Subject: [PATCH] When matching, ignore 'is_startpoint' propert, snap to any edge (#5297) Includes all edges in the rtree, but adds an `is_startpoint` flag to each. Most plugin behaviour remains unchanged (non-startpoint edges aren't used as snapping candidates), but for map matching, we allow snapping to any edge. This fixes map-matching across previously non-is_startpoint edges, like ferries, private service roads, and a few others. --- CHANGELOG.md | 2 + docs/http.md | 1 + features/car/ferry.feature | 9 +++ .../contiguous_internalmem_datafacade.hpp | 10 +-- include/engine/datafacade/datafacade_base.hpp | 6 +- include/engine/geospatial_query.hpp | 24 ++++--- include/engine/plugins/plugin_base.hpp | 8 ++- .../extractor/edge_based_graph_factory.hpp | 5 -- include/extractor/edge_based_node_segment.hpp | 12 ++-- include/extractor/extractor.hpp | 2 - src/engine/plugins/match.cpp | 3 +- src/engine/plugins/tile.cpp | 13 +++- src/extractor/edge_based_graph_factory.cpp | 12 +--- src/extractor/extractor.cpp | 31 +++----- test/nodejs/constants.js | 2 +- unit_tests/engine/offline_facade.cpp | 6 +- unit_tests/library/tile.cpp | 9 ++- unit_tests/mocks/mock_datafacade.hpp | 6 +- unit_tests/util/static_rtree.cpp | 72 ++++++++++++++----- 19 files changed, 143 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f953bc2f6..be5f21af5a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Table: - ADDED: new parameter `scale_factor` which will scale the cell `duration` values by this factor. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5298) - FIXED: only trigger `scale_factor` code to scan matrix when necessary. [#5303](https://github.com/Project-OSRM/osrm-backend/pull/5303) + - Matching: + - CHANGED: matching will now consider edges marked with is_startpoint=false, allowing matching over ferries and other previously non-matchable edge types. [#5297](https://github.com/Project-OSRM/osrm-backend/pull/5297) # 5.20.0 - Changes from 5.19.0: diff --git a/docs/http.md b/docs/http.md index 56c29051225..fb7811c794f 100644 --- a/docs/http.md +++ b/docs/http.md @@ -557,6 +557,7 @@ Vector tiles contain two layers: | `weight ` | `integer` | how long this segment takes to traverse, in units (may differ from `duration` when artificial biasing is applied in the Lua profiles). ACTUAL ROUTING USES THIS VALUE. | | `name` | `string` | the name of the road this segment belongs to | | `rate` | `float` | the value of `length/weight` - analagous to `speed`, but using the `weight` value rather than `duration`, rounded to the nearest integer | +| `is_startpoint` | `boolean` | whether this segment can be used as a start/endpoint for routes | `turns` layer: diff --git a/features/car/ferry.feature b/features/car/ferry.feature index acdd13f6e42..5a8de7b1b5c 100644 --- a/features/car/ferry.feature +++ b/features/car/ferry.feature @@ -109,3 +109,12 @@ Feature: Car - Handle ferry routes When I route I should get | from | to | route | modes | time | | c | d | bcde,bcde | ferry,ferry | 600s | + + Given the query options + | geometries | geojson | + | overview | full | + + # Note that matching *should* work across unsnappable ferries + When I match I should get + | trace | geometry | duration | + | abcdef| 1,1,1.000899,1,1.000899,1,1.002697,1,1.002697,1,1.003596,1,1.003596,1,1.005394,1,1.005394,1,1.006293,1 | 610.9 | diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 936d40f9961..7aabc704ed9 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -312,12 +312,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const float max_distance, - const Approach approach) const override final + const Approach approach, + const bool use_all_edges) const override final { BOOST_ASSERT(m_geospatial_query.get()); return m_geospatial_query->NearestPhantomNodesInRange( - input_coordinate, max_distance, approach); + input_coordinate, max_distance, approach, use_all_edges); } std::vector @@ -325,12 +326,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade const float max_distance, const int bearing, const int bearing_range, - const Approach approach) const override final + const Approach approach, + const bool use_all_edges) const override final { BOOST_ASSERT(m_geospatial_query.get()); return m_geospatial_query->NearestPhantomNodesInRange( - input_coordinate, max_distance, bearing, bearing_range, approach); + input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges); } std::vector diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 091017859b3..23b2bdae7c5 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -126,11 +126,13 @@ class BaseDataFacade const float max_distance, const int bearing, const int bearing_range, - const Approach approach) const = 0; + const Approach approach, + const bool use_all_edges) const = 0; virtual std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const float max_distance, - const Approach approach) const = 0; + const Approach approach, + const bool use_all_edges) const = 0; virtual std::vector NearestPhantomNodes(const util::Coordinate input_coordinate, diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index 4ecfc8118bd..42f8105b887 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -53,13 +53,15 @@ template class GeospatialQuery std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance, - const Approach approach) const + const Approach approach, + const bool use_all_edges) const { auto results = rtree.Nearest( input_coordinate, - [this, approach, &input_coordinate](const CandidateSegment &segment) { - return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)), - CheckApproach(input_coordinate, segment, approach)); + [this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) { + return boolPairAnd( + boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)), + CheckApproach(input_coordinate, segment, approach)); }, [this, max_distance, input_coordinate](const std::size_t, const CandidateSegment &segment) { @@ -76,15 +78,17 @@ template class GeospatialQuery const double max_distance, const int bearing, const int bearing_range, - const Approach approach) const + const Approach approach, + const bool use_all_edges) const { auto results = rtree.Nearest( input_coordinate, - [this, approach, &input_coordinate, bearing, bearing_range]( + [this, approach, &input_coordinate, bearing, bearing_range, use_all_edges]( const CandidateSegment &segment) { auto use_direction = boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range), - boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment))); + boolPairAnd(HasValidEdge(segment, use_all_edges), + CheckSegmentExclude(segment))); use_direction = boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach)); return use_direction; @@ -628,7 +632,8 @@ template class GeospatialQuery * which means that this edge is not currently traversible. If this is the case, * then we shouldn't snap to this edge. */ - std::pair HasValidEdge(const CandidateSegment &segment) const + std::pair HasValidEdge(const CandidateSegment &segment, + const bool use_all_edges = false) const { bool forward_edge_valid = false; @@ -652,6 +657,9 @@ template class GeospatialQuery reverse_edge_valid = data.reverse_segment_id.enabled; } + forward_edge_valid = forward_edge_valid && (data.is_startpoint || use_all_edges); + reverse_edge_valid = reverse_edge_valid && (data.is_startpoint || use_all_edges); + return std::make_pair(forward_edge_valid, reverse_edge_valid); } diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp index 17856044b94..7412627de32 100644 --- a/include/engine/plugins/plugin_base.hpp +++ b/include/engine/plugins/plugin_base.hpp @@ -138,7 +138,8 @@ class BasePlugin std::vector> GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade, const api::BaseParameters ¶meters, - const std::vector radiuses) const + const std::vector radiuses, + bool use_all_edges = false) const { std::vector> phantom_nodes( parameters.coordinates.size()); @@ -171,12 +172,13 @@ class BasePlugin radiuses[i], parameters.bearings[i]->bearing, parameters.bearings[i]->range, - approach); + approach, + use_all_edges); } else { phantom_nodes[i] = facade.NearestPhantomNodesInRange( - parameters.coordinates[i], radiuses[i], approach); + parameters.coordinates[i], radiuses[i], approach, use_all_edges); } } diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 388e0d75e71..b99ec2c2cf3 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -89,7 +89,6 @@ class EdgeBasedGraphFactory // The following get access functions destroy the content in the factory void GetEdgeBasedEdges(util::DeallocatingVector &edges); void GetEdgeBasedNodeSegments(std::vector &nodes); - void GetStartPointMarkers(std::vector &node_is_startpoint); void GetEdgeBasedNodeWeights(std::vector &output_node_weights); void GetEdgeBasedNodeDurations(std::vector &output_node_durations); void GetEdgeBasedNodeDistances(std::vector &output_node_distances); @@ -112,10 +111,6 @@ class EdgeBasedGraphFactory std::vector IndexConditionals(std::vector &&conditionals) const; - //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the - //! graph - std::vector m_edge_based_node_is_startpoint; - //! node weights that indicate the length of the segment (node based) represented by the //! edge-based node std::vector m_edge_based_node_weights; diff --git a/include/extractor/edge_based_node_segment.hpp b/include/extractor/edge_based_node_segment.hpp index 29bd8f7e114..b85131e02d4 100644 --- a/include/extractor/edge_based_node_segment.hpp +++ b/include/extractor/edge_based_node_segment.hpp @@ -22,7 +22,9 @@ struct EdgeBasedNodeSegment EdgeBasedNodeSegment() : forward_segment_id{SPECIAL_SEGMENTID, false}, reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID), - fwd_segment_position(std::numeric_limits::max()) + fwd_segment_position(std::numeric_limits::max() >> + 1), // >> 1 because we've only got 15 bits + is_startpoint(false) { } @@ -30,9 +32,10 @@ struct EdgeBasedNodeSegment const SegmentID reverse_segment_id_, NodeID u, NodeID v, - unsigned short fwd_segment_position) + unsigned short fwd_segment_position, + bool is_startpoint_) : forward_segment_id(forward_segment_id_), reverse_segment_id(reverse_segment_id_), u(u), - v(v), fwd_segment_position(fwd_segment_position) + v(v), fwd_segment_position(fwd_segment_position), is_startpoint(is_startpoint_) { BOOST_ASSERT(forward_segment_id.enabled || reverse_segment_id.enabled); } @@ -41,7 +44,8 @@ struct EdgeBasedNodeSegment SegmentID reverse_segment_id; // edge-based graph node ID in reverse direction (v->u if exists) NodeID u; // node-based graph node ID of the start node NodeID v; // node-based graph node ID of the target node - unsigned short fwd_segment_position; // segment id in a compressed geometry + unsigned short fwd_segment_position : 15; // segment id in a compressed geometry + bool is_startpoint : 1; }; } } diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index db571475b90..29dec218bfb 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -85,7 +85,6 @@ class Extractor // output data EdgeBasedNodeDataContainer &edge_based_nodes_container, std::vector &edge_based_node_segments, - std::vector &node_is_startpoint, std::vector &edge_based_node_weights, std::vector &edge_based_node_durations, std::vector &edge_based_node_distances, @@ -97,7 +96,6 @@ class Extractor const std::vector &input_node_segments, EdgeBasedNodeDataContainer &nodes_container) const; void BuildRTree(std::vector edge_based_node_segments, - std::vector node_is_startpoint, const std::vector &coordinates); std::shared_ptr LoadRestrictionMap(); diff --git a/src/engine/plugins/match.cpp b/src/engine/plugins/match.cpp index 8323b0ab6fd..54ad24231df 100644 --- a/src/engine/plugins/match.cpp +++ b/src/engine/plugins/match.cpp @@ -213,7 +213,8 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, }); } - auto candidates_lists = GetPhantomNodesInRange(facade, tidied.parameters, search_radiuses); + auto candidates_lists = + GetPhantomNodesInRange(facade, tidied.parameters, search_radiuses, true); filterCandidates(tidied.parameters.coordinates, candidates_lists); if (std::all_of(candidates_lists.begin(), diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp index bd776756640..47fb1933e76 100644 --- a/src/engine/plugins/tile.cpp +++ b/src/engine/plugins/tile.cpp @@ -294,6 +294,7 @@ struct SpeedLayer : public vtzero::layer_builder vtzero::index_value key_duration; vtzero::index_value key_name; vtzero::index_value key_rate; + vtzero::index_value key_is_startpoint; SpeedLayer(vtzero::tile_builder &tile) : layer_builder(tile, "speeds"), uint_index(*this), double_index(*this), @@ -302,7 +303,8 @@ struct SpeedLayer : public vtzero::layer_builder key_datasource(add_key_without_dup_check("datasource")), key_weight(add_key_without_dup_check("weight")), key_duration(add_key_without_dup_check("duration")), - key_name(add_key_without_dup_check("name")), key_rate(add_key_without_dup_check("rate")) + key_name(add_key_without_dup_check("name")), key_rate(add_key_without_dup_check("rate")), + key_is_startpoint(add_key_without_dup_check("is_startpoint")) { } @@ -349,6 +351,11 @@ class SpeedLayerFeatureBuilder : public vtzero::linestring_feature_builder void set_rate(double value) { add_property(m_layer.key_rate, m_layer.double_index(value)); } + void set_is_startpoint(bool value) + { + add_property(m_layer.key_is_startpoint, m_layer.bool_index(value)); + } + }; // class SpeedLayerFeatureBuilder struct TurnsLayer : public vtzero::layer_builder @@ -485,6 +492,8 @@ void encodeVectorTile(const DataFacadeBase &facade, const auto reverse_datasource_idx = reverse_datasource_range( reverse_datasource_range.size() - edge.fwd_segment_position - 1); + const auto is_startpoint = edge.is_startpoint; + const auto component_id = facade.GetComponentID(edge.forward_segment_id.id); const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id); auto name = facade.GetNameForID(name_id); @@ -516,6 +525,7 @@ void encodeVectorTile(const DataFacadeBase &facade, fbuilder.set_duration(forward_duration / 10.0); fbuilder.set_name(name); fbuilder.set_rate(forward_rate / 10.0); + fbuilder.set_is_startpoint(is_startpoint); fbuilder.commit(); } @@ -549,6 +559,7 @@ void encodeVectorTile(const DataFacadeBase &facade, fbuilder.set_duration(reverse_duration / 10.0); fbuilder.set_name(name); fbuilder.set_rate(reverse_rate / 10.0); + fbuilder.set_is_startpoint(is_startpoint); fbuilder.commit(); } diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index a5d5b605b3c..0d40238778d 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -95,12 +95,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector &node_is_startpoint) -{ - using std::swap; // Koenig swap - swap(m_edge_based_node_is_startpoint, node_is_startpoint); -} - void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector &output_node_weights) { using std::swap; // Koenig swap @@ -229,10 +223,9 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]), current_edge_source_coordinate_id, current_edge_target_coordinate_id, - i); + i, + forward_data.flags.startpoint || reverse_data.flags.startpoint); - m_edge_based_node_is_startpoint.push_back(forward_data.flags.startpoint || - reverse_data.flags.startpoint); current_edge_source_coordinate_id = current_edge_target_coordinate_id; } @@ -427,7 +420,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re } } - BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size()); diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index dc92f7011b8..abd0bab930a 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -239,7 +239,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) EdgeBasedNodeDataContainer edge_based_nodes_container; std::vector edge_based_node_segments; util::DeallocatingVector edge_based_edge_list; - std::vector node_is_startpoint; std::vector edge_based_node_weights; std::vector edge_based_node_durations; std::vector edge_based_node_distances; @@ -320,7 +319,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) scripting_environment, edge_based_nodes_container, edge_based_node_segments, - node_is_startpoint, edge_based_node_weights, edge_based_node_durations, edge_based_node_distances, @@ -362,7 +360,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) util::Log() << "Building r-tree ..."; TIMER_START(rtree); - BuildRTree(std::move(edge_based_node_segments), std::move(node_is_startpoint), coordinates); + BuildRTree(std::move(edge_based_node_segments), coordinates); TIMER_STOP(rtree); @@ -737,7 +735,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph( // output data EdgeBasedNodeDataContainer &edge_based_nodes_container, std::vector &edge_based_node_segments, - std::vector &node_is_startpoint, std::vector &edge_based_node_weights, std::vector &edge_based_node_durations, std::vector &edge_based_node_distances, @@ -788,7 +785,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph( edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list); edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments); - edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint); edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights); edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations); edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances); @@ -803,35 +799,24 @@ EdgeID Extractor::BuildEdgeExpandedGraph( Saves tree into '.ramIndex' and leaves into '.fileIndex'. */ void Extractor::BuildRTree(std::vector edge_based_node_segments, - std::vector node_is_startpoint, const std::vector &coordinates) { util::Log() << "Constructing r-tree of " << edge_based_node_segments.size() << " segments build on-top of " << coordinates.size() << " coordinates"; - BOOST_ASSERT(node_is_startpoint.size() == edge_based_node_segments.size()); - // Filter node based edges based on startpoint - auto out_iter = edge_based_node_segments.begin(); - auto in_iter = edge_based_node_segments.begin(); - for (auto index : util::irange(0UL, node_is_startpoint.size())) - { - BOOST_ASSERT(in_iter != edge_based_node_segments.end()); - if (node_is_startpoint[index]) - { - *out_iter = *in_iter; - out_iter++; - } - in_iter++; - } - auto new_size = out_iter - edge_based_node_segments.begin(); - if (new_size == 0) + auto start_point_count = std::accumulate(edge_based_node_segments.begin(), + edge_based_node_segments.end(), + 0, + [](const size_t so_far, const auto &segment) { + return so_far + (segment.is_startpoint ? 1 : 0); + }); + if (start_point_count == 0) { throw util::exception("There are no snappable edges left after processing. Are you " "setting travel modes correctly in the profile? Cannot continue." + SOURCE_REF); } - edge_based_node_segments.resize(new_size); TIMER_START(construction); util::StaticRTree rtree( diff --git a/test/nodejs/constants.js b/test/nodejs/constants.js index 0726bc91c3d..a6a32ca25c3 100644 --- a/test/nodejs/constants.js +++ b/test/nodejs/constants.js @@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956], exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2) -exports.test_tile = {'at': [17059, 11948, 15], 'size': 148750}; +exports.test_tile = {'at': [17059, 11948, 15], 'size': 156624}; // Test files generated by the routing engine; check test/data if (process.env.OSRM_DATA_PATH !== undefined) { diff --git a/unit_tests/engine/offline_facade.cpp b/unit_tests/engine/offline_facade.cpp index 6314b3a7c2d..bede4eabe96 100644 --- a/unit_tests/engine/offline_facade.cpp +++ b/unit_tests/engine/offline_facade.cpp @@ -229,7 +229,8 @@ class ContiguousInternalMemoryDataFacade const float /*max_distance*/, const int /*bearing*/, const int /*bearing_range*/, - const Approach /*approach*/) const override + const Approach /*approach*/, + const bool /*use_all_edges*/) const override { return {}; } @@ -237,7 +238,8 @@ class ContiguousInternalMemoryDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, const float /*max_distance*/, - const Approach /*approach*/) const override + const Approach /*approach*/, + const bool /*use_all_edges*/) const override { return {}; } diff --git a/unit_tests/library/tile.cpp b/unit_tests/library/tile.cpp index 16c073d3425..39bb26b02e5 100644 --- a/unit_tests/library/tile.cpp +++ b/unit_tests/library/tile.cpp @@ -36,7 +36,7 @@ void validate_feature_layer(vtzero::layer layer) BOOST_CHECK_EQUAL(layer.version(), 2); BOOST_CHECK_EQUAL(to_string(layer.name()), "speeds"); BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT); - BOOST_CHECK_EQUAL(layer.key_table().size(), 7); + BOOST_CHECK_EQUAL(layer.key_table().size(), 8); BOOST_CHECK(layer.num_features() > 2500); while (auto feature = layer.next_feature()) @@ -62,6 +62,9 @@ void validate_feature_layer(vtzero::layer layer) BOOST_CHECK(props.find("is_small") != props.end()); BOOST_CHECK(props["is_small"].type() == typeid(bool)); + BOOST_CHECK(props.find("is_startpoint") != props.end()); + BOOST_CHECK(props["is_startpoint"].type() == typeid(bool)); + BOOST_CHECK(props.find("datasource") != props.end()); BOOST_CHECK(props["datasource"].type() == typeid(std::string)); @@ -73,7 +76,7 @@ void validate_feature_layer(vtzero::layer layer) std::count_if(layer.value_table().begin(), layer.value_table().end(), [](auto v) { return v.type() == vtzero::property_value_type::uint_value; }); - BOOST_CHECK_EQUAL(number_of_uint_values, 77); + BOOST_CHECK_EQUAL(number_of_uint_values, 78); } void validate_turn_layer(vtzero::layer layer) @@ -125,7 +128,7 @@ void validate_node_layer(vtzero::layer layer) BOOST_CHECK_EQUAL(to_string(layer.name()), "osmnodes"); BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT); BOOST_CHECK_EQUAL(layer.key_table().size(), 0); - BOOST_CHECK_EQUAL(layer.num_features(), 1791); + BOOST_CHECK_EQUAL(layer.num_features(), 1810); while (auto feature = layer.next_feature()) { diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index 2342d47527c..e68a1a3063a 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -113,7 +113,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade const float /*max_distance*/, const int /*bearing*/, const int /*bearing_range*/, - const engine::Approach /*approach*/) const override + const engine::Approach /*approach*/, + const bool /*use_all_edges*/) const override { return {}; } @@ -121,7 +122,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, const float /*max_distance*/, - const engine::Approach /*approach*/) const override + const engine::Approach /*approach*/, + const bool /*use_all_edges*/) const override { return {}; } diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp index 5af7168f324..b6e7d7d1181 100644 --- a/unit_tests/util/static_rtree.cpp +++ b/unit_tests/util/static_rtree.cpp @@ -135,6 +135,7 @@ template struct RandomGraphFixture TestData data; data.u = edge_udist(g); data.v = edge_udist(g); + data.is_startpoint = true; if (used_edges.find(std::pair( std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end()) { @@ -151,7 +152,7 @@ template struct RandomGraphFixture struct GraphFixture { GraphFixture(const std::vector> &input_coords, - const std::vector> &input_edges) + const std::vector> &input_edges) { for (unsigned i = 0; i < input_coords.size(); i++) @@ -162,15 +163,16 @@ struct GraphFixture for (const auto &pair : input_edges) { TestData d; - d.u = pair.first; - d.v = pair.second; + d.u = std::get<0>(pair); + d.v = std::get<1>(pair); // We set the forward nodes to the target node-based-node IDs, just // so we have something to test against. Because this isn't a real // graph, the actual values aren't important, we just need something // to examine during tests. - d.forward_segment_id = {pair.second, true}; - d.reverse_segment_id = {pair.first, true}; + d.forward_segment_id = {std::get<1>(pair), true}; + d.reverse_segment_id = {std::get<0>(pair), true}; d.fwd_segment_position = 0; + d.is_startpoint = std::get<2>(pair); edges.emplace_back(d); } } @@ -299,7 +301,7 @@ BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_M BOOST_AUTO_TEST_CASE(regression_test) { using Coord = std::pair; - using Edge = std::pair; + using Edge = std::tuple; GraphFixture fixture( { Coord{FloatLongitude{0.0}, FloatLatitude{40.0}}, // @@ -313,7 +315,7 @@ BOOST_AUTO_TEST_CASE(regression_test) Coord{FloatLongitude{105.0}, FloatLatitude{5.0}}, // Coord{FloatLongitude{110.0}, FloatLatitude{0.0}}, // }, - {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)}); + {Edge(0, 1, true), Edge(2, 3, true), Edge(4, 5, true), Edge(6, 7, true), Edge(8, 9, true)}); TemporaryFile tmp; auto rtree = make_rtree(tmp.path, fixture); @@ -335,13 +337,13 @@ BOOST_AUTO_TEST_CASE(regression_test) BOOST_AUTO_TEST_CASE(radius_regression_test) { using Coord = std::pair; - using Edge = std::pair; + using Edge = std::tuple; GraphFixture fixture( { Coord(FloatLongitude{0.0}, FloatLatitude{0.0}), Coord(FloatLongitude{10.0}, FloatLatitude{10.0}), }, - {Edge(0, 1), Edge(1, 0)}); + {Edge(0, 1, true), Edge(1, 0, true)}); TemporaryFile tmp; auto rtree = make_rtree(tmp.path, fixture); @@ -352,22 +354,54 @@ BOOST_AUTO_TEST_CASE(radius_regression_test) Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0}); { - auto results = - query.NearestPhantomNodesInRange(input, 0.01, osrm::engine::Approach::UNRESTRICTED); + auto results = query.NearestPhantomNodesInRange( + input, 0.01, osrm::engine::Approach::UNRESTRICTED, true); BOOST_CHECK_EQUAL(results.size(), 0); } } +BOOST_AUTO_TEST_CASE(permissive_edge_snapping) +{ + using Coord = std::pair; + using Edge = std::tuple; + GraphFixture fixture( + { + Coord(FloatLongitude{0.0}, FloatLatitude{0.0}), + Coord(FloatLongitude{0.001}, FloatLatitude{0.001}), + }, + {Edge(0, 1, true), Edge(1, 0, false)}); + + TemporaryFile tmp; + auto rtree = make_rtree(tmp.path, fixture); + TestDataFacade mockfacade; + engine::GeospatialQuery query( + rtree, fixture.coords, mockfacade); + + Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005}); + + { + auto results = query.NearestPhantomNodesInRange( + input, 1000, osrm::engine::Approach::UNRESTRICTED, false); + BOOST_CHECK_EQUAL(results.size(), 1); + } + + { + auto results = query.NearestPhantomNodesInRange( + input, 1000, osrm::engine::Approach::UNRESTRICTED, true); + BOOST_CHECK_EQUAL(results.size(), 2); + } +} + BOOST_AUTO_TEST_CASE(bearing_tests) { using Coord = std::pair; - using Edge = std::pair; + using Edge = std::tuple; GraphFixture fixture( { Coord(FloatLongitude{0.0}, FloatLatitude{0.0}), Coord(FloatLongitude{10.0}, FloatLatitude{10.0}), }, - {Edge(0, 1), Edge(1, 0)}); + {Edge(0, 1, true), Edge(1, 0, true)}); TemporaryFile tmp; auto rtree = make_rtree(tmp.path, fixture); @@ -405,20 +439,20 @@ BOOST_AUTO_TEST_CASE(bearing_tests) } { - auto results = - query.NearestPhantomNodesInRange(input, 11000, osrm::engine::Approach::UNRESTRICTED); + auto results = query.NearestPhantomNodesInRange( + input, 11000, osrm::engine::Approach::UNRESTRICTED, true); BOOST_CHECK_EQUAL(results.size(), 2); } { auto results = query.NearestPhantomNodesInRange( - input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED); + input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED, true); BOOST_CHECK_EQUAL(results.size(), 0); } { auto results = query.NearestPhantomNodesInRange( - input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED); + input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED, true); BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled); @@ -434,7 +468,7 @@ BOOST_AUTO_TEST_CASE(bearing_tests) BOOST_AUTO_TEST_CASE(bbox_search_tests) { using Coord = std::pair; - using Edge = std::pair; + using Edge = std::tuple; GraphFixture fixture( { @@ -444,7 +478,7 @@ BOOST_AUTO_TEST_CASE(bbox_search_tests) Coord(FloatLongitude{3.0}, FloatLatitude{3.0}), Coord(FloatLongitude{4.0}, FloatLatitude{4.0}), }, - {Edge(0, 1), Edge(1, 2), Edge(2, 3), Edge(3, 4)}); + {Edge(0, 1, true), Edge(1, 2, true), Edge(2, 3, true), Edge(3, 4, true)}); TemporaryFile tmp; auto rtree = make_rtree(tmp.path, fixture);