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

View File

@ -1,5 +1,7 @@
# 5.11.0
- Changes from 5.10:
- Features
- BREAKING: Added support for conditional via-way instructions. This features changes the file format of osrm.restrictions and requires re-extraction
# 5.10.0
- Changes from 5.9:

View File

@ -72,6 +72,75 @@ Feature: Car - Turn restrictions
| n | m | nj,pjm,pjm |
| s | m | js,pjm,pjm |
@no_turning @conditionals
Scenario: Car - Restriction With Compressed Geometry
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
n
|
i
|
j-k-l-m
|
s
"""
And the ways
| nodes |
| nij |
| js |
| jklm |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
When I route I should get
| from | to | route |
| n | m | nij,js,js,jklm,jklm |
@no_turning @conditionals
Scenario: Car - Restriction With Compressed Geometry and Traffic Signal
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
n
|
i
|
j-k-l-m
|
s
"""
And the ways
| nodes |
| nij |
| js |
| jklm |
And the nodes
| node | highway |
| i | traffic_signal |
| k | traffic_signal |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
When I route I should get
| from | to | route |
| n | m | nij,js,js,jklm,jklm |
@no_turning @conditionals
Scenario: Car - ignores except restriction
Given the extract extra arguments "--parse-conditional-restrictions"
@ -530,6 +599,81 @@ Feature: Car - Turn restrictions
| n | p | nj,js,js,jp,jp |
| m | p | mj,jp,jp |
@restriction-way
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
# condition is off
@restriction-way
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 12am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route |
| a | d | ab,be,de,de |
| a | f | ab,be,ef,ef |
| c | d | bc,be,de,de |
| c | f | bc,be,ef,ef |
# https://www.openstreetmap.org/#map=18/38.91099/-77.00888
@no_turning @conditionals
Scenario: Car - DC North capitol situation, two on one off
@ -769,15 +913,145 @@ Feature: Car - Turn restrictions
| dg |
And the relations
| type | way:from | way:to | way:via | restriction:conditional |
| restriction | ab | be | ef | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | ef | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | ed | dg | d | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route | # |
| a | f | ab,be,ef,ef | currently we do not handle conditional via-ways, this test will have to change when we do |
| f | 1 | ef,eh,gh,dg,dg | |
| from | to | route |
| a | f | ab,bc,bc,be,ef,ef |
| f | 1 | ef,eh,gh,dg,dg |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | be | de | no_right_turn |
# condition is off, but the general restriction should take precedence
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
| d
|
a
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
And the relations
| type | way:from | node:via | way:to | restriction:conditional |
| restriction | be | e | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
# way restriction is off, node-restriction is on
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,ef,ef,de,de | depart,turn left,turn left,continue uturn,new name straight,arrive | c,b,e,f,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
| d
|
a
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
And the relations
| type | way:from | node:via | way:to | restriction:conditional |
| restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
# node restrictino is off, way restriction is on
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |

View File

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

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);

View File

@ -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);
};
}

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);
};
}
}

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);

View File

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

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"

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);

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

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_

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

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);
}
}
}
}

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

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)

View File

