handle conditional via-way restrictions

- refactor conditional restriction handling to not use external data (first OSM nodes on ways)
 - BREAKING: changes internal file format of osrm.restrictions
 - add support for general conditional penalties based on edge-based nodes (requires unique edges between nodes)
This commit is contained in:
Moritz Kobitzsch
2017-08-01 17:18:12 +02:00
parent f34320a89b
commit 93299d6651
27 changed files with 931 additions and 497 deletions
@@ -0,0 +1,28 @@
#ifndef OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
#define OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
#include "util/coordinate.hpp"
#include "util/opening_hours.hpp"
#include <cstdint>
#include <vector>
#include <type_traits>
namespace osrm
{
namespace extractor
{
struct ConditionalTurnPenalty
{
// offset into the sequential list of turn penalties (see TurnIndexBlock for reference);
std::uint64_t turn_offset;
util::Coordinate location;
std::vector<util::OpeningHours> conditions;
};
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
+18 -1
View File
@@ -4,6 +4,7 @@
#define EDGE_BASED_GRAPH_FACTORY_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/conditional_turn_penalty.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/edge_based_node_segment.hpp"
#include "extractor/extraction_turn.hpp"
@@ -16,7 +17,7 @@
#include "extractor/packed_osm_ids.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/way_restriction_map.hpp"
#include "util/concurrent_id_map.hpp"
@@ -92,7 +93,9 @@ class EdgeBasedGraphFactory
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map);
// The following get access functions destroy the content in the factory
@@ -124,6 +127,18 @@ class EdgeBasedGraphFactory
private:
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
struct Conditional
{
// the edge based nodes allow for a unique identification of conditionals
NodeID from_node;
NodeID to_node;
ConditionalTurnPenalty penalty;
};
// assign the correct index to the penalty value stored in the conditional
std::vector<ConditionalTurnPenalty>
IndexConditionals(std::vector<Conditional> &&conditionals) const;
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
//! graph
std::vector<bool> m_edge_based_node_is_startpoint;
@@ -173,7 +188,9 @@ class EdgeBasedGraphFactory
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &conditional_turn_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map);
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
@@ -27,7 +27,6 @@ class ExtractionContainers
void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::io::FileWriter &file_out) const;
void WriteConditionalRestrictions(const std::string &restrictions_file_name);
void WriteEdges(storage::io::FileWriter &file_out) const;
void WriteCharData(const std::string &file_name);
@@ -65,7 +64,6 @@ class ExtractionContainers
void PrepareData(ScriptingEnvironment &scripting_environment,
const std::string &osrm_path,
const std::string &restrictions_file_name,
const std::string &names_data_path);
};
}
+8 -1
View File
@@ -56,7 +56,9 @@ class Extractor
private:
ExtractorConfig config;
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
std::tuple<guidance::LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
std::pair<std::size_t, EdgeID>
@@ -70,6 +72,7 @@ class Extractor
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
guidance::LaneDescriptionMap &turn_lane_map);
void FindComponents(unsigned max_edge_id,
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
@@ -89,6 +92,10 @@ class Extractor
static void WriteCompressedNodeBasedGraph(const std::string &path,
const util::NodeBasedDynamicGraph &graph,
const std::vector<util::Coordinate> &coordiantes);
void WriteConditionalRestrictions(
const std::string &path,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
};
}
}
+1
View File
@@ -27,6 +27,7 @@ class GraphCompressor
const std::unordered_set<NodeID> &traffic_lights,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor);
@@ -6,7 +6,7 @@
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_normalization_operation.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "util/attributes.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
@@ -116,14 +116,6 @@ class IntersectionGenerator
// own state, used to find the correct coordinates along a road
const CoordinateExtractor coordinate_extractor;
// check turn restrictions to find a node that is the only allowed target when coming from a
// node to an intersection
// d
// |
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
boost::optional<NodeID> GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
const NodeID node_at_intersection) const;
};
} // namespace guidance
+1 -1
View File
@@ -14,7 +14,7 @@
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/suffix_table.hpp"
#include "util/attributes.hpp"
+3 -1
View File
@@ -1,6 +1,7 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
@@ -26,7 +27,8 @@ struct TurnRestriction;
class RestrictionCompressor
{
public:
RestrictionCompressor(std::vector<TurnRestriction> &restrictions);
RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
// account for the compression of `from-via-to` into `from-to`
void Compress(const NodeID from, const NodeID via, const NodeID to);
+3 -2
View File
@@ -14,8 +14,9 @@ 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 &);
std::vector<ConditionalTurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction>,
const util::NodeBasedDynamicGraph &);
} // namespace extractor
} // namespace osrm
+101
View File
@@ -0,0 +1,101 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// allows easy check for whether a node intersection is present at a given intersection
template <typename restriction_type> class RestrictionIndex
{
public:
using value_type = restriction_type;
template <typename extractor_type>
RestrictionIndex(std::vector<restriction_type> &restrictions, extractor_type extractor);
bool IsIndexed(NodeID first, NodeID second) const;
auto Restrictions(NodeID first, NodeID second) const
{
return restriction_hash.equal_range(std::make_pair(first, second));
};
auto Size() const { return restriction_hash.size(); }
private:
boost::unordered_multimap<std::pair<NodeID, NodeID>, restriction_type *> restriction_hash;
};
template <typename restriction_type>
template <typename extractor_type>
RestrictionIndex<restriction_type>::RestrictionIndex(std::vector<restriction_type> &restrictions,
extractor_type extractor)
{
// build a multi-map
for (auto &restriction : restrictions)
restriction_hash.insert(std::make_pair(extractor(restriction), &restriction));
}
template <typename restriction_type>
bool RestrictionIndex<restriction_type>::IsIndexed(const NodeID first, const NodeID second) const
{
return restriction_hash.count(std::make_pair(first, second));
}
struct IndexNodeByFromAndVia
{
std::pair<NodeID, NodeID> operator()(const TurnRestriction &restriction)
{
const auto &node = restriction.AsNodeRestriction();
return std::make_pair(node.from, node.via);
};
};
// check wheter a turn is restricted within a restriction_index
template <typename restriction_map_type>
std::pair<bool, typename restriction_map_type::value_type *>
isRestricted(const NodeID from,
const NodeID via,
const NodeID to,
const restriction_map_type &restriction_map)
{
const auto range = restriction_map.Restrictions(from, via);
// check if a given node_restriction is targeting node
const auto to_is_restricted = [to](const auto &pair) {
const auto &restriction = *pair.second;
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
auto const &as_node = restriction.AsNodeRestriction();
auto const restricted = restriction.is_only ? (to != as_node.to) : (to == as_node.to);
return restricted;
}
return false;
};
auto itr = std::find_if(range.first, range.second, to_is_restricted);
if (itr != range.second)
return {true, itr->second};
else
return {false, NULL};
}
using RestrictionMap = RestrictionIndex<TurnRestriction>;
using ConditionalRestrictionMap = RestrictionIndex<ConditionalTurnRestriction>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
-110
View File
@@ -1,110 +0,0 @@
#ifndef RESTRICTION_MAP_HPP
#define RESTRICTION_MAP_HPP
#include "extractor/edge_based_edge.hpp"
#include "extractor/restriction.hpp"
#include "util/std_hash.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace osrm
{
namespace extractor
{
struct RestrictionSource
{
NodeID start_node;
NodeID via_node;
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via) {}
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
{
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
}
};
struct RestrictionTarget
{
NodeID target_node;
bool is_only;
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only) {}
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
{
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
}
};
}
}
namespace std
{
template <> struct hash<osrm::extractor::RestrictionSource>
{
size_t operator()(const osrm::extractor::RestrictionSource &r_source) const
{
return hash_val(r_source.start_node, r_source.via_node);
}
};
template <> struct hash<osrm::extractor::RestrictionTarget>
{
size_t operator()(const osrm::extractor::RestrictionTarget &r_target) const
{
return hash_val(r_target.target_node, r_target.is_only);
}
};
}
namespace osrm
{
namespace extractor
{
/**
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
*/
class RestrictionMap
{
public:
RestrictionMap() : m_count(0) {}
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
bool IsViaNode(const NodeID node) const;
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
// Checks if turn <u,v,w> is actually a turn restriction.
bool
CheckIfTurnIsRestricted(const NodeID node_u, const NodeID node_v, const NodeID node_w) const;
std::size_t size() const { return m_count; }
private:
// check of node is the start of any restriction
bool IsSourceNode(const NodeID node) const;
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
std::size_t m_count;
//! index -> list of (target, isOnly)
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
//! maps (start, via) -> bucket index
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
std::unordered_set<NodeID> m_restriction_start_nodes;
std::unordered_set<NodeID> m_no_turn_via_node_set;
};
}
}
#endif // RESTRICTION_MAP_HPP
+49
View File
@@ -1,6 +1,7 @@
#ifndef OSRM_EXTRACTOR_IO_HPP
#define OSRM_EXTRACTOR_IO_HPP
#include "conditional_turn_penalty.hpp"
#include "extractor/datasources.hpp"
#include "extractor/intersection_bearings_container.hpp"
#include "extractor/nbg_to_ebg.hpp"
@@ -273,6 +274,54 @@ inline void write(storage::io::FileWriter &writer,
};
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
}
inline void read(storage::io::FileReader &reader, ConditionalTurnPenalty &turn_penalty)
{
reader.ReadInto(turn_penalty.turn_offset);
reader.ReadInto(turn_penalty.location.lat);
reader.ReadInto(turn_penalty.location.lon);
auto const num_conditions = reader.ReadElementCount64();
turn_penalty.conditions.resize(num_conditions);
for (auto &condition : turn_penalty.conditions)
{
reader.ReadInto(condition.modifier);
storage::serialization::read(reader, condition.times);
storage::serialization::read(reader, condition.weekdays);
storage::serialization::read(reader, condition.monthdays);
}
}
inline void write(storage::io::FileWriter &writer, const ConditionalTurnPenalty &turn_penalty)
{
writer.WriteOne(turn_penalty.turn_offset);
writer.WriteOne(static_cast<util::FixedLatitude::value_type>(turn_penalty.location.lat));
writer.WriteOne(static_cast<util::FixedLongitude::value_type>(turn_penalty.location.lon));
writer.WriteElementCount64(turn_penalty.conditions.size());
for (const auto &c : turn_penalty.conditions)
{
writer.WriteOne(c.modifier);
storage::serialization::write(writer, c.times);
storage::serialization::write(writer, c.weekdays);
storage::serialization::write(writer, c.monthdays);
}
}
inline void write(storage::io::FileWriter &writer,
const std::vector<ConditionalTurnPenalty> &conditional_penalties)
{
writer.WriteElementCount64(conditional_penalties.size());
for (const auto &penalty : conditional_penalties)
write(writer, penalty);
}
inline void read(storage::io::FileReader &reader,
std::vector<ConditionalTurnPenalty> &conditional_penalties)
{
auto const num_elements = reader.ReadElementCount64();
conditional_penalties.resize(num_elements);
for (auto &penalty : conditional_penalties)
read(reader, penalty);
}
}
}
}
+10 -7
View File
@@ -8,6 +8,7 @@
#include <boost/unordered_map.hpp>
#include "extractor/restriction.hpp"
#include "extractor/restriction_index.hpp"
#include "util/integer_range.hpp"
#include "util/typedefs.hpp"
@@ -18,6 +19,8 @@ namespace osrm
namespace extractor
{
// The WayRestrictionMap uses ConditionalTurnRestrictions in general. Most restrictions will have
// empty conditions, though.
class WayRestrictionMap
{
public:
@@ -26,7 +29,7 @@ class WayRestrictionMap
NodeID from;
NodeID to;
};
WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions);
WayRestrictionMap(const std::vector<ConditionalTurnRestriction> &conditional_restrictions);
// Check if an edge between two nodes is a restricted turn. The check needs to be performed to
// find duplicated nodes during the creation of edge-based-edges
@@ -43,10 +46,13 @@ class WayRestrictionMap
std::vector<ViaWay> DuplicatedNodeRepresentatives() const;
// Access all duplicated NodeIDs for a set of nodes indicating a via way
util::range<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
// check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const;
// Get the restriction resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
const ConditionalTurnRestriction &GetRestriction(DuplicatedNodeID duplicated_node,
const NodeID to) const;
// changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified with a restriction group
@@ -76,11 +82,8 @@ class WayRestrictionMap
// EBN: 0 . | 2 | 3 | 4 ...
// duplicated node groups: ... | 5 | 7 | ...
std::vector<DuplicatedNodeID> duplicated_node_groups;
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_starts;
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_ends;
std::vector<TurnRestriction> restriction_data;
std::vector<ConditionalTurnRestriction> restriction_data;
RestrictionIndex<ConditionalTurnRestriction> restriction_starts;
};
} // namespace extractor
+1 -1
View File
@@ -97,7 +97,7 @@ template <typename T> void write(io::FileWriter &writer, const std::vector<T> &d
{
const auto count = data.size();
writer.WriteElementCount64(count);
return writer.WriteFrom(data.data(), count);
writer.WriteFrom(data.data(), count);
}
template <typename T> void read(io::FileReader &reader, util::vector_view<T> &data)