diff --git a/CHANGELOG.md b/CHANGELOG.md index ce3d10706..7995afbcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/features/car/conditional_restrictions.feature b/features/car/conditional_restrictions.feature index e0d50a0d4..d2adb67e3 100644 --- a/features/car/conditional_restrictions.feature +++ b/features/car/conditional_restrictions.feature @@ -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 | diff --git a/include/extractor/conditional_turn_penalty.hpp b/include/extractor/conditional_turn_penalty.hpp new file mode 100644 index 000000000..ef47cbbd8 --- /dev/null +++ b/include/extractor/conditional_turn_penalty.hpp @@ -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 +#include + +#include + +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 conditions; +}; + +} // namespace extractor +} // namespace osrm + +#endif // OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_ diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 972eabe95..72af096a6 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -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 + IndexConditionals(std::vector &&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 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); diff --git a/include/extractor/extraction_containers.hpp b/include/extractor/extraction_containers.hpp index aa95064ca..0fb3f5a7b 100644 --- a/include/extractor/extraction_containers.hpp +++ b/include/extractor/extraction_containers.hpp @@ -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); }; } diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index acc811fae..a3f1b796c 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -56,7 +56,9 @@ class Extractor private: ExtractorConfig config; - std::tuple> + std::tuple, + std::vector> ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads); std::pair @@ -70,6 +72,7 @@ class Extractor util::DeallocatingVector &edge_based_edge_list, const std::string &intersection_class_output_file, std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions, guidance::LaneDescriptionMap &turn_lane_map); void FindComponents(unsigned max_edge_id, const util::DeallocatingVector &input_edge_list, @@ -89,6 +92,10 @@ class Extractor static void WriteCompressedNodeBasedGraph(const std::string &path, const util::NodeBasedDynamicGraph &graph, const std::vector &coordiantes); + + void WriteConditionalRestrictions( + const std::string &path, + std::vector &conditional_turn_restrictions); }; } } diff --git a/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp index a8772b170..2cb6c1f8a 100644 --- a/include/extractor/graph_compressor.hpp +++ b/include/extractor/graph_compressor.hpp @@ -27,6 +27,7 @@ class GraphCompressor const std::unordered_set &traffic_lights, ScriptingEnvironment &scripting_environment, std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions, util::NodeBasedDynamicGraph &graph, CompressedEdgeContainer &geometry_compressor); diff --git a/include/extractor/guidance/intersection_generator.hpp b/include/extractor/guidance/intersection_generator.hpp index 4f9cc5025..d012c81d8 100644 --- a/include/extractor/guidance/intersection_generator.hpp +++ b/include/extractor/guidance/intersection_generator.hpp @@ -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 GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node, - const NodeID node_at_intersection) const; }; } // namespace guidance diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index e1cd80416..41b56107f 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -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" diff --git a/include/extractor/restriction_compressor.hpp b/include/extractor/restriction_compressor.hpp index f3136760c..60fd5ccf4 100644 --- a/include/extractor/restriction_compressor.hpp +++ b/include/extractor/restriction_compressor.hpp @@ -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 @@ -26,7 +27,8 @@ struct TurnRestriction; class RestrictionCompressor { public: - RestrictionCompressor(std::vector &restrictions); + RestrictionCompressor(std::vector &restrictions, + std::vector &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); diff --git a/include/extractor/restriction_filter.hpp b/include/extractor/restriction_filter.hpp index c8c6d7293..0b23e3076 100644 --- a/include/extractor/restriction_filter.hpp +++ b/include/extractor/restriction_filter.hpp @@ -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 removeInvalidRestrictions(std::vector, - const util::NodeBasedDynamicGraph &); +std::vector +removeInvalidRestrictions(std::vector, + const util::NodeBasedDynamicGraph &); } // namespace extractor } // namespace osrm diff --git a/include/extractor/restriction_index.hpp b/include/extractor/restriction_index.hpp new file mode 100644 index 000000000..350a89d5e --- /dev/null +++ b/include/extractor/restriction_index.hpp @@ -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 + +#include +#include + +namespace osrm +{ +namespace extractor +{ + +// allows easy check for whether a node intersection is present at a given intersection +template class RestrictionIndex +{ + public: + using value_type = restriction_type; + + template + RestrictionIndex(std::vector &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, restriction_type *> restriction_hash; +}; + +template +template +RestrictionIndex::RestrictionIndex(std::vector &restrictions, + extractor_type extractor) +{ + // build a multi-map + for (auto &restriction : restrictions) + restriction_hash.insert(std::make_pair(extractor(restriction), &restriction)); +} + +template +bool RestrictionIndex::IsIndexed(const NodeID first, const NodeID second) const +{ + return restriction_hash.count(std::make_pair(first, second)); +} + +struct IndexNodeByFromAndVia +{ + std::pair 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 +std::pair +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; +using ConditionalRestrictionMap = RestrictionIndex; + +} // namespace extractor +} // namespace osrm + +#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_ diff --git a/include/extractor/restriction_map.hpp b/include/extractor/restriction_map.hpp deleted file mode 100644 index 09396d6d9..000000000 --- a/include/extractor/restriction_map.hpp +++ /dev/null @@ -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 - -#include -#include -#include -#include - -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 -{ - size_t operator()(const osrm::extractor::RestrictionSource &r_source) const - { - return hash_val(r_source.start_node, r_source.via_node); - } -}; - -template <> struct hash -{ - 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 &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 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; - - std::size_t m_count; - //! index -> list of (target, isOnly) - std::vector m_restriction_bucket_list; - //! maps (start, via) -> bucket index - std::unordered_map m_restriction_map; - std::unordered_set m_restriction_start_nodes; - std::unordered_set m_no_turn_via_node_set; -}; -} -} - -#endif // RESTRICTION_MAP_HPP diff --git a/include/extractor/serialization.hpp b/include/extractor/serialization.hpp index 7a8274231..8a361e194 100644 --- a/include/extractor/serialization.hpp +++ b/include/extractor/serialization.hpp @@ -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(turn_penalty.location.lat)); + writer.WriteOne(static_cast(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 &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 &conditional_penalties) +{ + auto const num_elements = reader.ReadElementCount64(); + conditional_penalties.resize(num_elements); + for (auto &penalty : conditional_penalties) + read(reader, penalty); +} } } } diff --git a/include/extractor/way_restriction_map.hpp b/include/extractor/way_restriction_map.hpp index 4daf99284..636c12747 100644 --- a/include/extractor/way_restriction_map.hpp +++ b/include/extractor/way_restriction_map.hpp @@ -8,6 +8,7 @@ #include #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 &turn_restrictions); + WayRestrictionMap(const std::vector &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 DuplicatedNodeRepresentatives() const; // Access all duplicated NodeIDs for a set of nodes indicating a via way - util::range DuplicatedNodeIDs(const NodeID from, const NodeID to) const; + std::vector 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 duplicated_node_groups; - - boost::unordered_multimap, RestrictionID> restriction_starts; - boost::unordered_multimap, RestrictionID> restriction_ends; - - std::vector restriction_data; + std::vector restriction_data; + RestrictionIndex restriction_starts; }; } // namespace extractor diff --git a/include/storage/serialization.hpp b/include/storage/serialization.hpp index 021bb8550..b52c9115e 100644 --- a/include/storage/serialization.hpp +++ b/include/storage/serialization.hpp @@ -97,7 +97,7 @@ template void write(io::FileWriter &writer, const std::vector &d { const auto count = data.size(); writer.WriteElementCount64(count); - return writer.WriteFrom(data.data(), count); + writer.WriteFrom(data.data(), count); } template void read(io::FileReader &reader, util::vector_view &data) diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index b149434a1..3131e6519 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -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 +#include #include +#include "boost/unordered_map.hpp" #include #include #include @@ -35,12 +39,26 @@ #include #include +namespace std +{ +template <> struct hash> +{ + std::size_t operator()(const std::pair &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 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 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 delayed_data; + std::vector 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 = 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(-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(-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 +EdgeBasedGraphFactory::IndexConditionals(std::vector &&conditionals) const +{ + boost::unordered_multimap, 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 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 EdgeBasedGraphFactory::GetBearingClasses() const { std::vector result(bearing_class_hash.data.size()); diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index f775d7795..93d33507b 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -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)); + } } }; diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 8f5bacb0c..a540fe46d 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -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 turn_restrictions; - std::tie(turn_lane_map, turn_restrictions) = + std::vector 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> +std::tuple, + std::vector> 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 &barriers, /** \brief Building an edge-expanded graph from node-based input and turn restrictions */ -std::pair -Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, - std::vector &coordinates, - extractor::PackedOSMIDs &osm_node_ids, - EdgeBasedNodeDataContainer &edge_based_nodes_container, - std::vector &edge_based_node_segments, - std::vector &node_is_startpoint, - std::vector &edge_based_node_weights, - util::DeallocatingVector &edge_based_edge_list, - const std::string &intersection_class_output_file, - std::vector &turn_restrictions, - guidance::LaneDescriptionMap &turn_lane_map) +std::pair Extractor::BuildEdgeExpandedGraph( + ScriptingEnvironment &scripting_environment, + std::vector &coordinates, + extractor::PackedOSMIDs &osm_node_ids, + EdgeBasedNodeDataContainer &edge_based_nodes_container, + std::vector &edge_based_node_segments, + std::vector &node_is_startpoint, + std::vector &edge_based_node_weights, + util::DeallocatingVector &edge_based_edge_list, + const std::string &intersection_class_output_file, + std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions, + guidance::LaneDescriptionMap &turn_lane_map) { std::unordered_set barrier_nodes; std::unordered_set 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 node_restrictions; + for (auto const &t : turn_restrictions) + if (t.Type() == RestrictionType::NODE_RESTRICTION) + node_restrictions.push_back(t); + + std::vector 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. diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index a3599b8d6..883bbd633 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -20,17 +20,19 @@ namespace osrm namespace extractor { -void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, - const std::unordered_set &traffic_signals, - ScriptingEnvironment &scripting_environment, - std::vector &turn_restrictions, - util::NodeBasedDynamicGraph &graph, - CompressedEdgeContainer &geometry_compressor) +void GraphCompressor::Compress( + const std::unordered_set &barrier_nodes, + const std::unordered_set &traffic_signals, + ScriptingEnvironment &scripting_environment, + std::vector &turn_restrictions, + std::vector &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 &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 = diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index 51fde3ec3..c2e94dfee 100644 --- a/src/extractor/guidance/intersection_generator.cpp +++ b/src/extractor/guidance/intersection_generator.cpp @@ -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 { + 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 -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; diff --git a/src/extractor/restriction_compressor.cpp b/src/extractor/restriction_compressor.cpp index 6da820f41..b20ef9c55 100644 --- a/src/extractor/restriction_compressor.cpp +++ b/src/extractor/restriction_compressor.cpp @@ -10,7 +10,9 @@ namespace osrm namespace extractor { -RestrictionCompressor::RestrictionCompressor(std::vector &restrictions) +RestrictionCompressor::RestrictionCompressor( + std::vector &restrictions, + std::vector &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 &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) diff --git a/src/extractor/restriction_filter.cpp b/src/extractor/restriction_filter.cpp index af23d7d10..ff14ece13 100644 --- a/src/extractor/restriction_filter.cpp +++ b/src/extractor/restriction_filter.cpp @@ -10,8 +10,8 @@ namespace osrm namespace extractor { -std::vector -removeInvalidRestrictions(std::vector restrictions, +std::vector +removeInvalidRestrictions(std::vector restrictions, const util::NodeBasedDynamicGraph &node_based_graph) { // definition of what we presume to be a valid via-node restriction diff --git a/src/extractor/restriction_map.cpp b/src/extractor/restriction_map.cpp deleted file mode 100644 index 812ff504b..000000000 --- a/src/extractor/restriction_map.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "extractor/restriction_map.hpp" - -#include - -namespace osrm -{ -namespace extractor -{ - -RestrictionMap::RestrictionMap(const std::vector &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::max()); - BOOST_ASSERT(node_restriction.via < std::numeric_limits::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(node_restriction.from), - static_cast(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 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(); -} -} -} diff --git a/src/extractor/way_restriction_map.cpp b/src/extractor/way_restriction_map.cpp index 570f926db..e4cfb178b 100644 --- a/src/extractor/way_restriction_map.cpp +++ b/src/extractor/way_restriction_map.cpp @@ -1,6 +1,7 @@ #include "extractor/way_restriction_map.hpp" #include "util/for_each_pair.hpp" +#include #include #include #include @@ -28,12 +29,46 @@ struct FindViaWay } }; -} // namespace - -WayRestrictionMap::WayRestrictionMap(const std::vector &turn_restrictions) +template 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 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 +std::vector +extractRestrictions(const std::vector &turn_restrictions) +{ + std::vector 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 &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()); + 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 struct ByInFromAndVia +{ + std::pair 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 &turn_restrictions_) + : restriction_data(extractRestrictions(turn_restrictions_)), + restriction_starts(restriction_data, ByInFromAndVia()) +{ std::size_t offset = 1; // the first group starts at 0 if (!restriction_data.empty()) @@ -74,8 +109,10 @@ WayRestrictionMap::WayRestrictionMap(const std::vector &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 WayRestrictionMap::DuplicatedNodeIDs(const NodeID from, +std::vector WayRestrictionMap::DuplicatedNodeIDs(const NodeID from, const NodeID to) const { const auto duplicated_node_range_itr = std::equal_range( @@ -125,9 +162,13 @@ util::range WayRestrictionMap::DuplicatedNodeIDs(const NodeID return std::distance(restriction_data.begin(), itr); }; - return util::irange( - 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 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::DuplicatedNodeRepresentatives() const { std::vector 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; } diff --git a/src/updater/updater.cpp b/src/updater/updater.cpp index 0377f94e8..27645d7f1 100644 --- a/src/updater/updater.cpp +++ b/src/updater/updater.cpp @@ -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 &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(toFloating(coordinates[via].lon)); - const auto lat = static_cast(toFloating(coordinates[via].lat)); - const auto &condition = turn.condition; + const auto lon = static_cast(toFloating(via.lon)); + const auto lat = static_cast(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 -updateConditionalTurns(const UpdaterConfig &config, - std::vector &turn_weight_penalties, - const std::vector &conditional_turns, - std::vector &coordinates, +updateConditionalTurns(std::vector &turn_weight_penalties, + const std::vector &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( - config.GetPath(".osrm.turn_penalties_index"), turn_index_region); - std::vector updated_turns; if (conditional_turns.size() == 0) return updated_turns; - // TODO make this into a function - LookupTable, NodeID> is_only_lookup; - std::unordered_set, - std::hash>> - 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 &e load_profile_properties); } - std::vector conditional_turns; + std::vector conditional_turns; if (update_conditional_turns) { using storage::io::FileReader; @@ -696,8 +635,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector &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. diff --git a/unit_tests/extractor/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp index 95236feed..e16147008 100644 --- a/unit_tests/extractor/graph_compressor.cpp +++ b/unit_tests/extractor/graph_compressor.cpp @@ -56,6 +56,7 @@ BOOST_AUTO_TEST_CASE(long_road_test) std::unordered_set barrier_nodes; std::unordered_set traffic_lights; std::vector restrictions; + std::vector 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 barrier_nodes; std::unordered_set traffic_lights; std::vector restrictions; + std::vector 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 barrier_nodes; std::unordered_set traffic_lights; std::vector restrictions; + std::vector 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 barrier_nodes; std::unordered_set traffic_lights; std::vector restrictions; + std::vector 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 barrier_nodes; std::unordered_set traffic_lights; std::vector restrictions; + std::vector 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);