@ -1,4 +1,5 @@
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/conditional_turn_penalty.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/files.hpp"
#include "extractor/guidance/turn_analysis.hpp"
@ -6,6 +7,7 @@
#include "extractor/scripting_environment.hpp"
#include "extractor/suffix_table.hpp"
#include "extractor/serialization.hpp"
#include "storage/io.hpp"
#include "util/assert.hpp"
@ -20,8 +22,10 @@
#include "util/timing_util.hpp"
#include <boost/assert.hpp>
#include <boost/functional/hash.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include "boost/unordered_map.hpp"
#include <algorithm>
#include <cmath>
#include <iomanip>
@ -35,12 +39,26 @@
#include <tbb/pipeline.h>
#include <tbb/task_scheduler_init.h>
namespace std
{
template <> struct hash<std::pair<NodeID, NodeID>>
{
std::size_t operator()(const std::pair<NodeID, NodeID> &mk) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, mk.first);
boost::hash_combine(seed, mk.second);
return seed;
}
};
}
namespace osrm
{
namespace extractor
{
// Configuration to find representative candidate for turn angle calculations
// Configuration to find representative candidate for turn angle calculations
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
CompressedEdgeContainer &compressed_edge_container,
@ -199,7 +217,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
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_node_restriction_map,
const WayRestrictionMap &way_restriction_map)
{
TIMER_START(renumber);
@ -220,7 +240,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
turn_weight_penalties_filename,
turn_duration_penalties_filename,
turn_penalties_index_filename,
conditional_penalties_filename,
node_restriction_map,
conditional_node_restriction_map,
way_restriction_map);
TIMER_STOP(generate_edges);
@ -384,7 +406,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
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_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map)
{
@ -427,6 +451,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto weight_multiplier =
scripting_environment.GetProfileProperties().GetWeightMultiplier();
// filled in during next stage, kept alive through following scope
std::vector<Conditional> conditionals;
// The following block generates the edge-based-edges using a parallel processing
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
// `generator_stage`,
@ -482,7 +508,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
};
// same as IntersectionData, but grouped with edge to allow sorting after creating. Edges
// are out of order
// can be out of order
struct EdgeWithData
{
EdgeBasedEdge edge;
@ -497,10 +523,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
std::size_t nodes_processed = 0;
IntersectionData continuous_data;
std::vector<EdgeWithData> delayed_data;
std::vector<Conditional> conditionals;
};
// Generate edges for either artificial nodes or the main graph
const auto generate_edge = [this, &scripting_environment, weight_multiplier](
const auto generate_edge = [this,
&scripting_environment,
weight_multiplier,
&conditional_restriction_map](
// what nodes will be used? In most cases this will be the id stored in the edge_data.
// In case of duplicated nodes (e.g. due to via-way restrictions), one/both of these
// might refer to a newly added edge based node
@ -514,6 +544,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto &intersection,
const auto &turn,
const auto entry_class_id) {
const auto node_restricted = isRestricted(node_along_road_entering,
node_at_center_of_intersection,
m_node_based_graph->GetTarget(turn.eid),
conditional_restriction_map);
boost::optional<Conditional> conditional = boost::none;
if (node_restricted.first)
{
auto const &conditions = node_restricted.second->condition;
// get conditions of the restriction limiting the node
conditional = {{edge_based_node_from,
edge_based_node_to,
{static_cast<std::uint64_t>(-1),
m_coordinates[node_at_center_of_intersection],
conditions}}};
}
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from);
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to);
@ -573,15 +621,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto &from_node =
isTrivial ? node_along_road_entering
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
const auto &via_node =
m_compressed_edge_container.GetLastEdgeTargetID(node_based_edge_from);
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node};
lookup::TurnIndexBlock turn_index_block = {
from_node, node_at_center_of_intersection, to_node};
// insert data into the designated buffer
return EdgeWithData{
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data};
return std::make_pair(
EdgeWithData{
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data},
conditional);
};
// Second part of the pipeline is where the intersection analysis is done for
@ -720,7 +769,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_number_of_edge_based_nodes);
{ // scope to forget edge_with_data after
const auto edge_with_data =
const auto edge_with_data_and_condition =
generate_edge(edge_data1.edge_id,
target_id,
node_along_road_entering,
@ -731,15 +780,21 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn,
entry_class_id);
buffer->continuous_data.edges_list.push_back(edge_with_data.edge);
buffer->continuous_data.edges_list.push_back(
edge_with_data_and_condition.first.edge);
buffer->continuous_data.turn_indexes.push_back(
edge_with_data.turn_index);
edge_with_data_and_condition.first.turn_index);
buffer->continuous_data.turn_weight_penalties.push_back(
edge_with_data.turn_weight_penalty);
edge_with_data_and_condition.first.turn_weight_penalty);
buffer->continuous_data.turn_duration_penalties.push_back(
edge_with_data.turn_duration_penalty);
edge_with_data_and_condition.first.turn_duration_penalty);
buffer->continuous_data.turn_data_container.push_back(
edge_with_data.turn_data);
edge_with_data_and_condition.first.turn_data);
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
}
// when turning off a a via-way turn restriction, we need to not only
@ -764,25 +819,73 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
auto const node_at_end_of_turn =
m_node_based_graph->GetTarget(turn.eid);
const auto is_restricted = way_restriction_map.IsRestricted(
const auto is_way_restricted = way_restriction_map.IsRestricted(
duplicated_node_id, node_at_end_of_turn);
if (is_restricted)
continue;
if (is_way_restricted)
{
// add into delayed data
auto edge_with_data = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
auto const restriction = way_restriction_map.GetRestriction(
duplicated_node_id, node_at_end_of_turn);
buffer->delayed_data.push_back(std::move(edge_with_data));
if (restriction.condition.empty())
continue;
// add into delayed data
auto edge_with_data_and_condition = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
std::move(edge_with_data_and_condition.first));
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
// also add the conditions for the way
if (is_way_restricted && !restriction.condition.empty())
{
// add a new conditional for the edge we just created
buffer->conditionals.push_back(
{NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
{static_cast<std::uint64_t>(-1),
m_coordinates[node_at_center_of_intersection],
restriction.condition}});
}
}
else
{
auto edge_with_data_and_condition = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
std::move(edge_with_data_and_condition.first));
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
}
}
}
}
@ -827,6 +930,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
data.turn_indexes.begin(),
data.turn_indexes.end());
conditionals.insert(
conditionals.end(), buffer->conditionals.begin(), buffer->conditionals.end());
// Buffer writes to reduce syscall count
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
{
@ -879,6 +985,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
}
});
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the
// ordering, we
// do not really have a choice but to index the conditional penalties and walk over all
// edge-based-edges to find the ID of the edge
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
{
util::Log() << "Writing " << indexed_conditionals.size()
<< " conditional turn penalties...";
// write conditional turn penalties into the restrictions file
storage::io::FileWriter writer(conditional_penalties_filename,
storage::io::FileWriter::GenerateFingerprint);
extractor::serialization::write(writer, indexed_conditionals);
}
// write weight penalties per turn
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size());
{
@ -918,11 +1038,36 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
util::Log() << " skips " << restricted_turns_counter << " turns, "
"defined by "
<< node_restriction_map.size() << " restrictions";
<< node_restriction_map.Size() << " restrictions";
util::Log() << " skips " << skipped_uturns_counter << " U turns";
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
}
std::vector<ConditionalTurnPenalty>
EdgeBasedGraphFactory::IndexConditionals(std::vector<Conditional> &&conditionals) const
{
boost::unordered_multimap<std::pair<NodeID, NodeID>, ConditionalTurnPenalty *> index;
// build and index of all conditional restrictions
for (auto &conditional : conditionals)
index.insert(std::make_pair(std::make_pair(conditional.from_node, conditional.to_node),
&conditional.penalty));
std::vector<ConditionalTurnPenalty> indexed_restrictions;
for (auto const &edge : m_edge_based_edge_list)
{
auto const range = index.equal_range(std::make_pair(edge.source, edge.target));
for (auto itr = range.first; itr != range.second; ++itr)
{
itr->second->turn_offset = edge.data.turn_id;
indexed_restrictions.push_back(*itr->second);
}
}
return indexed_restrictions;
}
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
{
std::vector<util::guidance::BearingClass> result(bearing_class_hash.data.size());

View File

@ -126,7 +126,6 @@ ExtractionContainers::ExtractionContainers()
*/
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
const std::string &osrm_path,
const std::string &restrictions_file_name,
const std::string &name_file_name)
{
storage::io::FileWriter file_out(osrm_path, storage::io::FileWriter::GenerateFingerprint);
@ -139,7 +138,6 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
WriteEdges(file_out);
PrepareRestrictions();
WriteConditionalRestrictions(restrictions_file_name);
WriteCharData(name_file_name);
}
@ -633,16 +631,6 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
util::Log() << "Processed " << max_internal_node_id << " nodes";
}
void ExtractionContainers::WriteConditionalRestrictions(const std::string &path)
{
std::uint64_t written_restriction_count = conditional_turn_restrictions.size();
storage::io::FileWriter restrictions_out_file(path,
storage::io::FileWriter::GenerateFingerprint);
serialization::write(restrictions_out_file, conditional_turn_restrictions);
util::Log() << "number of conditional restrictions written to disk: "
<< written_restriction_count;
}
void ExtractionContainers::PrepareRestrictions()
{
@ -837,7 +825,8 @@ void ExtractionContainers::PrepareRestrictions()
const auto transform_into_internal_types =
[&](const InputConditionalTurnRestriction &external_restriction) {
// unconditional restriction
if (external_restriction.condition.empty())
if (external_restriction.condition.empty() &&
external_restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
TurnRestriction restriction;
restriction.is_only = external_restriction.is_only;
@ -851,7 +840,9 @@ void ExtractionContainers::PrepareRestrictions()
restriction.is_only = external_restriction.is_only;
restriction.condition = std::move(external_restriction.condition);
if (transform(external_restriction, restriction))
{
conditional_turn_restrictions.push_back(std::move(restriction));
}
}
};

View File

@ -23,7 +23,7 @@
#include "util/timing_util.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/way_restriction_map.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
@ -110,7 +110,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
guidance::LaneDescriptionMap turn_lane_map;
std::vector<TurnRestriction> turn_restrictions;
std::tie(turn_lane_map, turn_restrictions) =
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
ParseOSMData(scripting_environment, number_of_threads);
// Transform the node-based graph that OSM is based on into an edge-based graph
@ -138,6 +139,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
edge_based_edge_list,
config.GetPath(".osrm.icd").string(),
turn_restrictions,
conditional_turn_restrictions,
turn_lane_map);
auto number_of_node_based_nodes = graph_size.first;
@ -190,7 +192,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
return 0;
}
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
std::tuple<guidance::LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>>
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
{
@ -333,7 +337,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
extraction_containers.PrepareData(scripting_environment,
config.GetPath(".osrm").string(),
config.GetPath(".osrm.restrictions").string(),
config.GetPath(".osrm.names").string());
auto profile_properties = scripting_environment.GetProfileProperties();
@ -344,7 +347,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
return std::make_tuple(std::move(turn_lane_map),
std::move(extraction_containers.unconditional_turn_restrictions));
std::move(extraction_containers.unconditional_turn_restrictions),
std::move(extraction_containers.conditional_turn_restrictions));
}
void Extractor::FindComponents(unsigned max_edge_id,
@ -440,18 +444,19 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::pair<std::size_t, EdgeID>
Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
std::vector<util::Coordinate> &coordinates,
extractor::PackedOSMIDs &osm_node_ids,
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions,
guidance::LaneDescriptionMap &turn_lane_map)
std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
ScriptingEnvironment &scripting_environment,
std::vector<util::Coordinate> &coordinates,
extractor::PackedOSMIDs &osm_node_ids,
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
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)
{
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_signals;
@ -465,10 +470,12 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
traffic_signals,
scripting_environment,
turn_restrictions,
conditional_turn_restrictions,
*node_based_graph,
compressed_edge_container);
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), *node_based_graph);
conditional_turn_restrictions =
removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph);
util::NameTable name_table(config.GetPath(".osrm.names").string());
@ -484,8 +491,20 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
const auto create_edge_based_edges = [&]() {
// scoped to relase intermediate datastructures right after the call
RestrictionMap via_node_restriction_map(turn_restrictions);
WayRestrictionMap via_way_restriction_map(turn_restrictions);
std::vector<TurnRestriction> node_restrictions;
for (auto const &t : turn_restrictions)
if (t.Type() == RestrictionType::NODE_RESTRICTION)
node_restrictions.push_back(t);
std::vector<ConditionalTurnRestriction> conditional_node_restrictions;
for (auto const &t : conditional_turn_restrictions)
if (t.Type() == RestrictionType::NODE_RESTRICTION)
conditional_node_restrictions.push_back(t);
RestrictionMap via_node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions);
ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions,
IndexNodeByFromAndVia());
turn_restrictions.clear();
turn_restrictions.shrink_to_fit();
@ -496,13 +515,14 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
config.GetPath(".osrm.turn_duration_penalties").string(),
config.GetPath(".osrm.turn_penalties_index").string(),
config.GetPath(".osrm.cnbg_to_ebg").string(),
config.GetPath(".osrm.restrictions").string(),
via_node_restriction_map,
conditional_node_restriction_map,
via_way_restriction_map);
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
};
const auto number_of_edge_based_nodes = create_edge_based_edges();
compressed_edge_container.PrintStatistics();
// The osrm-partition tool requires the compressed node based graph with an embedding.

