Improvements to maneuver override processing (#6215)
This change unblocks the osrm-extract debug build, which is currently failing on a maneuver override assertion. The processing of maneuver overrides currently has three issues - It assumes the via node(s) can't be compressed (the failing assertion) - It can't handle via-paths containing incompressible nodes - It doesn't interop with turn restriction on the same path Turn restrictions and maneuver overrides both use the same from-via-to path representation. Therefore, we can fix these issues by consolidating their structures and reusing the path representation for turn restrictions, which already is robust to the above issues. This also simplifies some of the codebase by removing maneuver override specific path processing. There are ~100 maneuver overrides in the OSM database, so the impact on processing and routing will be minimal.
This commit is contained in:
parent
8e74b7af9d
commit
a98074a051
@ -44,6 +44,7 @@
|
||||
- CHANGED: Lazily generate optional route path data [#6045](https://github.com/Project-OSRM/osrm-backend/pull/6045)
|
||||
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
|
||||
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
|
||||
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
|
||||
|
||||
# 5.26.0
|
||||
- Changes from 5.25.0
|
||||
|
@ -230,3 +230,100 @@ Feature: Maneuver tag support
|
||||
| waypoints | route | turns |
|
||||
| z,t | NY Ave,395,395 | depart,on ramp left,arrive |
|
||||
| z,b | NY Ave,,4th St,4th St | depart,on ramp left,fork slight right,arrive |
|
||||
|
||||
Scenario: Gracefully handles maneuvers that are redundant for the profile
|
||||
Given the node map
|
||||
"""
|
||||
a--b---c---d----f
|
||||
|
|
||||
|
|
||||
e
|
||||
"""
|
||||
And the ways
|
||||
| nodes | name | oneway | highway |
|
||||
| abc | A Street | no | primary |
|
||||
| ce | B Street | no | construction |
|
||||
| cdf | A Street | no | primary |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:to | maneuver | direction |
|
||||
| maneuver | abc | c | cdf | turn | slight_left |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,f | A Street,A Street | depart,arrive |
|
||||
|
||||
Scenario: Handles uncompressed nodes in maneuver path
|
||||
Given the node map
|
||||
"""
|
||||
a--b---c---f
|
||||
| |
|
||||
| |
|
||||
g d---h
|
||||
|
|
||||
|
|
||||
i-------e-------j
|
||||
"""
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| abc | A Street | no |
|
||||
| cf | B Street | no |
|
||||
| cde | C Street | no |
|
||||
| bg | D Street | no |
|
||||
| dh | E Street | no |
|
||||
| ei | F Street | no |
|
||||
| ej | G Street | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:via | way:to | maneuver | direction |
|
||||
| maneuver | abc | e | cde | ei | turn | sharp_right |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,i | A Street,C Street,F Street,F Street | depart,turn right,turn sharp right,arrive |
|
||||
|
||||
|
||||
Scenario: Can be used with turn restrictions
|
||||
Given the node map
|
||||
"""
|
||||
a---b---c
|
||||
|
|
||||
|
|
||||
d
|
||||
|
|
||||
e---f
|
||||
|
|
||||
|
|
||||
h------g---i
|
||||
"""
|
||||
And the ways
|
||||
| nodes | name | oneway |
|
||||
| ab | A Street | no |
|
||||
| bc | B Street | no |
|
||||
| bde | C Street | no |
|
||||
| ef | D Street | no |
|
||||
| eg | E Street | no |
|
||||
| hg | F Street | no |
|
||||
| gi | G Street | no |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:to | maneuver | direction | # |
|
||||
| maneuver | ab | b | bde | turn | sharp_right | ending on a turn restriction via way |
|
||||
| maneuver | bde | e | ef | turn | sharp_left | starting on a turn restriction via way |
|
||||
|
||||
And the relations
|
||||
| type | way:from | node:via | way:via | way:to | maneuver | direction | # |
|
||||
| maneuver | cb | g | bde,eg | gi | turn | slight_left | turn restricted |
|
||||
| maneuver | cb | g | bde,eg | hg | turn | slight_right | not turn restricted |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:via | way:to | restriction |
|
||||
| restriction | ab | bde,eg | hg | no_right_turn |
|
||||
| restriction | bc | bde,eg | gi | no_left_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | A Street,C Street,C Street | depart,turn sharp right,arrive |
|
||||
| b,f | C Street,D Street,D Street | depart,turn sharp left,arrive |
|
||||
| c,h | B Street,E Street,F Street,F Street | depart,turn left,turn slight right,arrive |
|
||||
| c,i | B Street,A Street,E Street,G Street,G Street | depart,turn uturn,turn right,end of road left,arrive |
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <memory>
|
||||
@ -18,6 +17,7 @@ namespace extractor
|
||||
|
||||
class CompressedEdgeContainer;
|
||||
struct TurnRestriction;
|
||||
struct UnresolvedManeuverOverride;
|
||||
|
||||
class GraphCompressor
|
||||
{
|
||||
|
@ -5,9 +5,13 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "storage/shared_memory_ownership.hpp"
|
||||
#include "turn_path.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/vector_view.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@ -17,7 +21,7 @@ namespace extractor
|
||||
// Data that is loaded from the OSM datafile directly
|
||||
struct InputManeuverOverride
|
||||
{
|
||||
std::vector<OSMWayID> via_ways;
|
||||
InputTurnPath turn_path;
|
||||
OSMNodeID via_node;
|
||||
std::string maneuver;
|
||||
std::string direction;
|
||||
@ -26,9 +30,7 @@ struct InputManeuverOverride
|
||||
// Object returned by the datafacade
|
||||
struct ManeuverOverride
|
||||
{
|
||||
// util::ViewOrVector<NodeID, storage::Ownership::View> node_sequence;
|
||||
std::vector<NodeID> node_sequence;
|
||||
// before the turn, then later, the edge_based_node_id of the turn
|
||||
NodeID instruction_node; // node-based node ID
|
||||
guidance::TurnType::Enum override_type;
|
||||
guidance::DirectionModifier::Enum direction;
|
||||
@ -40,12 +42,12 @@ struct StorageManeuverOverride
|
||||
std::uint32_t node_sequence_offset_begin;
|
||||
std::uint32_t node_sequence_offset_end;
|
||||
NodeID start_node;
|
||||
// before the turn, then later, the edge_based_node_id of the turn
|
||||
NodeID instruction_node; // node-based node ID
|
||||
guidance::TurnType::Enum override_type;
|
||||
guidance::DirectionModifier::Enum direction;
|
||||
};
|
||||
|
||||
// Used to identify maneuver turns whilst generating edge-based graph
|
||||
struct NodeBasedTurn
|
||||
{
|
||||
NodeID from;
|
||||
@ -58,29 +60,88 @@ struct NodeBasedTurn
|
||||
}
|
||||
};
|
||||
|
||||
// Internal representation of maneuvers during graph extraction phase
|
||||
struct UnresolvedManeuverOverride
|
||||
{
|
||||
|
||||
std::vector<NodeBasedTurn>
|
||||
turn_sequence; // initially the internal node-based-node ID of the node
|
||||
// before the turn, then later, the edge_based_node_id of the turn
|
||||
// The turn sequence that the maneuver override applies to.
|
||||
TurnPath turn_path;
|
||||
NodeID instruction_node; // node-based node ID
|
||||
guidance::TurnType::Enum override_type;
|
||||
guidance::DirectionModifier::Enum direction;
|
||||
|
||||
UnresolvedManeuverOverride()
|
||||
{
|
||||
turn_path = {ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}};
|
||||
instruction_node = SPECIAL_NODEID;
|
||||
override_type = guidance::TurnType::Invalid;
|
||||
direction = guidance::DirectionModifier::MaxDirectionModifier;
|
||||
}
|
||||
|
||||
// check if all parts of the restriction reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return !turn_sequence.empty() &&
|
||||
std::none_of(turn_sequence.begin(),
|
||||
turn_sequence.end(),
|
||||
[](const auto &n) {
|
||||
return n.from == SPECIAL_NODEID || n.via == SPECIAL_NODEID ||
|
||||
n.to == SPECIAL_NODEID;
|
||||
}) &&
|
||||
(direction != guidance::DirectionModifier::MaxDirectionModifier ||
|
||||
override_type != guidance::TurnType::Invalid);
|
||||
if ((direction == guidance::DirectionModifier::MaxDirectionModifier &&
|
||||
override_type == guidance::TurnType::Invalid) ||
|
||||
instruction_node == SPECIAL_NODEID || !turn_path.Valid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
const auto node_path = turn_path.AsViaNodePath();
|
||||
if (node_path.via != instruction_node)
|
||||
{
|
||||
util::Log(logDEBUG) << "Maneuver via-node " << node_path.via
|
||||
<< " does not match instruction node " << instruction_node;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
const auto way_path = turn_path.AsViaWayPath();
|
||||
|
||||
if (std::find(way_path.via.begin(), way_path.via.end(), instruction_node) ==
|
||||
way_path.via.end())
|
||||
{
|
||||
util::Log(logDEBUG) << "Maneuver via-way path does not contain instruction node "
|
||||
<< instruction_node;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate sequence of node-based-node turns. Used to identify the maneuver's edge-based-node
|
||||
// turns during graph expansion.
|
||||
std::vector<NodeBasedTurn> Turns() const
|
||||
{
|
||||
if (turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
const auto node_maneuver = turn_path.AsViaNodePath();
|
||||
return {{node_maneuver.from, node_maneuver.via, node_maneuver.to}};
|
||||
}
|
||||
|
||||
BOOST_ASSERT(turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
std::vector<NodeBasedTurn> result;
|
||||
const auto way_maneuver = turn_path.AsViaWayPath();
|
||||
BOOST_ASSERT(way_maneuver.via.size() >= 2);
|
||||
result.push_back({way_maneuver.from, way_maneuver.via[0], way_maneuver.via[1]});
|
||||
|
||||
for (auto i : util::irange<size_t>(0, way_maneuver.via.size() - 2))
|
||||
{
|
||||
result.push_back(
|
||||
{way_maneuver.via[i], way_maneuver.via[i + 1], way_maneuver.via[i + 2]});
|
||||
}
|
||||
result.push_back({way_maneuver.via[way_maneuver.via.size() - 2],
|
||||
way_maneuver.via.back(),
|
||||
way_maneuver.to});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string Name() { return "maneuver override"; };
|
||||
};
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "mapbox/variant.hpp"
|
||||
#include "turn_path.hpp"
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
@ -13,282 +14,54 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// OSM offers two types of restrictions, via node and via-way restrictions. We parse both into the
|
||||
// same input container
|
||||
//
|
||||
// A restriction turning at a single node. This is the most common type of restriction:
|
||||
//
|
||||
// a - b - c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// ab via b to bd
|
||||
struct InputNodeRestriction
|
||||
{
|
||||
OSMWayID from;
|
||||
OSMNodeID via;
|
||||
OSMWayID to;
|
||||
};
|
||||
|
||||
// A restriction that uses one or more via-way in between
|
||||
//
|
||||
// e - f - g
|
||||
// |
|
||||
// d
|
||||
// |
|
||||
// a - b - c
|
||||
//
|
||||
// ab via bd,df to fe -- no u turn
|
||||
struct InputWayRestriction
|
||||
{
|
||||
OSMWayID from;
|
||||
std::vector<OSMWayID> via;
|
||||
OSMWayID to;
|
||||
};
|
||||
|
||||
// Outside view of the variant, these are equal to the `which()` results
|
||||
enum RestrictionType
|
||||
{
|
||||
NODE_RESTRICTION = 0,
|
||||
WAY_RESTRICTION = 1,
|
||||
NUM_RESTRICTION_TYPES = 2
|
||||
};
|
||||
|
||||
// External (OSM) representation of restriction
|
||||
struct InputTurnRestriction
|
||||
{
|
||||
// keep in the same order as the turn restrictions below
|
||||
mapbox::util::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
|
||||
InputTurnPath turn_path;
|
||||
bool is_only;
|
||||
// We represent conditional and unconditional restrictions with the same structure.
|
||||
// Unconditional restrictions will have empty conditions.
|
||||
std::vector<util::OpeningHours> condition;
|
||||
|
||||
OSMWayID From() const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? mapbox::util::get<InputNodeRestriction>(node_or_way).from
|
||||
: mapbox::util::get<InputWayRestriction>(node_or_way).from;
|
||||
}
|
||||
|
||||
OSMWayID To() const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? mapbox::util::get<InputNodeRestriction>(node_or_way).to
|
||||
: mapbox::util::get<InputWayRestriction>(node_or_way).to;
|
||||
}
|
||||
|
||||
RestrictionType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
|
||||
return static_cast<RestrictionType>(node_or_way.which());
|
||||
}
|
||||
|
||||
InputWayRestriction &AsWayRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return mapbox::util::get<InputWayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const InputWayRestriction &AsWayRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return mapbox::util::get<InputWayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
InputNodeRestriction &AsNodeRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return mapbox::util::get<InputNodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const InputNodeRestriction &AsNodeRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return mapbox::util::get<InputNodeRestriction>(node_or_way);
|
||||
}
|
||||
};
|
||||
|
||||
// OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note
|
||||
// that this has the side-effect of not allowing parallel edges!
|
||||
//
|
||||
// a - b - c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// ab via b to bd
|
||||
struct NodeRestriction
|
||||
{
|
||||
NodeID from;
|
||||
NodeID via;
|
||||
NodeID to;
|
||||
|
||||
// check if all parts of the restriction reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID;
|
||||
};
|
||||
|
||||
bool operator==(const NodeRestriction &other) const
|
||||
{
|
||||
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
|
||||
}
|
||||
};
|
||||
|
||||
// A way restriction in the context of OSRM requires translation into NodeIDs. This is due to the
|
||||
// compression happening in the graph creation process which would make it difficult to track
|
||||
// way-ids over a series of operations. Having access to the nodes directly allows look-up of the
|
||||
// edges in the processed structures
|
||||
//
|
||||
// e - f - g
|
||||
// |
|
||||
// d
|
||||
// |
|
||||
// a - b - c
|
||||
//
|
||||
// ab via bd,df to fe -- no u turn
|
||||
struct WayRestriction
|
||||
{
|
||||
// A way restriction in OSRM needs to track all nodes that make up the via ways. Whilst most
|
||||
// of these nodes will be removed by compression, some nodes will contain features that need to
|
||||
// be considered when routing (e.g. intersections, nested restrictions, etc).
|
||||
NodeID from;
|
||||
std::vector<NodeID> via;
|
||||
NodeID to;
|
||||
|
||||
// check if all parts of the restriction reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via.size() >= 2 &&
|
||||
std::all_of(via.begin(), via.end(), [](NodeID i) { return i != SPECIAL_NODEID; });
|
||||
};
|
||||
|
||||
bool operator==(const WayRestriction &other) const
|
||||
{
|
||||
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper for turn restrictions that gives more information on its type / handles the switch
|
||||
// between node/way restrictions
|
||||
// Internal (OSRM) representation of restriction
|
||||
struct TurnRestriction
|
||||
{
|
||||
// keep in the same order as the turn restrictions above
|
||||
mapbox::util::variant<NodeRestriction, WayRestriction> node_or_way;
|
||||
// The turn sequence that the restriction applies to.
|
||||
TurnPath turn_path;
|
||||
// Indicates if the restriction turn *must* or *must not* be taken.
|
||||
bool is_only;
|
||||
// We represent conditional and unconditional restrictions with the same structure.
|
||||
// Unconditional restrictions will have empty conditions.
|
||||
std::vector<util::OpeningHours> condition;
|
||||
|
||||
// construction for NodeRestrictions
|
||||
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
|
||||
: node_or_way(node_restriction), is_only(is_only)
|
||||
{
|
||||
}
|
||||
|
||||
// construction for WayRestrictions
|
||||
explicit TurnRestriction(const WayRestriction &way_restriction, bool is_only = false)
|
||||
: node_or_way(way_restriction), is_only(is_only)
|
||||
explicit TurnRestriction(const TurnPath &turn_path, bool is_only = false)
|
||||
: turn_path(turn_path), is_only(is_only)
|
||||
{
|
||||
}
|
||||
|
||||
explicit TurnRestriction()
|
||||
{
|
||||
node_or_way = NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
turn_path = {ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}};
|
||||
}
|
||||
|
||||
NodeID To() const
|
||||
bool IsTurnRestricted(NodeID to) const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? mapbox::util::get<NodeRestriction>(node_or_way).to
|
||||
: mapbox::util::get<WayRestriction>(node_or_way).to;
|
||||
return is_only ? turn_path.To() != to : turn_path.To() == to;
|
||||
}
|
||||
|
||||
NodeID From() const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? mapbox::util::get<NodeRestriction>(node_or_way).from
|
||||
: mapbox::util::get<WayRestriction>(node_or_way).from;
|
||||
}
|
||||
|
||||
NodeID FirstVia() const
|
||||
{
|
||||
if (node_or_way.which() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
return mapbox::util::get<NodeRestriction>(node_or_way).via;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(!mapbox::util::get<WayRestriction>(node_or_way).via.empty());
|
||||
return mapbox::util::get<WayRestriction>(node_or_way).via[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTurnRestricted(NodeID to) const { return is_only ? To() != to : To() == to; }
|
||||
|
||||
bool IsUnconditional() const { return condition.empty(); }
|
||||
|
||||
WayRestriction &AsWayRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return mapbox::util::get<WayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const WayRestriction &AsWayRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return mapbox::util::get<WayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
NodeRestriction &AsNodeRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return mapbox::util::get<NodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const NodeRestriction &AsNodeRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return mapbox::util::get<NodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
RestrictionType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
|
||||
return static_cast<RestrictionType>(node_or_way.which());
|
||||
}
|
||||
|
||||
// check if all elements of the edge are considered valid
|
||||
bool Valid() const
|
||||
{
|
||||
if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
auto const &restriction = AsWayRestriction();
|
||||
return restriction.Valid();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const &restriction = AsNodeRestriction();
|
||||
return restriction.Valid();
|
||||
}
|
||||
}
|
||||
bool Valid() const { return turn_path.Valid(); }
|
||||
|
||||
bool operator==(const TurnRestriction &other) const
|
||||
{
|
||||
if (is_only != other.is_only)
|
||||
return false;
|
||||
|
||||
if (Type() != other.Type())
|
||||
return false;
|
||||
|
||||
if (Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
return AsWayRestriction() == other.AsWayRestriction();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AsNodeRestriction() == other.AsNodeRestriction();
|
||||
}
|
||||
return turn_path == other.turn_path;
|
||||
}
|
||||
|
||||
static std::string Name() { return "turn restriction"; };
|
||||
};
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
@ -1,56 +0,0 @@
|
||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct NodeRestriction;
|
||||
struct TurnRestriction;
|
||||
|
||||
// OSRM stores restrictions as node -> [node] -> node instead of way -> node -> way (or
|
||||
// way->[way]->way) as it is done in OSM. These restrictions need to match the state of graph
|
||||
// compression which we perform in the graph compressor that removes certain degree two nodes from
|
||||
// the graph (all but the ones with penalties/barriers, as of the state of writing).
|
||||
// Since this graph compression ins performed after creating the restrictions in the extraction
|
||||
// phase, we need to update the involved nodes whenever one of the nodes is compressed.
|
||||
//
|
||||
//
|
||||
// !!!! Will bind to the restrictions vector and modify it in-place !!!!
|
||||
class RestrictionCompressor
|
||||
{
|
||||
public:
|
||||
RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
|
||||
|
||||
// account for the compression of `from-via-to` into `from-to`
|
||||
void Compress(const NodeID from, const NodeID via, const NodeID to);
|
||||
|
||||
private:
|
||||
// A turn restriction is given as `from star via node to end`. Edges ending at `head` being
|
||||
// contracted move the head pointer to their respective head. Edges starting at tail move the
|
||||
// tail values to their respective tails.
|
||||
// Via nodes that are compressed are removed from the restriction representation.
|
||||
// We do not compress the first and last via nodes of a restriction as they act as
|
||||
// entrance/exit points into the restriction graph. For a node restriction, the first and last
|
||||
// via nodes are the same.
|
||||
boost::unordered_multimap<NodeID, TurnRestriction *> starts;
|
||||
boost::unordered_multimap<NodeID, TurnRestriction *> vias;
|
||||
boost::unordered_multimap<NodeID, TurnRestriction *> ends;
|
||||
|
||||
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_starts;
|
||||
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_ends;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
@ -1,22 +0,0 @@
|
||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_FILTER_HPP_
|
||||
#define OSRM_EXTRACTOR_RESTRICTION_FILTER_HPP_
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do
|
||||
// a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as
|
||||
// `restrictions = removeInvalidRestrictions(std::move(restrictions))`
|
||||
std::vector<TurnRestriction> removeInvalidRestrictions(std::vector<TurnRestriction>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_RESTRICTION_FILTER_HPP_
|
@ -4,7 +4,6 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@ -13,6 +12,8 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct TurnRestriction;
|
||||
|
||||
namespace restriction_graph_details
|
||||
{
|
||||
struct transferBuilder;
|
||||
|
269
include/extractor/turn_path.hpp
Normal file
269
include/extractor/turn_path.hpp
Normal file
@ -0,0 +1,269 @@
|
||||
#ifndef OSRM_TURN_PATH_HPP
|
||||
#define OSRM_TURN_PATH_HPP
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// Outside view of the variant, these are equal to the `which()` results
|
||||
enum TurnPathType
|
||||
{
|
||||
VIA_NODE_TURN_PATH = 0,
|
||||
VIA_WAY_TURN_PATH = 1,
|
||||
NUM_TURN_PATH_TYPES = 2
|
||||
};
|
||||
|
||||
// OSM turn restrictions and maneuver overrides are relations that use the same path
|
||||
// representation. Therefore, we can represent these paths by a shared, common structure.
|
||||
//
|
||||
// from: the way from which the turn sequence begins
|
||||
// via: a node or list of ways, representing the intermediate path taken in the turn sequence
|
||||
// to: the final way in the turn sequence
|
||||
//
|
||||
// We will have two representations of the paths, via-node and via-way, to represent the two options
|
||||
// for the intermediate path. We parse both into the same input container
|
||||
|
||||
//
|
||||
// A path turning at a single node. This is the most common type of relation:
|
||||
//
|
||||
// a - b - c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// ab via b to bd
|
||||
struct InputViaNodePath
|
||||
{
|
||||
OSMWayID from;
|
||||
OSMNodeID via;
|
||||
OSMWayID to;
|
||||
};
|
||||
|
||||
// A turn path that uses one or more via-way in between
|
||||
//
|
||||
// e - f - g
|
||||
// |
|
||||
// d
|
||||
// |
|
||||
// a - b - c
|
||||
//
|
||||
// ab via bd,df to fe
|
||||
struct InputViaWayPath
|
||||
{
|
||||
OSMWayID from;
|
||||
std::vector<OSMWayID> via;
|
||||
OSMWayID to;
|
||||
};
|
||||
|
||||
struct InputTurnPath
|
||||
{
|
||||
mapbox::util::variant<InputViaNodePath, InputViaWayPath> node_or_way;
|
||||
|
||||
TurnPathType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < TurnPathType::NUM_TURN_PATH_TYPES);
|
||||
return static_cast<TurnPathType>(node_or_way.which());
|
||||
}
|
||||
|
||||
OSMWayID From() const
|
||||
{
|
||||
return node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH
|
||||
? mapbox::util::get<InputViaNodePath>(node_or_way).from
|
||||
: mapbox::util::get<InputViaWayPath>(node_or_way).from;
|
||||
}
|
||||
|
||||
OSMWayID To() const
|
||||
{
|
||||
return node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH
|
||||
? mapbox::util::get<InputViaNodePath>(node_or_way).to
|
||||
: mapbox::util::get<InputViaWayPath>(node_or_way).to;
|
||||
}
|
||||
|
||||
InputViaWayPath &AsViaWayPath()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return mapbox::util::get<InputViaWayPath>(node_or_way);
|
||||
}
|
||||
|
||||
const InputViaWayPath &AsViaWayPath() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return mapbox::util::get<InputViaWayPath>(node_or_way);
|
||||
}
|
||||
|
||||
InputViaNodePath &AsViaNodePath()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
return mapbox::util::get<InputViaNodePath>(node_or_way);
|
||||
}
|
||||
|
||||
const InputViaNodePath &AsViaNodePath() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
return mapbox::util::get<InputViaNodePath>(node_or_way);
|
||||
}
|
||||
};
|
||||
|
||||
// Internally, we convert the turn paths into a node-based-node representation.
|
||||
// This allows us to correctly track the edges as they processed, such as during graph compression.
|
||||
// Having access to the nodes directly allows look-up of the edges in the processed structures,
|
||||
// and can be utilised during edge-based-graph generation.
|
||||
//
|
||||
// Once again, we keep two representations of the paths, via-node and via-way, for more efficient
|
||||
// representation of the more common via-node path.
|
||||
//
|
||||
// a - b - c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// a via b to d
|
||||
struct ViaNodePath
|
||||
{
|
||||
NodeID from;
|
||||
NodeID via;
|
||||
NodeID to;
|
||||
|
||||
// check if all parts of the restriction reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID;
|
||||
};
|
||||
|
||||
bool operator==(const ViaNodePath &other) const
|
||||
{
|
||||
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
// e - f - g
|
||||
// |
|
||||
// d
|
||||
// |
|
||||
// a - b - c
|
||||
//
|
||||
// a via bdf to e
|
||||
// (after compression) a via bf to e
|
||||
struct ViaWayPath
|
||||
{
|
||||
// A way path in OSRM needs to track all nodes that make up the via ways. Whilst most
|
||||
// of these nodes will be removed by compression, some nodes will contain features that need to
|
||||
// be considered when routing (e.g. intersections, nested restrictions, etc).
|
||||
NodeID from;
|
||||
std::vector<NodeID> via;
|
||||
NodeID to;
|
||||
|
||||
// check if all parts of the path reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via.size() >= 2 &&
|
||||
std::all_of(via.begin(), via.end(), [](NodeID i) { return i != SPECIAL_NODEID; });
|
||||
};
|
||||
|
||||
bool operator==(const ViaWayPath &other) const
|
||||
{
|
||||
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper for turn paths that gives more information on its type / handles the switch
|
||||
// between node/way paths
|
||||
struct TurnPath
|
||||
{
|
||||
mapbox::util::variant<ViaNodePath, ViaWayPath> node_or_way;
|
||||
|
||||
NodeID To() const
|
||||
{
|
||||
return node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH
|
||||
? mapbox::util::get<ViaNodePath>(node_or_way).to
|
||||
: mapbox::util::get<ViaWayPath>(node_or_way).to;
|
||||
}
|
||||
|
||||
NodeID From() const
|
||||
{
|
||||
return node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH
|
||||
? mapbox::util::get<ViaNodePath>(node_or_way).from
|
||||
: mapbox::util::get<ViaWayPath>(node_or_way).from;
|
||||
}
|
||||
|
||||
NodeID FirstVia() const
|
||||
{
|
||||
if (node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
return mapbox::util::get<ViaNodePath>(node_or_way).via;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(!mapbox::util::get<ViaWayPath>(node_or_way).via.empty());
|
||||
return mapbox::util::get<ViaWayPath>(node_or_way).via[0];
|
||||
}
|
||||
}
|
||||
|
||||
ViaWayPath &AsViaWayPath()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return mapbox::util::get<ViaWayPath>(node_or_way);
|
||||
}
|
||||
|
||||
const ViaWayPath &AsViaWayPath() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return mapbox::util::get<ViaWayPath>(node_or_way);
|
||||
}
|
||||
|
||||
ViaNodePath &AsViaNodePath()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
return mapbox::util::get<ViaNodePath>(node_or_way);
|
||||
}
|
||||
|
||||
const ViaNodePath &AsViaNodePath() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
return mapbox::util::get<ViaNodePath>(node_or_way);
|
||||
}
|
||||
|
||||
TurnPathType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < TurnPathType::NUM_TURN_PATH_TYPES);
|
||||
return static_cast<TurnPathType>(node_or_way.which());
|
||||
}
|
||||
|
||||
bool operator==(const TurnPath &other) const
|
||||
{
|
||||
if (Type() != other.Type())
|
||||
return false;
|
||||
|
||||
if (Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
return AsViaWayPath() == other.AsViaWayPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AsViaNodePath() == other.AsViaNodePath();
|
||||
}
|
||||
}
|
||||
|
||||
bool Valid() const
|
||||
{
|
||||
if (Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
return AsViaWayPath().Valid();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AsViaNodePath().Valid();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
#endif // OSRM_TURN_PATH_HPP
|
54
include/extractor/turn_path_compressor.hpp
Normal file
54
include/extractor/turn_path_compressor.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef OSRM_EXTRACTOR_TURN_PATH_COMPRESSOR_HPP_
|
||||
#define OSRM_EXTRACTOR_TURN_PATH_COMPRESSOR_HPP_
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct TurnPath;
|
||||
struct TurnRestriction;
|
||||
struct UnresolvedManeuverOverride;
|
||||
|
||||
// OSRM stores turn paths as node -> [node] -> node instead of way -> node -> way (or
|
||||
// way->[way]->way) as it is done in OSM. These paths need to match the state of graph
|
||||
// compression which we perform in the graph compressor that removes certain degree two nodes from
|
||||
// the graph (all but the ones with penalties/barriers, as of the state of writing).
|
||||
// Since this graph compression is performed after creating the turn paths in the extraction
|
||||
// phase, we need to update the involved nodes whenever one of the nodes is compressed.
|
||||
//
|
||||
//
|
||||
// !!!! Will bind to the restriction/maneuver vectors and modify it in-place !!!!
|
||||
class TurnPathCompressor
|
||||
{
|
||||
public:
|
||||
TurnPathCompressor(std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
|
||||
|
||||
// account for the compression of `from-via-to` into `from-to`
|
||||
void Compress(const NodeID from, const NodeID via, const NodeID to);
|
||||
|
||||
private:
|
||||
// A turn path is given as `from start via node(s) to end`. Edges ending at `head` being
|
||||
// contracted move the head pointer to their respective head. Edges starting at tail move the
|
||||
// tail values to their respective tails.
|
||||
// Via nodes that are compressed are removed from the restriction representation.
|
||||
// We do not compress the first and last via nodes of a restriction as they act as
|
||||
// entrance/exit points into the restriction graph. For a node restriction, the first and last
|
||||
// via nodes are the same.
|
||||
// Similarly, we do not compress the instruction via node in a maneuver override, as we need
|
||||
// this to identify the location of the maneuver during routing path-processing.
|
||||
boost::unordered_multimap<NodeID, TurnPath *> starts;
|
||||
boost::unordered_multimap<NodeID, TurnPath *> vias;
|
||||
boost::unordered_multimap<NodeID, TurnPath *> ends;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_TURN_PATH_COMPRESSOR_HPP_
|
22
include/extractor/turn_path_filter.hpp
Normal file
22
include/extractor/turn_path_filter.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef OSRM_EXTRACTOR_TURN_PATH_FILTER_HPP_
|
||||
#define OSRM_EXTRACTOR_TURN_PATH_FILTER_HPP_
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// To avoid handling invalid turn paths / creating unnecessary duplicate nodes for via-ways, we do
|
||||
// a pre-flight check for paths and remove all invalid turn relations from the data. Use as
|
||||
// `restrictions = removeInvalidRestrictions(std::move(restrictions))`
|
||||
template <typename T>
|
||||
std::vector<T> removeInvalidTurnPaths(std::vector<T>, const util::NodeBasedDynamicGraph &);
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_TURN_PATH_FILTER_HPP_
|
@ -10,24 +10,19 @@
|
||||
#include "storage/io.hpp"
|
||||
|
||||
#include "util/assert.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/connectivity_checksum.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/percent.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/crc.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@ -451,6 +446,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
{
|
||||
util::Log() << "Generating edge-expanded edges ";
|
||||
|
||||
// Keep a set of all maneuver turns so we can identify them as
|
||||
// we generate the edge-expansion.
|
||||
std::unordered_set<NodeBasedTurn> unresolved_turns;
|
||||
for (const auto &manuevers : unresolved_maneuver_overrides)
|
||||
{
|
||||
for (const auto &turn : manuevers.Turns())
|
||||
{
|
||||
unresolved_turns.insert(turn);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t node_based_edge_counter = 0;
|
||||
|
||||
SuffixTable street_name_suffix_table(scripting_environment);
|
||||
@ -514,7 +520,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
std::vector<EdgeWithData> delayed_data; // may need this
|
||||
std::vector<Conditional> conditionals;
|
||||
|
||||
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
|
||||
std::unordered_multimap<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
|
||||
|
||||
util::ConnectivityChecksum checksum;
|
||||
};
|
||||
@ -522,7 +528,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
m_connectivity_checksum = 0;
|
||||
|
||||
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
|
||||
std::unordered_multimap<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
|
||||
|
||||
// going over all nodes (which form the center of an intersection), we compute all possible
|
||||
// turns along these intersections.
|
||||
@ -894,24 +900,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto outgoing_edge_target =
|
||||
m_node_based_graph.GetTarget(outgoing_edge.edge);
|
||||
|
||||
// TODO: this loop is not optimized - once we have a few
|
||||
// overrides available, we should index this for faster
|
||||
// lookups
|
||||
for (auto &override : unresolved_maneuver_overrides)
|
||||
const auto turn_nodes = NodeBasedTurn{
|
||||
incoming_edge.node, intersection_node, outgoing_edge_target};
|
||||
const auto is_maneuver_turn = unresolved_turns.count(turn_nodes) > 0;
|
||||
|
||||
if (is_maneuver_turn)
|
||||
{
|
||||
for (auto &turn : override.turn_sequence)
|
||||
{
|
||||
if (turn.from == incoming_edge.node &&
|
||||
turn.via == intersection_node &&
|
||||
turn.to == outgoing_edge_target)
|
||||
{
|
||||
const auto &ebn_from =
|
||||
nbe_to_ebn_mapping[incoming_edge.edge];
|
||||
const auto &ebn_to = target_id;
|
||||
buffer->turn_to_ebn_map[turn] =
|
||||
std::make_pair(ebn_from, ebn_to);
|
||||
}
|
||||
}
|
||||
const auto &ebn_from = nbe_to_ebn_mapping[incoming_edge.edge];
|
||||
const auto &ebn_to = target_id;
|
||||
buffer->turn_to_ebn_map.insert(
|
||||
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
|
||||
}
|
||||
|
||||
{ // scope to forget edge_with_data after
|
||||
@ -1025,6 +1023,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
m_coordinates[intersection_node],
|
||||
restriction->condition}});
|
||||
}
|
||||
|
||||
// We also need to track maneuvers that traverse duplicate
|
||||
// edges
|
||||
if (is_maneuver_turn)
|
||||
{
|
||||
const auto &ebn_from = from_id;
|
||||
const auto &ebn_to = via_target_id;
|
||||
buffer->turn_to_ebn_map.insert(
|
||||
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1053,6 +1061,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
edge_geometries);
|
||||
|
||||
buffer->delayed_data.push_back(edge_with_data);
|
||||
|
||||
// We also need to track maneuvers that traverse duplicate
|
||||
// edges
|
||||
if (is_maneuver_turn)
|
||||
{
|
||||
const auto &ebn_from = from_id;
|
||||
const auto &ebn_to = via_target_id;
|
||||
buffer->turn_to_ebn_map.insert(
|
||||
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1107,35 +1125,64 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// Now, replace node-based-node ID values in the `node_sequence` with
|
||||
// the edge-based-node values we found and stored in the `turn_to_ebn_map`
|
||||
for (auto &unresolved_override : unresolved_maneuver_overrides)
|
||||
for (const auto &unresolved_override : unresolved_maneuver_overrides)
|
||||
{
|
||||
StorageManeuverOverride storage_override;
|
||||
storage_override.instruction_node = unresolved_override.instruction_node;
|
||||
storage_override.override_type = unresolved_override.override_type;
|
||||
storage_override.direction = unresolved_override.direction;
|
||||
// There can be multiple edge-based-node sequences for a node-based-turn sequence
|
||||
// due to duplicate edges in the restriction graph.
|
||||
std::vector<std::vector<NodeID>> node_sequences;
|
||||
|
||||
std::vector<NodeID> node_sequence(unresolved_override.turn_sequence.size() + 1,
|
||||
SPECIAL_NODEID);
|
||||
const auto &turns = unresolved_override.Turns();
|
||||
|
||||
for (std::int64_t i = unresolved_override.turn_sequence.size() - 1; i >= 0; --i)
|
||||
{
|
||||
const auto v = global_turn_to_ebn_map.find(unresolved_override.turn_sequence[i]);
|
||||
if (v != global_turn_to_ebn_map.end())
|
||||
BOOST_ASSERT(!turns.empty());
|
||||
// Populate the node sequences with the first turn values.
|
||||
const auto first_turn_edges = global_turn_to_ebn_map.equal_range(turns[0]);
|
||||
std::transform(
|
||||
first_turn_edges.first,
|
||||
first_turn_edges.second,
|
||||
std::back_inserter(node_sequences),
|
||||
[](const auto turn_edges) {
|
||||
return std::vector<NodeID>{turn_edges.second.first, turn_edges.second.second};
|
||||
});
|
||||
|
||||
std::for_each(std::next(turns.begin()), turns.end(), [&](const auto &turn) {
|
||||
std::vector<std::vector<NodeID>> next_node_sequences;
|
||||
const auto next_turn_edges = global_turn_to_ebn_map.equal_range(turn);
|
||||
for (auto &node_sequence : node_sequences)
|
||||
{
|
||||
node_sequence[i] = v->second.first;
|
||||
node_sequence[i + 1] = v->second.second;
|
||||
const auto found_it = std::find_if(
|
||||
next_turn_edges.first, next_turn_edges.second, [&](const auto &turn_edges) {
|
||||
const auto pre_turn_edge = turn_edges.second.first;
|
||||
return (node_sequence.back() == pre_turn_edge);
|
||||
});
|
||||
|
||||
if (found_it != next_turn_edges.second)
|
||||
{
|
||||
const auto post_turn_edge = found_it->second.second;
|
||||
node_sequence.push_back(post_turn_edge);
|
||||
next_node_sequences.push_back(std::move(node_sequence));
|
||||
}
|
||||
}
|
||||
node_sequences = std::move(next_node_sequences);
|
||||
});
|
||||
|
||||
for (const auto &node_sequence : node_sequences)
|
||||
{
|
||||
StorageManeuverOverride storage_override;
|
||||
storage_override.instruction_node = unresolved_override.instruction_node;
|
||||
storage_override.override_type = unresolved_override.override_type;
|
||||
storage_override.direction = unresolved_override.direction;
|
||||
|
||||
storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
|
||||
storage_override.node_sequence_offset_end =
|
||||
maneuver_override_sequences.size() + node_sequence.size();
|
||||
|
||||
storage_override.start_node = node_sequence.front();
|
||||
|
||||
maneuver_override_sequences.insert(
|
||||
maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
|
||||
|
||||
storage_maneuver_overrides.push_back(storage_override);
|
||||
}
|
||||
storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
|
||||
storage_override.node_sequence_offset_end =
|
||||
maneuver_override_sequences.size() + node_sequence.size();
|
||||
|
||||
storage_override.start_node = node_sequence.front();
|
||||
|
||||
maneuver_override_sequences.insert(
|
||||
maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
|
||||
|
||||
storage_maneuver_overrides.push_back(storage_override);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
@ -152,6 +152,228 @@ std::tuple<OSMNodeID, OSMNodeID, OSMNodeID> find_turn_nodes(const oe::NodesOfWay
|
||||
}
|
||||
return std::make_tuple(SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID);
|
||||
}
|
||||
|
||||
// Via-node paths describe a relation between the two segments closest
|
||||
// to the shared via-node on the from and to ways.
|
||||
// from: [a, b, c, d, e]
|
||||
// to: [f, g, h, i, j]
|
||||
//
|
||||
// The via node establishes the orientation of the from/to intersection when choosing the
|
||||
// segments.
|
||||
// via | node path
|
||||
// a=f | b,a,g
|
||||
// a=j | b,a,i
|
||||
// e=f | d,e,g
|
||||
// e=j | d,e,i
|
||||
oe::ViaNodePath find_via_node_path(const std::string &turn_relation_type,
|
||||
const oe::NodesOfWay &from_segment,
|
||||
const oe::NodesOfWay &to_segment,
|
||||
const OSMNodeID via_node,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) = find_turn_nodes(from_segment, to_segment, via_node);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " references unconnected way: " << from_segment.way_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return oe::ViaNodePath{to_internal_node(from), to_internal_node(via), to_internal_node(to)};
|
||||
}
|
||||
|
||||
// Via way paths are comprised of:
|
||||
// 1. The segment in the from way that intersects with the via ways
|
||||
// 2. All segments that make up the via path
|
||||
// 3. The segment in the to way that intersects with the via path.
|
||||
//
|
||||
// from: [a, b, c, d, e]
|
||||
// via: [[f, g, h, i, j], [k, l], [m, n, o]]
|
||||
// to: [p, q, r, s]
|
||||
//
|
||||
// First establish the orientation of the from/via intersection by finding which end
|
||||
// nodes both ways share. From this we can select the from segment.
|
||||
//
|
||||
// intersect | from segment | next_connection
|
||||
// a=f | b,a | f
|
||||
// a=j | b,a | j
|
||||
// e=f | e,d | f
|
||||
// e=j | e,d | j
|
||||
//
|
||||
// Use the next connection to inform the orientation of the first via
|
||||
// way and the intersection between first and second via ways.
|
||||
//
|
||||
// next_connection | intersect | via result | next_next_connection
|
||||
// f | j=k | [f,g,h,i,j] | k
|
||||
// f | j=l | [f,g,h,i,j] | l
|
||||
// j | f=k | [j,i,h,g,f] | k
|
||||
// j | f=l | [j,i,h,g,f] | l
|
||||
//
|
||||
// This is continued for the remaining via ways, appending to the via result
|
||||
//
|
||||
// The final via/to intersection also uses the next_connection information in a similar fashion.
|
||||
//
|
||||
// next_connection | intersect | to_segment
|
||||
// m | o=p | p,q
|
||||
// m | o=s | s,r
|
||||
// o | m=p | p,q
|
||||
// o | m=s | s,r
|
||||
//
|
||||
// The final result is a list of nodes that represent a valid from->via->to path through the
|
||||
// ways.
|
||||
//
|
||||
// E.g. if intersection nodes are a=j, f=l, k=o, m=s
|
||||
// the result will be {e [d,c,b,a,i,h,g,f,k,n,m] r}
|
||||
oe::ViaWayPath find_via_way_path(const std::string &turn_relation_type,
|
||||
const oe::NodesOfWay &from_way,
|
||||
const std::vector<oe::NodesOfWay> &via_ways,
|
||||
const oe::NodesOfWay &to_way,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
BOOST_ASSERT(!via_ways.empty());
|
||||
|
||||
oe::ViaWayPath way_path;
|
||||
|
||||
// Find the orientation of the connected ways starting with the from-via intersection.
|
||||
OSMNodeID from, via;
|
||||
std::tie(from, via, std::ignore) =
|
||||
find_turn_nodes(from_way, via_ways.front(), SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " has unconnected from and via ways: " << from_way.way_id
|
||||
<< ", " << via_ways.front().way_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
way_path.from = to_internal_node(from);
|
||||
way_path.via.push_back(to_internal_node(via));
|
||||
|
||||
// Use the connection node from the previous intersection to inform our conversion of
|
||||
// via ways into internal nodes.
|
||||
OSMNodeID next_connection = via;
|
||||
for (const auto &via_way : via_ways)
|
||||
{
|
||||
if (next_connection == via_way.first_segment_source_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.begin()),
|
||||
via_way.node_ids.end(),
|
||||
std::back_inserter(way_path.via),
|
||||
to_internal_node);
|
||||
next_connection = via_way.last_segment_target_id();
|
||||
}
|
||||
else if (next_connection == via_way.last_segment_target_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.rbegin()),
|
||||
via_way.node_ids.rend(),
|
||||
std::back_inserter(way_path.via),
|
||||
to_internal_node);
|
||||
next_connection = via_way.first_segment_source_id();
|
||||
}
|
||||
else
|
||||
{
|
||||
osrm::util::Log(logDEBUG)
|
||||
<< turn_relation_type << " has unconnected via way: " << via_way.way_id
|
||||
<< " to node " << next_connection;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
}
|
||||
|
||||
// Add the final to node after the via-to intersection.
|
||||
if (next_connection == to_way.first_segment_source_id())
|
||||
{
|
||||
way_path.to = to_internal_node(to_way.first_segment_target_id());
|
||||
}
|
||||
else if (next_connection == to_way.last_segment_target_id())
|
||||
{
|
||||
way_path.to = to_internal_node(to_way.last_segment_source_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " has unconnected via and to ways: " << via_ways.back().way_id
|
||||
<< ", " << to_way.way_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
return way_path;
|
||||
}
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal via-way turn path
|
||||
oe::ViaWayPath
|
||||
get_via_way_path_from_OSM_ids(const std::string &turn_relation_type,
|
||||
const std::unordered_map<OSMWayID, oe::NodesOfWay> &referenced_ways,
|
||||
const OSMWayID from_id,
|
||||
const OSMWayID to_id,
|
||||
const std::vector<OSMWayID> &via_ids,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
auto const from_way_itr = referenced_ways.find(from_id);
|
||||
if (from_way_itr->second.way_id != from_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " references invalid from way: " << from_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
std::vector<oe::NodesOfWay> via_ways;
|
||||
for (const auto &via_id : via_ids)
|
||||
{
|
||||
auto const via_segment_itr = referenced_ways.find(via_id);
|
||||
if (via_segment_itr->second.way_id != via_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG)
|
||||
<< turn_relation_type << " references invalid via way: " << via_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
via_ways.push_back(via_segment_itr->second);
|
||||
}
|
||||
|
||||
auto const to_way_itr = referenced_ways.find(to_id);
|
||||
if (to_way_itr->second.way_id != to_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid to way: " << to_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_via_way_path(
|
||||
turn_relation_type, from_way_itr->second, via_ways, to_way_itr->second, to_internal_node);
|
||||
}
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal via-node turn path
|
||||
oe::ViaNodePath
|
||||
get_via_node_path_from_OSM_ids(const std::string &turn_relation_type,
|
||||
const std::unordered_map<OSMWayID, oe::NodesOfWay> &referenced_ways,
|
||||
const OSMWayID from_id,
|
||||
const OSMWayID to_id,
|
||||
const OSMNodeID via_node,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
|
||||
auto const from_segment_itr = referenced_ways.find(from_id);
|
||||
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid way: " << from_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = referenced_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid way: " << to_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_via_node_path(turn_relation_type,
|
||||
from_segment_itr->second,
|
||||
to_segment_itr->second,
|
||||
via_node,
|
||||
to_internal_node);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace osrm
|
||||
@ -177,10 +399,10 @@ ExtractionContainers::ExtractionContainers()
|
||||
* Processes the collected data and serializes it.
|
||||
* At this point nodes are still referenced by their OSM id.
|
||||
*
|
||||
* - map start-end nodes of ways to ways used in restrictions to compute compressed
|
||||
* trippe representation
|
||||
* - filter nodes list to nodes that are referenced by ways
|
||||
* - merge edges with nodes to include location of start/end points and serialize
|
||||
* - Identify nodes of ways used in restrictions and maneuver overrides
|
||||
* - Filter nodes list to nodes that are referenced by ways
|
||||
* - Prepare edges and compute routing properties
|
||||
* - Prepare and validate restrictions and maneuver overrides
|
||||
*
|
||||
*/
|
||||
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
|
||||
@ -723,11 +945,17 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
|
||||
|
||||
const auto mark_ids = [&](auto const &external_maneuver_override) {
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
std::for_each(external_maneuver_override.via_ways.begin(),
|
||||
external_maneuver_override.via_ways.end(),
|
||||
[&maneuver_override_ways, dummy_segment](const auto &element) {
|
||||
maneuver_override_ways[element] = dummy_segment;
|
||||
});
|
||||
const auto &turn_path = external_maneuver_override.turn_path;
|
||||
maneuver_override_ways[turn_path.From()] = dummy_segment;
|
||||
maneuver_override_ways[turn_path.To()] = dummy_segment;
|
||||
if (external_maneuver_override.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way = turn_path.AsViaWayPath();
|
||||
for (const auto &via : way.via)
|
||||
{
|
||||
maneuver_override_ways[via] = dummy_segment;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// First, make an empty hashtable keyed by the ways referenced
|
||||
@ -767,36 +995,6 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
return internal;
|
||||
};
|
||||
|
||||
auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) {
|
||||
auto const from_segment_itr = maneuver_override_ways.find(from_id);
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Override references invalid way: " << from_id;
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = maneuver_override_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Override references invalid way: " << to_id;
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) =
|
||||
find_turn_nodes(from_segment_itr->second, to_segment_itr->second, SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
util::Log(logDEBUG) << "Maneuver override ways " << from_segment_itr->second.way_id
|
||||
<< " and " << to_segment_itr->second.way_id << " are not connected";
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return NodeBasedTurn{osm_node_to_internal_nbn(from),
|
||||
osm_node_to_internal_nbn(via),
|
||||
osm_node_to_internal_nbn(to)};
|
||||
};
|
||||
|
||||
const auto strings_to_turn_type_and_direction = [](const std::string &turn_string,
|
||||
const std::string &direction_string) {
|
||||
auto result = std::make_pair(guidance::TurnType::MaxTurnType,
|
||||
@ -862,44 +1060,36 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
// Later, the UnresolvedManeuverOverride will be converted into a final ManeuverOverride
|
||||
// once the edge-based-node IDs are generated by the edge-based-graph-factory
|
||||
const auto transform = [&](const auto &external, auto &internal) {
|
||||
// Create a stub override
|
||||
auto maneuver_override =
|
||||
UnresolvedManeuverOverride{{},
|
||||
osm_node_to_internal_nbn(external.via_node),
|
||||
guidance::TurnType::Invalid,
|
||||
guidance::DirectionModifier::MaxDirectionModifier};
|
||||
|
||||
// Convert Way IDs into node-based-node IDs
|
||||
// We iterate from back to front here because the first node in the node_sequence
|
||||
// must eventually be a source node, but all the others must be targets.
|
||||
// the get_internal_pairs_from_ways returns (source,target), so if we
|
||||
// iterate backwards, we will end up with source,target,target,target,target
|
||||
// in a sequence, which is what we want
|
||||
for (auto i = 0ul; i < external.via_ways.size() - 1; ++i)
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
// returns the two far ends of the referenced ways
|
||||
auto turn = get_turn_from_way_pair(external.via_ways[i], external.via_ways[i + 1]);
|
||||
|
||||
maneuver_override.turn_sequence.push_back(turn);
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_way_path_from_OSM_ids(internal_type.Name(),
|
||||
maneuver_override_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
osm_node_to_internal_nbn);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(external_type.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
auto const &external = external_type.turn_path.AsViaNodePath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_node_path_from_OSM_ids(internal_type.Name(),
|
||||
maneuver_override_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
osm_node_to_internal_nbn);
|
||||
}
|
||||
|
||||
// check if we were able to resolve all the involved ways
|
||||
// auto maneuver_override =
|
||||
// get_maneuver_override_from_OSM_ids(external.from, external.to,
|
||||
// external.via_node);
|
||||
internal_type.instruction_node = osm_node_to_internal_nbn(external_type.via_node),
|
||||
std::tie(internal_type.override_type, internal_type.direction) =
|
||||
strings_to_turn_type_and_direction(external_type.maneuver, external_type.direction);
|
||||
|
||||
std::tie(maneuver_override.override_type, maneuver_override.direction) =
|
||||
strings_to_turn_type_and_direction(external.maneuver, external.direction);
|
||||
|
||||
if (!maneuver_override.Valid())
|
||||
{
|
||||
util::Log(logDEBUG) << "Override is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
internal = std::move(maneuver_override);
|
||||
return true;
|
||||
return internal_type.Valid();
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types =
|
||||
@ -925,7 +1115,7 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
|
||||
ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWays()
|
||||
{
|
||||
// Contains the nodes of each way that is part of an restriction
|
||||
// Contains the nodes of each way that is part of a restriction
|
||||
ReferencedWays restriction_ways;
|
||||
|
||||
// Prepare for extracting nodes for all restrictions
|
||||
@ -937,23 +1127,17 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
|
||||
// nodes of these ways.
|
||||
const auto mark_ids = [&](auto const &turn_restriction) {
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
const auto &turn_path = turn_restriction.turn_path;
|
||||
restriction_ways[turn_path.From()] = dummy_segment;
|
||||
restriction_ways[turn_path.To()] = dummy_segment;
|
||||
if (turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way = turn_restriction.AsWayRestriction();
|
||||
restriction_ways[way.from] = dummy_segment;
|
||||
restriction_ways[way.to] = dummy_segment;
|
||||
for (const auto &v : way.via)
|
||||
const auto &way = turn_path.AsViaWayPath();
|
||||
for (const auto &via : way.via)
|
||||
{
|
||||
restriction_ways[v] = dummy_segment;
|
||||
restriction_ways[via] = dummy_segment;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
const auto &node = turn_restriction.AsNodeRestriction();
|
||||
restriction_ways[node.from] = dummy_segment;
|
||||
restriction_ways[node.to] = dummy_segment;
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids);
|
||||
@ -992,234 +1176,41 @@ void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction
|
||||
return internal;
|
||||
};
|
||||
|
||||
// Way restrictions are comprised of:
|
||||
// 1. The segment in the from way that intersects with the via path
|
||||
// 2. All segments that make up the via path
|
||||
// 3. The segment in the to way that intersects with the via path.
|
||||
//
|
||||
// from: [a, b, c, d, e]
|
||||
// via: [[f, g, h, i, j], [k, l], [m, n, o]]
|
||||
// to: [p, q, r, s]
|
||||
//
|
||||
// First establish the orientation of the from/via intersection by finding which end
|
||||
// nodes both ways share. From this we can select the from segment.
|
||||
//
|
||||
// intersect | from segment | next_connection
|
||||
// a=f | b,a | f
|
||||
// a=j | b,a | j
|
||||
// e=f | e,d | f
|
||||
// e=j | e,d | j
|
||||
//
|
||||
// Use the next connection to inform the orientation of the first via
|
||||
// way and the intersection between first and second via ways.
|
||||
//
|
||||
// next_connection | intersect | via result | next_next_connection
|
||||
// f | j=k | [f,g,h,i,j] | k
|
||||
// f | j=l | [f,g,h,i,j] | l
|
||||
// j | f=k | [j,i,h,g,f] | k
|
||||
// j | f=l | [j,i,h,g,f] | l
|
||||
//
|
||||
// This is continued for the remaining via ways, appending to the via result
|
||||
//
|
||||
// The final via/to intersection also uses the next_connection information in a similar fashion.
|
||||
//
|
||||
// next_connection | intersect | to_segment
|
||||
// m | o=p | p,q
|
||||
// m | o=s | s,r
|
||||
// o | m=p | p,q
|
||||
// o | m=s | s,r
|
||||
//
|
||||
// The final result is a list of nodes that represent a valid from->via->to path through the
|
||||
// ways.
|
||||
//
|
||||
// E.g. if intersection nodes are a=j, f=l, k=o, m=s
|
||||
// the result will be {e [d,c,b,a,i,h,g,f,k,n,m] r}
|
||||
auto const find_way_restriction = [&](const NodesOfWay &from_way,
|
||||
const std::vector<NodesOfWay> &via_ways,
|
||||
const NodesOfWay &to_way) {
|
||||
BOOST_ASSERT(!via_ways.empty());
|
||||
|
||||
WayRestriction restriction;
|
||||
|
||||
// Find the orientation of the connected ways starting with the from-via intersection.
|
||||
OSMNodeID from, via;
|
||||
std::tie(from, via, std::ignore) =
|
||||
find_turn_nodes(from_way, via_ways.front(), SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected from and via ways: "
|
||||
<< from_way.way_id << ", " << via_ways.front().way_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
restriction.from = to_internal(from);
|
||||
restriction.via.push_back(to_internal(via));
|
||||
|
||||
// Use the connection node from the previous intersection to inform our conversion of
|
||||
// via ways into internal nodes.
|
||||
OSMNodeID next_connection = via;
|
||||
for (const auto &via_way : via_ways)
|
||||
{
|
||||
if (next_connection == via_way.first_segment_source_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.begin()),
|
||||
via_way.node_ids.end(),
|
||||
std::back_inserter(restriction.via),
|
||||
to_internal);
|
||||
next_connection = via_way.last_segment_target_id();
|
||||
}
|
||||
else if (next_connection == via_way.last_segment_target_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.rbegin()),
|
||||
via_way.node_ids.rend(),
|
||||
std::back_inserter(restriction.via),
|
||||
to_internal);
|
||||
next_connection = via_way.first_segment_source_id();
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected via way: " << via_way.way_id
|
||||
<< " to node " << next_connection;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
}
|
||||
|
||||
// Add the final to node after the via-to intersection.
|
||||
if (next_connection == to_way.first_segment_source_id())
|
||||
{
|
||||
restriction.to = to_internal(to_way.first_segment_target_id());
|
||||
}
|
||||
else if (next_connection == to_way.last_segment_target_id())
|
||||
{
|
||||
restriction.to = to_internal(to_way.last_segment_source_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected via and to ways: "
|
||||
<< via_ways.back().way_id << ", " << to_way.way_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
return restriction;
|
||||
};
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal restriction
|
||||
auto const get_way_restriction_from_OSM_ids =
|
||||
[&](auto const from_id, auto const to_id, const std::vector<OSMWayID> &via_ids) {
|
||||
auto const from_way_itr = restriction_ways.find(from_id);
|
||||
if (from_way_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid from way: " << from_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
std::vector<NodesOfWay> via_ways;
|
||||
for (const auto &via_id : via_ids)
|
||||
{
|
||||
auto const via_segment_itr = restriction_ways.find(via_id);
|
||||
if (via_segment_itr->second.way_id != via_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid via way: " << via_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
via_ways.push_back(via_segment_itr->second);
|
||||
}
|
||||
|
||||
auto const to_way_itr = restriction_ways.find(to_id);
|
||||
if (to_way_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid to way: " << to_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_way_restriction(from_way_itr->second, via_ways, to_way_itr->second);
|
||||
};
|
||||
|
||||
// Node restrictions are described as a restriction between the two segments closest
|
||||
// to the shared via-node on the from and to ways.
|
||||
// from: [a, b, c, d, e]
|
||||
// to: [f, g, h, i, j]
|
||||
//
|
||||
// The via node establishes the orientation of the from/to intersection when choosing the
|
||||
// segments.
|
||||
// via | node restriction
|
||||
// a=f | b,a,g
|
||||
// a=j | b,a,i
|
||||
// e=f | d,e,g
|
||||
// e=j | d,e,i
|
||||
auto const find_node_restriction =
|
||||
[&](auto const &from_segment, auto const &to_segment, auto const via_node) {
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) = find_turn_nodes(from_segment, to_segment, via_node);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
util::Log(logDEBUG)
|
||||
<< "Restriction references unconnected way: " << from_segment.way_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return NodeRestriction{to_internal(from), to_internal(via), to_internal(to)};
|
||||
};
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal restriction
|
||||
auto const get_node_restriction_from_OSM_ids = [&](auto const from_id,
|
||||
auto const to_id,
|
||||
const OSMNodeID via_node) {
|
||||
auto const from_segment_itr = restriction_ways.find(from_id);
|
||||
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << from_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = restriction_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << to_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_node_restriction(from_segment_itr->second, to_segment_itr->second, via_node);
|
||||
};
|
||||
|
||||
// Transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs).
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
auto const &external = external_type.AsWayRestriction();
|
||||
auto const restriction =
|
||||
get_way_restriction_from_OSM_ids(external.from, external.to, external.via);
|
||||
|
||||
if (!restriction.Valid())
|
||||
return false;
|
||||
|
||||
internal_type.node_or_way = restriction;
|
||||
return true;
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_way_path_from_OSM_ids(internal_type.Name(),
|
||||
restriction_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
to_internal);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(external_type.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
auto const &external = external_type.AsNodeRestriction();
|
||||
|
||||
auto restriction =
|
||||
get_node_restriction_from_OSM_ids(external.from, external.to, external.via);
|
||||
|
||||
if (!restriction.Valid())
|
||||
return false;
|
||||
|
||||
internal_type.node_or_way = restriction;
|
||||
return true;
|
||||
BOOST_ASSERT(external_type.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
auto const &external = external_type.turn_path.AsViaNodePath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_node_path_from_OSM_ids(internal_type.Name(),
|
||||
restriction_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
to_internal);
|
||||
}
|
||||
internal_type.is_only = external_type.is_only;
|
||||
internal_type.condition = std::move(external_type.condition);
|
||||
return internal_type.Valid();
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types = [&](InputTurnRestriction &external_restriction) {
|
||||
TurnRestriction restriction;
|
||||
if (transform(external_restriction, restriction))
|
||||
{
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
restriction.condition = std::move(external_restriction.condition);
|
||||
turn_restrictions.push_back(std::move(restriction));
|
||||
}
|
||||
};
|
||||
|
@ -13,11 +13,11 @@
|
||||
#include "extractor/name_table.hpp"
|
||||
#include "extractor/node_based_graph_factory.hpp"
|
||||
#include "extractor/node_restriction_map.hpp"
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "extractor/restriction_graph.hpp"
|
||||
#include "extractor/restriction_parser.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/tarjan_scc.hpp"
|
||||
#include "extractor/turn_path_filter.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
|
||||
#include "guidance/files.hpp"
|
||||
@ -279,7 +279,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
edge_based_nodes_container =
|
||||
EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData()));
|
||||
|
||||
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), node_based_graph);
|
||||
turn_restrictions = removeInvalidTurnPaths(std::move(turn_restrictions), node_based_graph);
|
||||
unresolved_maneuver_overrides =
|
||||
removeInvalidTurnPaths(std::move(unresolved_maneuver_overrides), node_based_graph);
|
||||
auto restriction_graph = constructRestrictionGraph(turn_restrictions);
|
||||
|
||||
const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes();
|
||||
|
@ -3,8 +3,7 @@
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
#include "guidance/intersection.hpp"
|
||||
#include "extractor/turn_path_compressor.hpp"
|
||||
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
@ -32,28 +31,34 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions, maneuver_overrides);
|
||||
TurnPathCompressor turn_path_compressor(turn_restrictions, maneuver_overrides);
|
||||
|
||||
// Some degree two nodes are not compressed if they act as entry/exit points into a
|
||||
// restriction path.
|
||||
std::unordered_set<NodeID> restriction_via_nodes;
|
||||
std::unordered_set<NodeID> incompressible_via_nodes;
|
||||
|
||||
const auto remember_via_nodes = [&](const auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
if (restriction.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
restriction_via_nodes.insert(restriction.AsNodeRestriction().via);
|
||||
incompressible_via_nodes.insert(restriction.turn_path.AsViaNodePath().via);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
const auto &way_restriction = restriction.AsWayRestriction();
|
||||
BOOST_ASSERT(restriction.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
const auto &way_restriction = restriction.turn_path.AsViaWayPath();
|
||||
// We do not compress the first and last via nodes so that we know how to enter/exit
|
||||
// a restriction path and apply the restrictions correctly.
|
||||
restriction_via_nodes.insert(way_restriction.via.front());
|
||||
restriction_via_nodes.insert(way_restriction.via.back());
|
||||
incompressible_via_nodes.insert(way_restriction.via.front());
|
||||
incompressible_via_nodes.insert(way_restriction.via.back());
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
|
||||
for (const auto &maneuver : maneuver_overrides)
|
||||
{
|
||||
// Only incompressible is where the instruction occurs.
|
||||
incompressible_via_nodes.insert(maneuver.instruction_node);
|
||||
}
|
||||
|
||||
{
|
||||
const auto weight_multiplier =
|
||||
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
||||
@ -77,7 +82,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
}
|
||||
|
||||
// check if v is an entry/exit via node for a turn restriction
|
||||
if (restriction_via_nodes.count(node_v) > 0)
|
||||
if (incompressible_via_nodes.count(node_v) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -303,8 +308,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
graph.DeleteEdge(node_v, forward_e2);
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_compressor.Compress(node_u, node_v, node_w);
|
||||
// update any involved turn relations
|
||||
turn_path_compressor.Compress(node_u, node_v, node_w);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(forward_e1,
|
||||
|
@ -119,9 +119,15 @@ ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
|
||||
|
||||
if (valid_relation)
|
||||
{
|
||||
maneuver_override.via_ways.push_back(from);
|
||||
std::copy(via_ways.begin(), via_ways.end(), std::back_inserter(maneuver_override.via_ways));
|
||||
maneuver_override.via_ways.push_back(to);
|
||||
if (via_ways.empty())
|
||||
{
|
||||
maneuver_override.turn_path.node_or_way = InputViaNodePath{{from}, {via_node}, {to}};
|
||||
}
|
||||
else
|
||||
{
|
||||
maneuver_override.turn_path.node_or_way =
|
||||
InputViaWayPath{{from}, std::move(via_ways), {to}};
|
||||
}
|
||||
maneuver_override.via_node = via_node;
|
||||
}
|
||||
else
|
||||
|
@ -1,242 +0,0 @@
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionCompressor::RestrictionCompressor(
|
||||
std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
{
|
||||
// add a turn restriction ptr to the starts/ends maps, needs to be a reference!
|
||||
auto index = [&](auto &element) {
|
||||
starts.insert({element.From(), &element});
|
||||
ends.insert({element.To(), &element});
|
||||
if (element.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
const auto &way_via = element.AsWayRestriction().via;
|
||||
BOOST_ASSERT(way_via.size() >= 2);
|
||||
// No need to track the first and last via nodes as they will not be compressed.
|
||||
for (const auto &via_node :
|
||||
boost::make_iterator_range(way_via.begin() + 1, way_via.end() - 1))
|
||||
{
|
||||
vias.insert({via_node, &element});
|
||||
}
|
||||
}
|
||||
};
|
||||
// !needs to be reference, so we can get the correct address
|
||||
const auto index_starts_ends_vias = [&](auto &restriction) { index(restriction); };
|
||||
|
||||
// add all restrictions as their respective start/via/end pointers
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_ends_vias);
|
||||
|
||||
auto index_maneuver = [&](auto &maneuver) {
|
||||
for (auto &turn : maneuver.turn_sequence)
|
||||
{
|
||||
maneuver_starts.insert({turn.from, &turn});
|
||||
maneuver_ends.insert({turn.to, &turn});
|
||||
}
|
||||
};
|
||||
// !needs to be reference, so we can get the correct address
|
||||
std::for_each(maneuver_overrides.begin(), maneuver_overrides.end(), [&](auto &maneuver) {
|
||||
index_maneuver(maneuver);
|
||||
});
|
||||
}
|
||||
|
||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
{
|
||||
// handle turn restrictions
|
||||
// extract all start ptrs and move them from via to from.
|
||||
auto all_starts_range = starts.equal_range(via);
|
||||
std::vector<TurnRestriction *> start_ptrs;
|
||||
std::transform(all_starts_range.first,
|
||||
all_starts_range.second,
|
||||
std::back_inserter(start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_start = [&](auto ptr) {
|
||||
if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
auto &node_ptr = ptr->AsNodeRestriction();
|
||||
BOOST_ASSERT(node_ptr.from == via);
|
||||
if (node_ptr.via == to)
|
||||
{
|
||||
node_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == from);
|
||||
node_ptr.from = to;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = ptr->AsWayRestriction();
|
||||
// ____ | from - p.from | via - p.via[0] | to - p[1..],p.to | ____
|
||||
BOOST_ASSERT(way_ptr.from == via);
|
||||
if (way_ptr.via.front() == to)
|
||||
{
|
||||
way_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via[0] | from - p[1,..],p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.front() == from);
|
||||
way_ptr.from = to;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), update_start);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
starts.erase(via);
|
||||
|
||||
const auto reinsert_start = [&](auto ptr) { starts.insert({ptr->From(), ptr}); };
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start);
|
||||
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto all_ends_range = ends.equal_range(via);
|
||||
std::vector<TurnRestriction *> end_ptrs;
|
||||
std::transform(all_ends_range.first,
|
||||
all_ends_range.second,
|
||||
std::back_inserter(end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end = [&](auto ptr) {
|
||||
if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
auto &node_ptr = ptr->AsNodeRestriction();
|
||||
|
||||
BOOST_ASSERT(node_ptr.to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (node_ptr.via == from)
|
||||
{
|
||||
node_ptr.to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == to);
|
||||
node_ptr.to = from;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = ptr->AsWayRestriction();
|
||||
|
||||
BOOST_ASSERT(way_ptr.to == via);
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | from - p.to | via - ____ | to
|
||||
if (way_ptr.via.back() == from)
|
||||
{
|
||||
way_ptr.to = to;
|
||||
}
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.back() == to);
|
||||
way_ptr.to = from;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end);
|
||||
|
||||
// update end ptrs in mapping
|
||||
ends.erase(via);
|
||||
|
||||
const auto reinsert_end = [&](auto ptr) { ends.insert({ptr->To(), ptr}); };
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
|
||||
|
||||
// remove compressed node from all via paths
|
||||
auto all_vias_range = vias.equal_range(via);
|
||||
|
||||
const auto update_via = [&](auto restriction_pair) {
|
||||
BOOST_ASSERT(restriction_pair.second->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = restriction_pair.second->AsWayRestriction();
|
||||
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
|
||||
way_ptr.via.erase(std::remove(way_ptr.via.begin(), way_ptr.via.end(), via),
|
||||
way_ptr.via.end());
|
||||
};
|
||||
std::for_each(all_vias_range.first, all_vias_range.second, update_via);
|
||||
|
||||
// update via ptrs in mapping
|
||||
vias.erase(via);
|
||||
|
||||
/**********************************************************************************************/
|
||||
|
||||
// handle maneuver overrides from nodes
|
||||
// extract all startptrs
|
||||
auto maneuver_starts_range = maneuver_starts.equal_range(via);
|
||||
std::vector<NodeBasedTurn *> mnv_start_ptrs;
|
||||
std::transform(maneuver_starts_range.first,
|
||||
maneuver_starts_range.second,
|
||||
std::back_inserter(mnv_start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
// update from nodes of maneuver overrides
|
||||
const auto update_start_mnv = [&](auto ptr) {
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
BOOST_ASSERT(ptr->from == via);
|
||||
if (ptr->via == to)
|
||||
{
|
||||
ptr->from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == from);
|
||||
ptr->from = to;
|
||||
}
|
||||
};
|
||||
std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), update_start_mnv);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
maneuver_starts.erase(via);
|
||||
const auto reinsert_start_mnv = [&](auto ptr) { maneuver_starts.insert({ptr->from, ptr}); };
|
||||
std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), reinsert_start_mnv);
|
||||
|
||||
/**********************************************************************************************/
|
||||
// handle maneuver override to nodes
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto maneuver_ends_range = maneuver_ends.equal_range(via);
|
||||
std::vector<NodeBasedTurn *> mnv_end_ptrs;
|
||||
std::transform(maneuver_ends_range.first,
|
||||
maneuver_ends_range.second,
|
||||
std::back_inserter(mnv_end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end_mnv = [&](auto ptr) {
|
||||
BOOST_ASSERT(ptr->to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (ptr->via == from)
|
||||
{
|
||||
ptr->to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == to);
|
||||
ptr->to = from;
|
||||
}
|
||||
};
|
||||
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), update_end_mnv);
|
||||
|
||||
// update end ptrs in mapping
|
||||
maneuver_ends.erase(via);
|
||||
|
||||
const auto reinsert_end_mnvs = [&](auto ptr) { maneuver_ends.insert({ptr->to, ptr}); };
|
||||
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
@ -1,83 +0,0 @@
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
std::vector<TurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Removing invalid restrictions...";
|
||||
TIMER_START(remove_invalid_restrictions);
|
||||
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
|
||||
const auto eid = node_based_graph.FindEdge(from, to);
|
||||
if (eid == SPECIAL_EDGEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has invalid edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(eid);
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has non-traversable edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto is_valid_node = [is_valid_edge](const auto &node_restriction) {
|
||||
return is_valid_edge(node_restriction.from, node_restriction.via) &&
|
||||
is_valid_edge(node_restriction.via, node_restriction.to);
|
||||
};
|
||||
|
||||
const auto is_valid_way = [is_valid_edge](const auto &way_restriction) {
|
||||
if (!is_valid_edge(way_restriction.from, way_restriction.via.front()))
|
||||
return false;
|
||||
|
||||
const auto invalid_it = std::adjacent_find(
|
||||
way_restriction.via.begin(),
|
||||
way_restriction.via.end(),
|
||||
[&](auto via_from, auto via_to) { return !is_valid_edge(via_from, via_to); });
|
||||
if (invalid_it != way_restriction.via.end())
|
||||
return false;
|
||||
|
||||
return is_valid_edge(way_restriction.via.back(), way_restriction.to);
|
||||
};
|
||||
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
return !is_valid_node(restriction.AsNodeRestriction());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
return !is_valid_way(restriction.AsWayRestriction());
|
||||
}
|
||||
};
|
||||
|
||||
const auto end_valid_restrictions =
|
||||
std::remove_if(restrictions.begin(), restrictions.end(), is_invalid);
|
||||
const auto num_removed = std::distance(end_valid_restrictions, restrictions.end());
|
||||
restrictions.erase(end_valid_restrictions, restrictions.end());
|
||||
|
||||
TIMER_STOP(remove_invalid_restrictions);
|
||||
log << "removed " << num_removed << " invalid restrictions, after "
|
||||
<< TIMER_SEC(remove_invalid_restrictions) << "s";
|
||||
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
@ -1,9 +1,10 @@
|
||||
#include "extractor/restriction_graph.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/turn_path.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include <util/for_each_pair.hpp>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace osrm
|
||||
@ -211,11 +212,11 @@ void buildGraph(RestrictionGraph &rg, const std::vector<TurnRestriction> &restri
|
||||
const auto run_builder = [&](const auto &restriction) {
|
||||
builder_type builder(rg);
|
||||
|
||||
builder.start(restriction.From(), restriction.FirstVia());
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
builder.start(restriction.turn_path.From(), restriction.turn_path.FirstVia());
|
||||
if (restriction.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way_restriction = restriction.AsWayRestriction();
|
||||
util::for_each_pair(way_restriction.via,
|
||||
const auto &via_way_path = restriction.turn_path.AsViaWayPath();
|
||||
util::for_each_pair(via_way_path.via,
|
||||
[&](NodeID from, NodeID to) { builder.next(from, to); });
|
||||
}
|
||||
builder.end(restriction);
|
||||
|
@ -232,7 +232,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
return {};
|
||||
}
|
||||
// Internally restrictions are represented with one 'from' and one 'to' way.
|
||||
// Therefore we need to convert a multi from/to restriction into multiple restrictions.
|
||||
// Therefore, we need to convert a multi from/to restriction into multiple restrictions.
|
||||
for (const auto &from : from_ways)
|
||||
{
|
||||
for (const auto &to : to_ways)
|
||||
@ -243,12 +243,12 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
if (is_node_restriction)
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction.node_or_way = InputNodeRestriction{{from}, {via_node}, {to}};
|
||||
restriction.turn_path.node_or_way = InputViaNodePath{{from}, {via_node}, {to}};
|
||||
}
|
||||
else
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction.node_or_way = InputWayRestriction{{from}, via_ways, {to}};
|
||||
restriction.turn_path.node_or_way = InputViaWayPath{{from}, via_ways, {to}};
|
||||
}
|
||||
restriction_containers.push_back(std::move(restriction));
|
||||
}
|
||||
|
164
src/extractor/turn_path_compressor.cpp
Normal file
164
src/extractor/turn_path_compressor.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
#include "extractor/turn_path_compressor.hpp"
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
TurnPathCompressor::TurnPathCompressor(std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
{
|
||||
// Track all turn paths by their respective start/via/end nodes.
|
||||
auto index = [&](auto &element) {
|
||||
starts.insert({element.From(), &element});
|
||||
ends.insert({element.To(), &element});
|
||||
if (element.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
// Some of the via nodes can not be compressed so don't need tracking
|
||||
// (e.g. first and last via node of a restriction, instruction node of maneuver).
|
||||
// However, for the sake of simplicity we'll track them all.
|
||||
for (const auto &via_node : element.AsViaWayPath().via)
|
||||
{
|
||||
vias.insert({via_node, &element});
|
||||
}
|
||||
}
|
||||
};
|
||||
// We need to pass a reference to the index as we will mutate the turn path during compression.
|
||||
const auto index_starts_ends_vias = [&](auto &relation) { index(relation.turn_path); };
|
||||
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_ends_vias);
|
||||
std::for_each(maneuver_overrides.begin(), maneuver_overrides.end(), index_starts_ends_vias);
|
||||
}
|
||||
|
||||
void TurnPathCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
{
|
||||
// handle turn restrictions
|
||||
// extract all start ptrs and move them from via to from.
|
||||
auto all_starts_range = starts.equal_range(via);
|
||||
std::vector<TurnPath *> start_ptrs;
|
||||
std::transform(all_starts_range.first,
|
||||
all_starts_range.second,
|
||||
std::back_inserter(start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_start = [&](auto ptr) {
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
auto &node_ptr = ptr->AsViaNodePath();
|
||||
BOOST_ASSERT(node_ptr.from == via);
|
||||
if (node_ptr.via == to)
|
||||
{
|
||||
node_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == from);
|
||||
node_ptr.from = to;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = ptr->AsViaWayPath();
|
||||
// ____ | from - p.from | via - p.via[0] | to - p[1..],p.to | ____
|
||||
BOOST_ASSERT(way_ptr.from == via);
|
||||
if (way_ptr.via.front() == to)
|
||||
{
|
||||
way_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via[0] | from - p[1,..],p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.front() == from);
|
||||
way_ptr.from = to;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), update_start);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
starts.erase(via);
|
||||
|
||||
const auto reinsert_start = [&](auto ptr) { starts.insert({ptr->From(), ptr}); };
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start);
|
||||
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto all_ends_range = ends.equal_range(via);
|
||||
std::vector<TurnPath *> end_ptrs;
|
||||
std::transform(all_ends_range.first,
|
||||
all_ends_range.second,
|
||||
std::back_inserter(end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end = [&](auto ptr) {
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
auto &node_ptr = ptr->AsViaNodePath();
|
||||
|
||||
BOOST_ASSERT(node_ptr.to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (node_ptr.via == from)
|
||||
{
|
||||
node_ptr.to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == to);
|
||||
node_ptr.to = from;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = ptr->AsViaWayPath();
|
||||
|
||||
BOOST_ASSERT(way_ptr.to == via);
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | from - p.to | via - ____ | to
|
||||
if (way_ptr.via.back() == from)
|
||||
{
|
||||
way_ptr.to = to;
|
||||
}
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.back() == to);
|
||||
way_ptr.to = from;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end);
|
||||
|
||||
// update end ptrs in mapping
|
||||
ends.erase(via);
|
||||
|
||||
const auto reinsert_end = [&](auto ptr) { ends.insert({ptr->To(), ptr}); };
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
|
||||
|
||||
// remove compressed node from all via paths
|
||||
auto all_vias_range = vias.equal_range(via);
|
||||
|
||||
const auto update_via = [&](auto restriction_pair) {
|
||||
BOOST_ASSERT(restriction_pair.second->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = restriction_pair.second->AsViaWayPath();
|
||||
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
|
||||
way_ptr.via.erase(std::remove(way_ptr.via.begin(), way_ptr.via.end(), via),
|
||||
way_ptr.via.end());
|
||||
};
|
||||
std::for_each(all_vias_range.first, all_vias_range.second, update_via);
|
||||
|
||||
// update via ptrs in mapping
|
||||
vias.erase(via);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
88
src/extractor/turn_path_filter.cpp
Normal file
88
src/extractor/turn_path_filter.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "extractor/turn_path_filter.hpp"
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> removeInvalidTurnPaths(std::vector<T> turn_relations,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Removing invalid " << T::Name() << "s...";
|
||||
TIMER_START(remove_invalid_turn_paths);
|
||||
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
|
||||
const auto eid = node_based_graph.FindEdge(from, to);
|
||||
if (eid == SPECIAL_EDGEID)
|
||||
{
|
||||
util::Log(logDEBUG) << T::Name() << " has invalid edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(eid);
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
util::Log(logDEBUG) << T::Name() << " has non-traversable edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto is_valid_node = [is_valid_edge](const auto &via_node_path) {
|
||||
return is_valid_edge(via_node_path.from, via_node_path.via) &&
|
||||
is_valid_edge(via_node_path.via, via_node_path.to);
|
||||
};
|
||||
|
||||
const auto is_valid_way = [is_valid_edge](const auto &via_way_path) {
|
||||
if (!is_valid_edge(via_way_path.from, via_way_path.via.front()))
|
||||
return false;
|
||||
|
||||
const auto invalid_it = std::adjacent_find(
|
||||
via_way_path.via.begin(), via_way_path.via.end(), [&](auto via_from, auto via_to) {
|
||||
return !is_valid_edge(via_from, via_to);
|
||||
});
|
||||
if (invalid_it != via_way_path.via.end())
|
||||
return false;
|
||||
|
||||
return is_valid_edge(via_way_path.via.back(), via_way_path.to);
|
||||
};
|
||||
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &turn_relation) {
|
||||
if (turn_relation.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
return !is_valid_node(turn_relation.turn_path.AsViaNodePath());
|
||||
}
|
||||
|
||||
BOOST_ASSERT(turn_relation.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return !is_valid_way(turn_relation.turn_path.AsViaWayPath());
|
||||
};
|
||||
|
||||
const auto end_valid_relations =
|
||||
std::remove_if(turn_relations.begin(), turn_relations.end(), is_invalid);
|
||||
const auto num_removed = std::distance(end_valid_relations, turn_relations.end());
|
||||
turn_relations.erase(end_valid_relations, turn_relations.end());
|
||||
|
||||
TIMER_STOP(remove_invalid_turn_paths);
|
||||
log << "removed " << num_removed << " invalid " << T::Name() << "s, after "
|
||||
<< TIMER_SEC(remove_invalid_turn_paths) << "s";
|
||||
|
||||
return turn_relations;
|
||||
}
|
||||
|
||||
template std::vector<TurnRestriction> removeInvalidTurnPaths<>(std::vector<TurnRestriction>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
template std::vector<UnresolvedManeuverOverride>
|
||||
removeInvalidTurnPaths<>(std::vector<UnresolvedManeuverOverride>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
@ -23,7 +23,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations{
|
||||
{EMPTY_NAMEID, 0, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false},
|
||||
{EMPTY_NAMEID, 1, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}};
|
||||
std::vector<TurnRestriction> restrictions{TurnRestriction{NodeRestriction{0, 2, 1}, false}};
|
||||
std::vector<TurnRestriction> restrictions{TurnRestriction{{ViaNodePath{0, 2, 1}}, false}};
|
||||
CompressedEdgeContainer container;
|
||||
test::MockScriptingEnvironment scripting_environment;
|
||||
std::vector<UnresolvedManeuverOverride> maneuver_overrides;
|
||||
|
@ -15,14 +15,14 @@ using namespace osrm::extractor;
|
||||
|
||||
TurnRestriction makeWayRestriction(NodeID from, std::vector<NodeID> via, NodeID to, bool is_only)
|
||||
{
|
||||
WayRestriction wr{from, std::move(via), to};
|
||||
return TurnRestriction(wr, is_only);
|
||||
ViaWayPath vwp{from, std::move(via), to};
|
||||
return TurnRestriction({vwp}, is_only);
|
||||
}
|
||||
|
||||
TurnRestriction makeNodeRestriction(NodeID from, NodeID via, NodeID to, bool is_only)
|
||||
{
|
||||
NodeRestriction nr{from, via, to};
|
||||
return TurnRestriction(nr, is_only);
|
||||
ViaNodePath vnp{from, via, to};
|
||||
return TurnRestriction({vnp}, is_only);
|
||||
}
|
||||
|
||||
struct instruction
|
||||
@ -52,7 +52,7 @@ void checkInstructions(RestrictionGraph::RestrictionRange restrictions,
|
||||
restrictions.end(),
|
||||
std::back_inserter(actual_instructions),
|
||||
[](const auto &restriction) {
|
||||
return instruction{restriction->To(), bool(restriction->is_only)};
|
||||
return instruction{restriction->turn_path.To(), bool(restriction->is_only)};
|
||||
});
|
||||
std::sort(actual_instructions.begin(),
|
||||
actual_instructions.end(),
|
||||
|
Loading…
Reference in New Issue
Block a user