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.
This commit is contained in:
Daniel Patterson 2018-12-13 17:10:32 -07:00 committed by GitHub
parent 06e010b4d0
commit 81bc2f41a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 143 additions and 90 deletions

View File

@ -6,6 +6,8 @@
- Table: - 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) - 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) - 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 # 5.20.0
- Changes from 5.19.0: - Changes from 5.19.0:

View File

@ -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. | | `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 | | `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 | | `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: `turns` layer:

View File

@ -109,3 +109,12 @@ Feature: Car - Handle ferry routes
When I route I should get When I route I should get
| from | to | route | modes | time | | from | to | route | modes | time |
| c | d | bcde,bcde | ferry,ferry | 600s | | 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 |

View File

@ -312,12 +312,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance, 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()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange( return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, approach); input_coordinate, max_distance, approach, use_all_edges);
} }
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
@ -325,12 +326,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
const float max_distance, const float max_distance,
const int bearing, const int bearing,
const int bearing_range, 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()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange( 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<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>

View File

@ -126,11 +126,13 @@ class BaseDataFacade
const float max_distance, const float max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance, const float max_distance,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate, NearestPhantomNodes(const util::Coordinate input_coordinate,

View File

@ -53,12 +53,14 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate](const CandidateSegment &segment) { [this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)), return boolPairAnd(
boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach)); CheckApproach(input_coordinate, segment, approach));
}, },
[this, max_distance, input_coordinate](const std::size_t, [this, max_distance, input_coordinate](const std::size_t,
@ -76,15 +78,17 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range]( [this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
const CandidateSegment &segment) { const CandidateSegment &segment) {
auto use_direction = auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range), boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment))); boolPairAnd(HasValidEdge(segment, use_all_edges),
CheckSegmentExclude(segment)));
use_direction = use_direction =
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach)); boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
return use_direction; return use_direction;
@ -628,7 +632,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
* which means that this edge is not currently traversible. If this is the case, * which means that this edge is not currently traversible. If this is the case,
* then we shouldn't snap to this edge. * then we shouldn't snap to this edge.
*/ */
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment) const std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
const bool use_all_edges = false) const
{ {
bool forward_edge_valid = false; bool forward_edge_valid = false;
@ -652,6 +657,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_edge_valid = data.reverse_segment_id.enabled; 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); return std::make_pair(forward_edge_valid, reverse_edge_valid);
} }

View File

@ -138,7 +138,8 @@ class BasePlugin
std::vector<std::vector<PhantomNodeWithDistance>> std::vector<std::vector<PhantomNodeWithDistance>>
GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade, GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade,
const api::BaseParameters &parameters, const api::BaseParameters &parameters,
const std::vector<double> radiuses) const const std::vector<double> radiuses,
bool use_all_edges = false) const
{ {
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes( std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
parameters.coordinates.size()); parameters.coordinates.size());
@ -171,12 +172,13 @@ class BasePlugin
radiuses[i], radiuses[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
else else
{ {
phantom_nodes[i] = facade.NearestPhantomNodesInRange( phantom_nodes[i] = facade.NearestPhantomNodesInRange(
parameters.coordinates[i], radiuses[i], approach); parameters.coordinates[i], radiuses[i], approach, use_all_edges);
} }
} }

View File

@ -89,7 +89,6 @@ class EdgeBasedGraphFactory
// The following get access functions destroy the content in the factory // The following get access functions destroy the content in the factory
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges); void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes); void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights); void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations); void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances); void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
@ -112,10 +111,6 @@ class EdgeBasedGraphFactory
std::vector<ConditionalTurnPenalty> std::vector<ConditionalTurnPenalty>
IndexConditionals(std::vector<Conditional> &&conditionals) const; IndexConditionals(std::vector<Conditional> &&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<bool> m_edge_based_node_is_startpoint;
//! node weights that indicate the length of the segment (node based) represented by the //! node weights that indicate the length of the segment (node based) represented by the
//! edge-based node //! edge-based node
std::vector<EdgeWeight> m_edge_based_node_weights; std::vector<EdgeWeight> m_edge_based_node_weights;

View File

@ -22,7 +22,9 @@ struct EdgeBasedNodeSegment
EdgeBasedNodeSegment() EdgeBasedNodeSegment()
: forward_segment_id{SPECIAL_SEGMENTID, false}, : forward_segment_id{SPECIAL_SEGMENTID, false},
reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID), reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID),
fwd_segment_position(std::numeric_limits<unsigned short>::max()) fwd_segment_position(std::numeric_limits<unsigned short>::max() >>
1), // >> 1 because we've only got 15 bits
is_startpoint(false)
{ {
} }
@ -30,9 +32,10 @@ struct EdgeBasedNodeSegment
const SegmentID reverse_segment_id_, const SegmentID reverse_segment_id_,
NodeID u, NodeID u,
NodeID v, 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), : 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); 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) 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 u; // node-based graph node ID of the start node
NodeID v; // node-based graph node ID of the target 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;
}; };
} }
} }

View File

@ -85,7 +85,6 @@ class Extractor
// output data // output data
EdgeBasedNodeDataContainer &edge_based_nodes_container, EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments, std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights, std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations, std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances, std::vector<EdgeDistance> &edge_based_node_distances,
@ -97,7 +96,6 @@ class Extractor
const std::vector<EdgeBasedNodeSegment> &input_node_segments, const std::vector<EdgeBasedNodeSegment> &input_node_segments,
EdgeBasedNodeDataContainer &nodes_container) const; EdgeBasedNodeDataContainer &nodes_container) const;
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments, void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &coordinates); const std::vector<util::Coordinate> &coordinates);
std::shared_ptr<RestrictionMap> LoadRestrictionMap(); std::shared_ptr<RestrictionMap> LoadRestrictionMap();

View File

@ -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); filterCandidates(tidied.parameters.coordinates, candidates_lists);
if (std::all_of(candidates_lists.begin(), if (std::all_of(candidates_lists.begin(),

View File

@ -294,6 +294,7 @@ struct SpeedLayer : public vtzero::layer_builder
vtzero::index_value key_duration; vtzero::index_value key_duration;
vtzero::index_value key_name; vtzero::index_value key_name;
vtzero::index_value key_rate; vtzero::index_value key_rate;
vtzero::index_value key_is_startpoint;
SpeedLayer(vtzero::tile_builder &tile) SpeedLayer(vtzero::tile_builder &tile)
: layer_builder(tile, "speeds"), uint_index(*this), double_index(*this), : 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_datasource(add_key_without_dup_check("datasource")),
key_weight(add_key_without_dup_check("weight")), key_weight(add_key_without_dup_check("weight")),
key_duration(add_key_without_dup_check("duration")), 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_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 }; // class SpeedLayerFeatureBuilder
struct TurnsLayer : public vtzero::layer_builder struct TurnsLayer : public vtzero::layer_builder
@ -485,6 +492,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto reverse_datasource_idx = reverse_datasource_range( const auto reverse_datasource_idx = reverse_datasource_range(
reverse_datasource_range.size() - edge.fwd_segment_position - 1); 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 component_id = facade.GetComponentID(edge.forward_segment_id.id);
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id); const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
auto name = facade.GetNameForID(name_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_duration(forward_duration / 10.0);
fbuilder.set_name(name); fbuilder.set_name(name);
fbuilder.set_rate(forward_rate / 10.0); fbuilder.set_rate(forward_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit(); fbuilder.commit();
} }
@ -549,6 +559,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
fbuilder.set_duration(reverse_duration / 10.0); fbuilder.set_duration(reverse_duration / 10.0);
fbuilder.set_name(name); fbuilder.set_name(name);
fbuilder.set_rate(reverse_rate / 10.0); fbuilder.set_rate(reverse_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit(); fbuilder.commit();
} }

View File

@ -95,12 +95,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSe
swap(nodes, m_edge_based_node_segments); swap(nodes, m_edge_based_node_segments);
} }
void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
{
using std::swap; // Koenig swap
swap(m_edge_based_node_is_startpoint, node_is_startpoint);
}
void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights) void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
{ {
using std::swap; // Koenig swap 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]), edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]),
current_edge_source_coordinate_id, current_edge_source_coordinate_id,
current_edge_target_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; 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_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_durations.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size());

View File

@ -239,7 +239,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
EdgeBasedNodeDataContainer edge_based_nodes_container; EdgeBasedNodeDataContainer edge_based_nodes_container;
std::vector<EdgeBasedNodeSegment> edge_based_node_segments; std::vector<EdgeBasedNodeSegment> edge_based_node_segments;
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list; util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
std::vector<bool> node_is_startpoint;
std::vector<EdgeWeight> edge_based_node_weights; std::vector<EdgeWeight> edge_based_node_weights;
std::vector<EdgeDuration> edge_based_node_durations; std::vector<EdgeDuration> edge_based_node_durations;
std::vector<EdgeDistance> edge_based_node_distances; std::vector<EdgeDistance> edge_based_node_distances;
@ -320,7 +319,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
scripting_environment, scripting_environment,
edge_based_nodes_container, edge_based_nodes_container,
edge_based_node_segments, edge_based_node_segments,
node_is_startpoint,
edge_based_node_weights, edge_based_node_weights,
edge_based_node_durations, edge_based_node_durations,
edge_based_node_distances, edge_based_node_distances,
@ -362,7 +360,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
util::Log() << "Building r-tree ..."; util::Log() << "Building r-tree ...";
TIMER_START(rtree); 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); TIMER_STOP(rtree);
@ -737,7 +735,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
// output data // output data
EdgeBasedNodeDataContainer &edge_based_nodes_container, EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments, std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights, std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations, std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances, std::vector<EdgeDistance> &edge_based_node_distances,
@ -788,7 +785,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list); edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments); 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.GetEdgeBasedNodeWeights(edge_based_node_weights);
edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations); edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations);
edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances); edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances);
@ -803,35 +799,24 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
Saves tree into '.ramIndex' and leaves into '.fileIndex'. Saves tree into '.ramIndex' and leaves into '.fileIndex'.
*/ */
void Extractor::BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments, void Extractor::BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &coordinates) const std::vector<util::Coordinate> &coordinates)
{ {
util::Log() << "Constructing r-tree of " << edge_based_node_segments.size() util::Log() << "Constructing r-tree of " << edge_based_node_segments.size()
<< " segments build on-top of " << coordinates.size() << " coordinates"; << " 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 // Filter node based edges based on startpoint
auto out_iter = edge_based_node_segments.begin(); auto start_point_count = std::accumulate(edge_based_node_segments.begin(),
auto in_iter = edge_based_node_segments.begin(); edge_based_node_segments.end(),
for (auto index : util::irange<std::size_t>(0UL, node_is_startpoint.size())) 0,
{ [](const size_t so_far, const auto &segment) {
BOOST_ASSERT(in_iter != edge_based_node_segments.end()); return so_far + (segment.is_startpoint ? 1 : 0);
if (node_is_startpoint[index]) });
{ if (start_point_count == 0)
*out_iter = *in_iter;
out_iter++;
}
in_iter++;
}
auto new_size = out_iter - edge_based_node_segments.begin();
if (new_size == 0)
{ {
throw util::exception("There are no snappable edges left after processing. Are you " throw util::exception("There are no snappable edges left after processing. Are you "
"setting travel modes correctly in the profile? Cannot continue." + "setting travel modes correctly in the profile? Cannot continue." +
SOURCE_REF); SOURCE_REF);
} }
edge_based_node_segments.resize(new_size);
TIMER_START(construction); TIMER_START(construction);
util::StaticRTree<EdgeBasedNodeSegment> rtree( util::StaticRTree<EdgeBasedNodeSegment> rtree(

View File

@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2) 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 // Test files generated by the routing engine; check test/data
if (process.env.OSRM_DATA_PATH !== undefined) { if (process.env.OSRM_DATA_PATH !== undefined) {

View File

@ -229,7 +229,8 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
const float /*max_distance*/, const float /*max_distance*/,
const int /*bearing*/, const int /*bearing*/,
const int /*bearing_range*/, const int /*bearing_range*/,
const Approach /*approach*/) const override const Approach /*approach*/,
const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} }
@ -237,7 +238,8 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const float /*max_distance*/,
const Approach /*approach*/) const override const Approach /*approach*/,
const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} }

View File

@ -36,7 +36,7 @@ void validate_feature_layer(vtzero::layer layer)
BOOST_CHECK_EQUAL(layer.version(), 2); BOOST_CHECK_EQUAL(layer.version(), 2);
BOOST_CHECK_EQUAL(to_string(layer.name()), "speeds"); BOOST_CHECK_EQUAL(to_string(layer.name()), "speeds");
BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT); 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); BOOST_CHECK(layer.num_features() > 2500);
while (auto feature = layer.next_feature()) 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.find("is_small") != props.end());
BOOST_CHECK(props["is_small"].type() == typeid(bool)); 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.find("datasource") != props.end());
BOOST_CHECK(props["datasource"].type() == typeid(std::string)); 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) { std::count_if(layer.value_table().begin(), layer.value_table().end(), [](auto v) {
return v.type() == vtzero::property_value_type::uint_value; 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) 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(to_string(layer.name()), "osmnodes");
BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT); BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT);
BOOST_CHECK_EQUAL(layer.key_table().size(), 0); 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()) while (auto feature = layer.next_feature())
{ {

View File

@ -113,7 +113,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
const float /*max_distance*/, const float /*max_distance*/,
const int /*bearing*/, const int /*bearing*/,
const int /*bearing_range*/, const int /*bearing_range*/,
const engine::Approach /*approach*/) const override const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} }
@ -121,7 +122,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
std::vector<engine::PhantomNodeWithDistance> std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/, const float /*max_distance*/,
const engine::Approach /*approach*/) const override const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override
{ {
return {}; return {};
} }

View File

@ -135,6 +135,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
TestData data; TestData data;
data.u = edge_udist(g); data.u = edge_udist(g);
data.v = edge_udist(g); data.v = edge_udist(g);
data.is_startpoint = true;
if (used_edges.find(std::pair<unsigned, unsigned>( if (used_edges.find(std::pair<unsigned, unsigned>(
std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end()) std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
{ {
@ -151,7 +152,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
struct GraphFixture struct GraphFixture
{ {
GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords, GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords,
const std::vector<std::pair<unsigned, unsigned>> &input_edges) const std::vector<std::tuple<unsigned, unsigned, bool>> &input_edges)
{ {
for (unsigned i = 0; i < input_coords.size(); i++) for (unsigned i = 0; i < input_coords.size(); i++)
@ -162,15 +163,16 @@ struct GraphFixture
for (const auto &pair : input_edges) for (const auto &pair : input_edges)
{ {
TestData d; TestData d;
d.u = pair.first; d.u = std::get<0>(pair);
d.v = pair.second; d.v = std::get<1>(pair);
// We set the forward nodes to the target node-based-node IDs, just // 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 // so we have something to test against. Because this isn't a real
// graph, the actual values aren't important, we just need something // graph, the actual values aren't important, we just need something
// to examine during tests. // to examine during tests.
d.forward_segment_id = {pair.second, true}; d.forward_segment_id = {std::get<1>(pair), true};
d.reverse_segment_id = {pair.first, true}; d.reverse_segment_id = {std::get<0>(pair), true};
d.fwd_segment_position = 0; d.fwd_segment_position = 0;
d.is_startpoint = std::get<2>(pair);
edges.emplace_back(d); edges.emplace_back(d);
} }
} }
@ -299,7 +301,7 @@ BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_M
BOOST_AUTO_TEST_CASE(regression_test) BOOST_AUTO_TEST_CASE(regression_test)
{ {
using Coord = std::pair<FloatLongitude, FloatLatitude>; using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>; using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture( GraphFixture fixture(
{ {
Coord{FloatLongitude{0.0}, FloatLatitude{40.0}}, // 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{105.0}, FloatLatitude{5.0}}, //
Coord{FloatLongitude{110.0}, FloatLatitude{0.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; TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture); auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@ -335,13 +337,13 @@ BOOST_AUTO_TEST_CASE(regression_test)
BOOST_AUTO_TEST_CASE(radius_regression_test) BOOST_AUTO_TEST_CASE(radius_regression_test)
{ {
using Coord = std::pair<FloatLongitude, FloatLatitude>; using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>; using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture( GraphFixture fixture(
{ {
Coord(FloatLongitude{0.0}, FloatLatitude{0.0}), Coord(FloatLongitude{0.0}, FloatLatitude{0.0}),
Coord(FloatLongitude{10.0}, FloatLatitude{10.0}), Coord(FloatLongitude{10.0}, FloatLatitude{10.0}),
}, },
{Edge(0, 1), Edge(1, 0)}); {Edge(0, 1, true), Edge(1, 0, true)});
TemporaryFile tmp; TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture); auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@ -352,22 +354,54 @@ BOOST_AUTO_TEST_CASE(radius_regression_test)
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0}); Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
{ {
auto results = auto results = query.NearestPhantomNodesInRange(
query.NearestPhantomNodesInRange(input, 0.01, osrm::engine::Approach::UNRESTRICTED); input, 0.01, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 0); BOOST_CHECK_EQUAL(results.size(), 0);
} }
} }
BOOST_AUTO_TEST_CASE(permissive_edge_snapping)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::tuple<unsigned, unsigned, bool>;
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<MiniStaticRTree>(tmp.path, fixture);
TestDataFacade mockfacade;
engine::GeospatialQuery<MiniStaticRTree, TestDataFacade> 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) BOOST_AUTO_TEST_CASE(bearing_tests)
{ {
using Coord = std::pair<FloatLongitude, FloatLatitude>; using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>; using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture( GraphFixture fixture(
{ {
Coord(FloatLongitude{0.0}, FloatLatitude{0.0}), Coord(FloatLongitude{0.0}, FloatLatitude{0.0}),
Coord(FloatLongitude{10.0}, FloatLatitude{10.0}), Coord(FloatLongitude{10.0}, FloatLatitude{10.0}),
}, },
{Edge(0, 1), Edge(1, 0)}); {Edge(0, 1, true), Edge(1, 0, true)});
TemporaryFile tmp; TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture); auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@ -405,20 +439,20 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
} }
{ {
auto results = auto results = query.NearestPhantomNodesInRange(
query.NearestPhantomNodesInRange(input, 11000, osrm::engine::Approach::UNRESTRICTED); input, 11000, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.size(), 2);
} }
{ {
auto results = query.NearestPhantomNodesInRange( 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); BOOST_CHECK_EQUAL(results.size(), 0);
} }
{ {
auto results = query.NearestPhantomNodesInRange( 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_EQUAL(results.size(), 2);
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled); 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) BOOST_AUTO_TEST_CASE(bbox_search_tests)
{ {
using Coord = std::pair<FloatLongitude, FloatLatitude>; using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>; using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture( GraphFixture fixture(
{ {
@ -444,7 +478,7 @@ BOOST_AUTO_TEST_CASE(bbox_search_tests)
Coord(FloatLongitude{3.0}, FloatLatitude{3.0}), Coord(FloatLongitude{3.0}, FloatLatitude{3.0}),
Coord(FloatLongitude{4.0}, FloatLatitude{4.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; TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture); auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);