View File

@ -20,17 +20,19 @@ namespace osrm
namespace extractor
{
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor)
void GraphCompressor::Compress(
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor)
{
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
RestrictionCompressor restriction_compressor(turn_restrictions);
RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
// indicated `directed` barriers
@ -51,6 +53,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
}
};
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
remember_via_nodes);
{
const auto weight_multiplier =

View File

@ -236,8 +236,25 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
{
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
// check if there is a single valid turn entering the current intersection
const auto only_valid_turn = GetOnlyAllowedTurnIfExistent(previous_node, node_at_intersection);
// request all turn restrictions
auto const restrictions = restriction_map.Restrictions(previous_node, node_at_intersection);
// 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`
const auto find_only_valid_turn = [&]() -> boost::optional<NodeID> {
const auto itr = std::find_if(restrictions.first, restrictions.second, [](auto pair) {
return pair.second->is_only;
});
if (itr != restrictions.second)
return {itr->second->AsNodeRestriction().to};
else
return boost::none;
};
const auto only_valid_turn = find_only_valid_turn();
// barriers change our behaviour regarding u-turns
const bool is_barrier_node = barrier_nodes.find(node_at_intersection) != barrier_nodes.end();
@ -258,12 +275,14 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
const auto is_restricted = [&](const NodeID destination) {
// check if we have a dedicated destination
if (only_valid_turn && *only_valid_turn != destination)
return true;
if (only_valid_turn)
return *only_valid_turn != destination;
// not explicitly forbidden
return restriction_map.CheckIfTurnIsRestricted(
previous_node, node_at_intersection, destination);
// check if explicitly forbidden
return restrictions.second !=
std::find_if(restrictions.first, restrictions.second, [&](const auto &restriction) {
return restriction.second->AsNodeRestriction().to == destination;
});
};
const auto is_allowed_turn = [&](const IntersectionShapeData &road) {
@ -396,21 +415,6 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
return intersection_view;
}
boost::optional<NodeID>
IntersectionGenerator::GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
const NodeID node_at_intersection) const
{
// If only restrictions refer to invalid ways somewhere far away, we rather ignore the
// restriction than to not route over the intersection at all.
const auto only_restriction_to_node =
restriction_map.CheckForEmanatingIsOnlyTurn(coming_from_node, node_at_intersection);
if (only_restriction_to_node != SPECIAL_NODEID)
return only_restriction_to_node;
// Ignore broken only restrictions.
return boost::none;
}
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
{
return coordinate_extractor;

View File

@ -10,7 +10,9 @@ namespace osrm
namespace extractor
{
RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restrictions)
RestrictionCompressor::RestrictionCompressor(
std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
{
// add a node restriction ptr to the starts/ends maps, needs to be a reference!
auto index = [&](auto &element) {
@ -35,6 +37,9 @@ RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restr
// add all restrictions as their respective startend pointers
std::for_each(restrictions.begin(), restrictions.end(), index_starts_and_ends);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
index_starts_and_ends);
}
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)

View File

@ -10,8 +10,8 @@ namespace osrm
namespace extractor
{
std::vector<TurnRestriction>
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
std::vector<ConditionalTurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions,
const util::NodeBasedDynamicGraph &node_based_graph)
{
// definition of what we presume to be a valid via-node restriction

View File

@ -1,138 +0,0 @@
#include "extractor/restriction_map.hpp"
#include <boost/assert.hpp>
namespace osrm
{
namespace extractor
{
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
{
// decompose restriction consisting of a start, via and end node into a
// a pair of starting edge and a list of all end nodes
for (auto &restriction : restriction_list)
{
// only handle node restrictions here
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
continue;
const auto &node_restriction = restriction.AsNodeRestriction();
BOOST_ASSERT(node_restriction.Valid());
// This downcasting is OK because when this is called, the node IDs have been
// renumbered into internal values, which should be well under 2^32
// This will be a problem if we have more than 2^32 actual restrictions
BOOST_ASSERT(node_restriction.from < std::numeric_limits<NodeID>::max());
BOOST_ASSERT(node_restriction.via < std::numeric_limits<NodeID>::max());
m_restriction_start_nodes.insert(node_restriction.from);
m_no_turn_via_node_set.insert(node_restriction.via);
// This explicit downcasting is also OK for the same reason.
RestrictionSource restriction_source = {static_cast<NodeID>(node_restriction.from),
static_cast<NodeID>(node_restriction.via)};
std::size_t index;
auto restriction_iter = m_restriction_map.find(restriction_source);
if (restriction_iter == m_restriction_map.end())
{
index = m_restriction_bucket_list.size();
m_restriction_bucket_list.resize(index + 1);
m_restriction_map.emplace(restriction_source, index);
}
else
{
index = restriction_iter->second;
// Map already contains an is_only_*-restriction
if (m_restriction_bucket_list.at(index).begin()->is_only)
{
continue;
}
else if (restriction.is_only)
{
// We are going to insert an is_only_*-restriction. There can be only one.
m_count -= m_restriction_bucket_list.at(index).size();
m_restriction_bucket_list.at(index).clear();
}
}
++m_count;
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only);
}
}
bool RestrictionMap::IsViaNode(const NodeID node) const
{
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
}
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return SPECIAL_NODEID;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter != m_restriction_map.end())
{
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (restriction_target.is_only)
{
return restriction_target.target_node;
}
}
}
return SPECIAL_NODEID;
}
// Checks if turn <u,v,w> is actually a turn restriction.
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
const NodeID node_v,
const NodeID node_w) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return false;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter == m_restriction_map.end())
{
return false;
}
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (node_w == restriction_target.target_node && // target found
!restriction_target.is_only) // and not an only_-restr.
{
return true;
}
// We could be tempted to check for `only` restrictions here as well. However, that check is
// actually perfomed in intersection generation where we can also verify if the only
// restriction is valid at all.
}
return false;
}
// check of node is the start of any restriction
bool RestrictionMap::IsSourceNode(const NodeID node) const
{
return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
}
}
}

