When matching, ignore 'is_startpoint' proper, snap to any edge. Typically map-matching is done from real world data, which implies access to previously unsnappable points.

This commit is contained in:
Daniel Patterson 2018-12-07 17:04:14 -08:00
parent 06e010b4d0
commit d8de5bddb6
No known key found for this signature in database
GPG Key ID: 19C12BE1725A028B
16 changed files with 81 additions and 68 deletions

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. |
| `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:

View File

@ -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 |

View File

@ -312,12 +312,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::vector<PhantomNodeWithDistance>
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<PhantomNodeWithDistance>
@ -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<PhantomNodeWithDistance>

View File

@ -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<PhantomNodeWithDistance>
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<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,

View File

@ -53,12 +53,14 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::vector<PhantomNodeWithDistance>
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)),
[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,
@ -76,15 +78,17 @@ template <typename RTreeT, typename DataFacadeT> 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 <typename RTreeT, typename DataFacadeT> 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<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;
@ -652,6 +657,9 @@ template <typename RTreeT, typename DataFacadeT> 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);
}

View File

@ -138,7 +138,8 @@ class BasePlugin
std::vector<std::vector<PhantomNodeWithDistance>>
GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade,
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(
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);
}
}

View File

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

View File

@ -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<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_,
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;
};
}
}

View File

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

View File

@ -95,12 +95,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSe
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)
{
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());

View File

@ -239,7 +239,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
EdgeBasedNodeDataContainer edge_based_nodes_container;
std::vector<EdgeBasedNodeSegment> edge_based_node_segments;
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
std::vector<bool> node_is_startpoint;
std::vector<EdgeWeight> edge_based_node_weights;
std::vector<EdgeDuration> edge_based_node_durations;
std::vector<EdgeDistance> 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<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations,
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.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<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &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<std::size_t>(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<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.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) {

View File

@ -229,7 +229,8 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
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<routing_algorithms::offline::Algorithm>
std::vector<PhantomNodeWithDistance>
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 {};
}

View File

@ -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<engine::PhantomNodeWithDistance>
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 {};
}