diff --git a/docs/http.md b/docs/http.md index 56c290512..fb7811c79 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 acdd13f6e..5a8de7b1b 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 936d40f99..7aabc704e 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 091017859..23b2bdae7 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 4ecfc8118..42f8105b8 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 17856044b..7412627de 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 388e0d75e..b99ec2c2c 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 29bd8f7e1..b85131e02 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 db571475b..29dec218b 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 8323b0ab6..54ad24231 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 bd7767566..4ad1e6e22 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(); } diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index a5d5b605b..0d4023877 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 dc92f7011..abd0bab93 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 0726bc91c..04bf35ce3 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': 151220}; // 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 6314b3a7c..bede4eabe 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/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index 2342d4752..e68a1a306 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 {}; }