View File

@ -1,6 +1,7 @@
#include "extractor/way_restriction_map.hpp"
#include "util/for_each_pair.hpp"
#include <functional>
#include <iterator>
#include <tuple>
#include <utility>
@ -28,12 +29,46 @@ struct FindViaWay
}
};
} // namespace
WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions)
template <typename restriction_type> auto asDuplicatedNode(const restriction_type &restriction)
{
// get all way restrictions
const auto extract_restrictions = [this](const auto &turn_restriction) {
auto &way = restriction.AsWayRestriction();
// group restrictions by the via-way. On same via-ways group by from
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
};
template <typename restriction_type> struct CompareByDuplicatedNode
{
bool operator()(const ConditionalTurnRestriction &lhs, const ConditionalTurnRestriction &rhs)
{
if (asDuplicatedNode(lhs) < asDuplicatedNode(rhs))
{
return true;
}
else if (asDuplicatedNode(rhs) < asDuplicatedNode(lhs))
{
return false;
}
else
{
const auto lhs_to = lhs.AsWayRestriction().out_restriction.to;
const auto rhs_to = rhs.AsWayRestriction().out_restriction.to;
const bool has_conditions_lhs = !lhs.condition.empty();
const bool has_conditions_rhs = !rhs.condition.empty();
return std::tie(lhs_to, lhs.is_only, has_conditions_lhs) <
std::tie(rhs_to, rhs.is_only, has_conditions_rhs);
}
}
};
template <typename restriction_type>
std::vector<restriction_type>
extractRestrictions(const std::vector<restriction_type> &turn_restrictions)
{
std::vector<restriction_type> result;
for (const auto &turn_restriction : turn_restrictions)
{
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
const auto &way = turn_restriction.AsWayRestriction();
@ -41,32 +76,32 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
// so far we can only handle restrictions that are not interrupted
if (way.in_restriction.via == way.out_restriction.from &&
way.in_restriction.to == way.out_restriction.via)
restriction_data.push_back(turn_restriction);
result.push_back(turn_restriction);
}
};
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);
}
std::sort(result.begin(), result.end(), CompareByDuplicatedNode<restriction_type>());
auto new_end = std::unique(result.begin(), result.end());
result.erase(new_end, result.end());
return result;
}
const auto as_duplicated_node = [](auto const &restriction) {
auto &way = restriction.AsWayRestriction();
// group restrictions by the via-way. On same via-ways group by from
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
};
const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) {
return as_duplicated_node(lhs) < as_duplicated_node(rhs);
};
std::sort(restriction_data.begin(), restriction_data.end(), by_duplicated_node);
// map all way restrictions into access containers
for (RestrictionID index = 0; index < restriction_data.size(); ++index)
template <typename restriction_type> struct ByInFromAndVia
{
std::pair<NodeID, NodeID> operator()(const restriction_type &restriction)
{
const auto &restriction = restriction_data[index];
const auto &way = restriction.AsWayRestriction();
restriction_starts.insert(
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
};
return std::make_pair(way.in_restriction.from, way.in_restriction.via);
}
};
} // namespace
// get all way restrictions
WayRestrictionMap::WayRestrictionMap(
const std::vector<ConditionalTurnRestriction> &turn_restrictions_)
: restriction_data(extractRestrictions(turn_restrictions_)),
restriction_starts(restriction_data, ByInFromAndVia<ConditionalTurnRestriction>())
{
std::size_t offset = 1;
// the first group starts at 0
if (!restriction_data.empty())
@ -74,8 +109,10 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
auto const add_offset_on_new_groups = [&](auto const &lhs, auto const &rhs) {
BOOST_ASSERT(rhs == restriction_data[offset]);
BOOST_ASSERT(lhs.Type() == RestrictionType::WAY_RESTRICTION);
BOOST_ASSERT(rhs.Type() == RestrictionType::WAY_RESTRICTION);
// add a new lower bound for rhs
if (as_duplicated_node(lhs) != as_duplicated_node(rhs))
if (asDuplicatedNode(lhs) != asDuplicatedNode(rhs))
duplicated_node_groups.push_back(offset);
++offset;
};
@ -115,7 +152,7 @@ DuplicatedNodeID WayRestrictionMap::AsDuplicatedNodeID(const RestrictionID restr
return distance_to_upper_bound - 1;
}
util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
const NodeID to) const
{
const auto duplicated_node_range_itr = std::equal_range(
@ -125,9 +162,13 @@ util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID
return std::distance(restriction_data.begin(), itr);
};
return util::irange<DuplicatedNodeID>(
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)),
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second)));
auto first = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first));
auto end = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second));
std::vector<DuplicatedNodeID> result(end - first);
std::iota(result.begin(), result.end(), first);
return result;
}
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
@ -138,6 +179,7 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
restriction_index != duplicated_node_groups[duplicated_node + 1];
++restriction_index)
{
BOOST_ASSERT(restriction_index < restriction_data.size());
const auto &restriction = restriction_data[restriction_index];
const auto &way = restriction.AsWayRestriction();
@ -149,6 +191,32 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
return false;
}
ConditionalTurnRestriction const &
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const
{
// loop over all restrictions associated with the node. Mark as restricted based on
// is_only/restricted targets
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node];
restriction_index != duplicated_node_groups[duplicated_node + 1];
++restriction_index)
{
BOOST_ASSERT(restriction_index < restriction_data.size());
const auto &restriction = restriction_data[restriction_index];
const auto &way = restriction.AsWayRestriction();
if (restriction.is_only && (way.out_restriction.to != to))
{
return restriction;
}
else if (!restriction.is_only && (to == way.out_restriction.to))
{
return restriction;
}
}
throw("Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
"calling GetRestriction");
}
std::vector<WayRestrictionMap::ViaWay> WayRestrictionMap::DuplicatedNodeRepresentatives() const
{
std::vector<ViaWay> result;
@ -169,19 +237,19 @@ NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node,
const NodeID node_based_to,
const NodeID number_of_edge_based_nodes) const
{
auto range = restriction_starts.equal_range(std::make_pair(node_based_from, node_based_via));
auto range = restriction_starts.Restrictions(node_based_from, node_based_via);
// returns true if the ID saved in an iterator belongs to a turn restriction that references
// node_based_to as destination of the `in_restriction`
const auto restriction_targets_to = [node_based_to, this](const auto &pair) {
return restriction_data[pair.second].AsWayRestriction().in_restriction.to == node_based_to;
return pair.second->AsWayRestriction().in_restriction.to == node_based_to;
};
const auto itr = std::find_if(range.first, range.second, restriction_targets_to);
// in case we found a matching restriction, we can remap the edge_based_node
if (itr != range.second)
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() +
AsDuplicatedNodeID(itr->second);
AsDuplicatedNodeID(itr->second - &restriction_data[0]);
else
return edge_based_node;
}

View File

@ -7,6 +7,7 @@
#include "extractor/node_based_edge.hpp"
#include "extractor/packed_osm_ids.hpp"
#include "extractor/restriction.hpp"
#include "extractor/serialization.hpp"
#include "storage/io.hpp"
@ -443,20 +444,16 @@ updateTurnPenalties(const UpdaterConfig &config,
return updated_turns;
}
bool IsRestrictionValid(const Timezoner &tz_handler,
const extractor::ConditionalTurnRestriction &turn,
const std::vector<util::Coordinate> &coordinates)
bool IsRestrictionValid(const Timezoner &tz_handler, const extractor::ConditionalTurnPenalty &turn)
{
BOOST_ASSERT(!turn.condition.empty());
BOOST_ASSERT(!turn.conditions.empty());
// we utilize the via node (first on ways) to represent the turn restriction
auto const via = turn.Type() == extractor::RestrictionType::WAY_RESTRICTION
? turn.AsWayRestriction().in_restriction.to
: turn.AsNodeRestriction().via;
auto const via = turn.location;
const auto lon = static_cast<double>(toFloating(coordinates[via].lon));
const auto lat = static_cast<double>(toFloating(coordinates[via].lat));
const auto &condition = turn.condition;
const auto lon = static_cast<double>(toFloating(via.lon));
const auto lat = static_cast<double>(toFloating(via.lat));
const auto &conditions = turn.conditions;
// Get local time of the restriction
const auto &local_time = tz_handler(point_t{lon, lat});
@ -469,85 +466,27 @@ bool IsRestrictionValid(const Timezoner &tz_handler,
// TODO: parsing will fail for combined conditions, e.g. Sa-Su AND weight>7
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions#Combined_conditions:_AND
if (osrm::util::CheckOpeningHours(condition, *local_time))
return true;
return false;
return osrm::util::CheckOpeningHours(conditions, *local_time);
}
std::vector<std::uint64_t>
updateConditionalTurns(const UpdaterConfig &config,
std::vector<TurnPenalty> &turn_weight_penalties,
const std::vector<extractor::ConditionalTurnRestriction> &conditional_turns,
std::vector<util::Coordinate> &coordinates,
updateConditionalTurns(std::vector<TurnPenalty> &turn_weight_penalties,
const std::vector<extractor::ConditionalTurnPenalty> &conditional_turns,
Timezoner time_zone_handler)
{
// Mapped file pointer for turn indices
boost::iostreams::mapped_file_source turn_index_region;
auto turn_index_blocks = util::mmapFile<extractor::lookup::TurnIndexBlock>(
config.GetPath(".osrm.turn_penalties_index"), turn_index_region);
std::vector<std::uint64_t> updated_turns;
if (conditional_turns.size() == 0)
return updated_turns;
// TODO make this into a function
LookupTable<std::tuple<NodeID, NodeID>, NodeID> is_only_lookup;
std::unordered_set<std::tuple<NodeID, NodeID, NodeID>,
std::hash<std::tuple<NodeID, NodeID, NodeID>>>
is_no_set;
for (const auto &node_or_way : conditional_turns)
for (const auto &penalty : conditional_turns)
{
// TODO handle conditional turn restrictions for via-ways (look-up doesn't work here)
// https://github.com/Project-OSRM/osrm-backend/issues/2681#issuecomment-313376385
if (node_or_way.Type() == extractor::RestrictionType::WAY_RESTRICTION)
continue;
if (!IsRestrictionValid(time_zone_handler, node_or_way, coordinates))
continue;
// TODO get rid of this, when we can handle way restrictions
const auto &c = node_or_way.AsNodeRestriction();
// only add restrictions to the lookups if the restriction is valid now
if (node_or_way.is_only)
if (IsRestrictionValid(time_zone_handler, penalty))
{
is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to});
}
else
{
is_no_set.insert({std::make_tuple(c.from, c.via, c.to)});
std::cout << "Disabling: " << penalty.turn_offset << std::endl;
turn_weight_penalties[penalty.turn_offset] = INVALID_TURN_PENALTY;
updated_turns.push_back(penalty.turn_offset);
}
}
for (std::uint64_t edge_index = 0; edge_index < turn_weight_penalties.size(); ++edge_index)
{
const extractor::lookup::TurnIndexBlock internal_turn = turn_index_blocks[edge_index];
const auto is_no_tuple =
std::make_tuple(internal_turn.from_id, internal_turn.via_id, internal_turn.to_id);
const auto is_only_tuple = std::make_tuple(internal_turn.from_id, internal_turn.via_id);
// turn has a no_* restriction
if (is_no_set.find(is_no_tuple) != is_no_set.end())
{
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
updated_turns.push_back(edge_index);
}
// turn has an only_* restriction
else if (is_only_lookup(is_only_tuple))
{
// with only_* restrictions, the turn on which the restriction is tagged is valid
if (*is_only_lookup(is_only_tuple) == internal_turn.to_id)
continue;
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
updated_turns.push_back(edge_index);
}
}
return updated_turns;
}
}
@ -638,7 +577,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
load_profile_properties);
}
std::vector<extractor::ConditionalTurnRestriction> conditional_turns;
std::vector<extractor::ConditionalTurnPenalty> conditional_turns;
if (update_conditional_turns)
{
using storage::io::FileReader;
@ -696,8 +635,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
}
const Timezoner time_zone_handler = Timezoner(config.tz_file_path, config.valid_now);
auto updated_turn_penalties = updateConditionalTurns(
config, turn_weight_penalties, conditional_turns, coordinates, time_zone_handler);
auto updated_turn_penalties =
updateConditionalTurns(turn_weight_penalties, conditional_turns, time_zone_handler);
const auto offset = updated_segments.size();
updated_segments.resize(offset + updated_turn_penalties.size());
// we need to re-compute all edges that have updated turn penalties.

View File

@ -56,6 +56,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
@ -73,8 +74,13 @@ BOOST_AUTO_TEST_CASE(long_road_test)
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data));
Graph graph(5, edges);
compressor.Compress(
barrier_nodes, traffic_lights, scripting_environment, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID);
@ -95,6 +101,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
@ -125,8 +132,13 @@ BOOST_AUTO_TEST_CASE(loop_test)
BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data));
Graph graph(6, edges);
compressor.Compress(
barrier_nodes, traffic_lights, scripting_environment, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
@ -149,6 +161,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
@ -166,8 +179,13 @@ BOOST_AUTO_TEST_CASE(t_intersection)
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
Graph graph(4, edges);
compressor.Compress(
barrier_nodes, traffic_lights, scripting_environment, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
@ -184,6 +202,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
@ -195,8 +214,13 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
Graph graph(5, edges);
compressor.Compress(
barrier_nodes, traffic_lights, scripting_environment, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
@ -212,6 +236,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
@ -221,8 +246,13 @@ BOOST_AUTO_TEST_CASE(direction_changes)
edges[1].data.reversed = true;
Graph graph(5, edges);
compressor.Compress(
barrier_nodes, traffic_lights, scripting_environment, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);