refactor restriction parsing / extraction to actual types
Makes turn restrictions into dedicated structures and diferentiates between them via a variant. Ensures that we do not accidentally mess up ID types within our application. In addition this improves the restriction performance by only parsing all edges once at the cost of (at the time of writing) 22MB in terms of main memory usage.
This commit is contained in:
parent
1f7aa6f812
commit
2e9a7d9c1a
@ -2,7 +2,6 @@
|
||||
#define EXTRACTION_CONTAINERS_HPP
|
||||
|
||||
#include "extractor/first_and_last_segment_of_way.hpp"
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
#include "extractor/internal_extractor_edge.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
@ -28,7 +27,7 @@ class ExtractionContainers
|
||||
void PrepareEdges(ScriptingEnvironment &scripting_environment);
|
||||
|
||||
void WriteNodes(storage::io::FileWriter &file_out) const;
|
||||
void WriteRestrictions(const std::string &restrictions_file_name);
|
||||
void WriteConditionalRestrictions(const std::string &restrictions_file_name);
|
||||
void WriteEdges(storage::io::FileWriter &file_out) const;
|
||||
void WriteCharData(const std::string &file_name);
|
||||
|
||||
@ -36,7 +35,6 @@ class ExtractionContainers
|
||||
using NodeIDVector = std::vector<OSMNodeID>;
|
||||
using NodeVector = std::vector<QueryNode>;
|
||||
using EdgeVector = std::vector<InternalExtractorEdge>;
|
||||
using RestrictionsVector = std::vector<InputRestrictionContainer>;
|
||||
using WayIDStartEndVector = std::vector<FirstAndLastSegmentOfWay>;
|
||||
using NameCharData = std::vector<unsigned char>;
|
||||
using NameOffsets = std::vector<unsigned>;
|
||||
@ -49,9 +47,15 @@ class ExtractionContainers
|
||||
NameCharData name_char_data;
|
||||
NameOffsets name_offsets;
|
||||
// an adjacency array containing all turn lane masks
|
||||
RestrictionsVector restrictions_list;
|
||||
WayIDStartEndVector way_start_end_id_list;
|
||||
|
||||
unsigned max_internal_node_id;
|
||||
|
||||
// list of restrictions before we transform them into the output types
|
||||
std::vector<InputConditionalTurnRestriction> restrictions_list;
|
||||
|
||||
// turn restrictions split into conditional and unconditional turn restrictions
|
||||
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
|
||||
std::vector<TurnRestriction> unconditional_turn_restrictions;
|
||||
|
||||
ExtractionContainers();
|
||||
|
@ -42,10 +42,10 @@ namespace extractor
|
||||
{
|
||||
|
||||
class ExtractionContainers;
|
||||
struct InputRestrictionContainer;
|
||||
struct ExtractionNode;
|
||||
struct ExtractionWay;
|
||||
struct ProfileProperties;
|
||||
struct InputConditionalTurnRestriction;
|
||||
|
||||
/**
|
||||
* This class is used by the extractor with the results of the
|
||||
@ -83,7 +83,7 @@ class ExtractorCallbacks
|
||||
void ProcessNode(const osmium::Node ¤t_node, const ExtractionNode &result_node);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessRestriction(const boost::optional<InputRestrictionContainer> &restriction);
|
||||
void ProcessRestriction(const InputConditionalTurnRestriction &restriction);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@ -14,7 +15,7 @@ namespace extractor
|
||||
{
|
||||
|
||||
class CompressedEdgeContainer;
|
||||
class RestrictionMap;
|
||||
struct TurnRestriction;
|
||||
|
||||
class GraphCompressor
|
||||
{
|
||||
@ -23,7 +24,7 @@ class GraphCompressor
|
||||
public:
|
||||
void Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
RestrictionMap &restriction_map,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "util/opening_hours.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
@ -12,104 +13,254 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// OSM offers two types of restrictions, via node and via-way restrictions. We parse both into the
|
||||
// same input container
|
||||
//
|
||||
// A restriction turning at a single node. This is the most common type of restriction:
|
||||
//
|
||||
// a - b - c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// ab via b to bd
|
||||
struct InputNodeRestriction
|
||||
{
|
||||
OSMEdgeID_weak from;
|
||||
OSMNodeID_weak via;
|
||||
OSMEdgeID_weak to;
|
||||
};
|
||||
|
||||
// A restriction that uses a single via-way in between
|
||||
//
|
||||
// f - e - d
|
||||
// |
|
||||
// a - b - c
|
||||
//
|
||||
// ab via be to ef -- no u turn
|
||||
struct InputWayRestriction
|
||||
{
|
||||
OSMEdgeID_weak from;
|
||||
OSMEdgeID_weak via;
|
||||
OSMEdgeID_weak to;
|
||||
};
|
||||
|
||||
// Outside view of the variant, these are equal to the `which()` results
|
||||
enum RestrictionType
|
||||
{
|
||||
NODE_RESTRICTION = 0,
|
||||
WAY_RESTRICTION = 1,
|
||||
NUM_RESTRICTION_TYPES = 2
|
||||
};
|
||||
|
||||
namespace restriction_details
|
||||
{
|
||||
|
||||
// currently these bits only hold an `is_only` value.
|
||||
struct Bits
|
||||
{ // mostly unused, initialised to false by default
|
||||
Bits() : is_only(false) {}
|
||||
|
||||
bool is_only;
|
||||
// when adding more bits, consider using bitfields just as in
|
||||
// bool unused : 7;
|
||||
};
|
||||
|
||||
} // namespace restriction
|
||||
|
||||
struct InputTurnRestriction
|
||||
{
|
||||
// keep in the same order as the turn restrictions below
|
||||
boost::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
|
||||
restriction_details::Bits flags;
|
||||
|
||||
OSMEdgeID_weak From() const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? boost::get<InputNodeRestriction>(node_or_way).from
|
||||
: boost::get<InputWayRestriction>(node_or_way).from;
|
||||
}
|
||||
|
||||
OSMEdgeID_weak To() const
|
||||
{
|
||||
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||
? boost::get<InputNodeRestriction>(node_or_way).to
|
||||
: boost::get<InputWayRestriction>(node_or_way).to;
|
||||
}
|
||||
|
||||
RestrictionType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
|
||||
return static_cast<RestrictionType>(node_or_way.which());
|
||||
}
|
||||
|
||||
InputWayRestriction &AsWayRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return boost::get<InputWayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const InputWayRestriction &AsWayRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return boost::get<InputWayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
InputNodeRestriction &AsNodeRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return boost::get<InputNodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const InputNodeRestriction &AsNodeRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return boost::get<InputNodeRestriction>(node_or_way);
|
||||
}
|
||||
};
|
||||
struct InputConditionalTurnRestriction : InputTurnRestriction
|
||||
{
|
||||
std::vector<util::OpeningHours> condition;
|
||||
};
|
||||
|
||||
// OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note
|
||||
// that this has the side-effect of not allowing parallel edges!
|
||||
struct NodeRestriction
|
||||
{
|
||||
NodeID from;
|
||||
NodeID via;
|
||||
NodeID to;
|
||||
|
||||
// check if all parts of the restriction reference an actual node
|
||||
bool Valid() const
|
||||
{
|
||||
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID;
|
||||
};
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return "From " + std::to_string(from) + " via " + std::to_string(via) + " to " +
|
||||
std::to_string(to);
|
||||
}
|
||||
};
|
||||
|
||||
// A way restriction in the context of OSRM requires translation into NodeIDs. This is due to the
|
||||
// compression happening in the graph creation process which would make it difficult to track
|
||||
// way-ids over a series of operations. Having access to the nodes directly allows look-up of the
|
||||
// edges in the processed structures
|
||||
struct WayRestriction
|
||||
{
|
||||
// a way restriction in OSRM is essentially a dual node turn restriction;
|
||||
//
|
||||
// | |
|
||||
// c -x- b
|
||||
// | |
|
||||
// d a
|
||||
//
|
||||
// from ab via bxc to cd: no_uturn
|
||||
//
|
||||
// Technically, we would need only a,b,c,d to describe the full turn in terms of nodes. When
|
||||
// parsing the relation, though, we do not know about the final representation in the node-based
|
||||
// graph for the restriction. In case of a traffic light, for example, we might end up with bxc
|
||||
// not being compressed to bc. For that reason, we need to maintain two node restrictions in
|
||||
// case a way restrction is not fully collapsed
|
||||
NodeRestriction in_restriction;
|
||||
NodeRestriction out_restriction;
|
||||
};
|
||||
|
||||
// Wrapper for turn restrictions that gives more information on its type / handles the switch
|
||||
// between node/way/multi-way restrictions
|
||||
struct TurnRestriction
|
||||
{
|
||||
union WayOrNode {
|
||||
OSMNodeID_weak node;
|
||||
OSMEdgeID_weak way;
|
||||
};
|
||||
WayOrNode via;
|
||||
WayOrNode from;
|
||||
WayOrNode to;
|
||||
// keep in the same order as the turn restrictions above
|
||||
boost::variant<NodeRestriction, WayRestriction> node_or_way;
|
||||
restriction_details::Bits flags;
|
||||
|
||||
std::vector<util::OpeningHours> condition;
|
||||
|
||||
struct Bits
|
||||
{ // mostly unused
|
||||
Bits()
|
||||
: is_only(false), uses_via_way(false), unused2(false), unused3(false), unused4(false),
|
||||
unused5(false), unused6(false), unused7(false)
|
||||
// construction for NodeRestrictions
|
||||
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
|
||||
: node_or_way(node_restriction)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_only : 1;
|
||||
bool uses_via_way : 1;
|
||||
bool unused2 : 1;
|
||||
bool unused3 : 1;
|
||||
bool unused4 : 1;
|
||||
bool unused5 : 1;
|
||||
bool unused6 : 1;
|
||||
bool unused7 : 1;
|
||||
} flags;
|
||||
|
||||
explicit TurnRestriction(NodeID node)
|
||||
{
|
||||
via.node = node;
|
||||
from.node = SPECIAL_NODEID;
|
||||
to.node = SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
explicit TurnRestriction(const bool is_only = false)
|
||||
{
|
||||
via.node = SPECIAL_NODEID;
|
||||
from.node = SPECIAL_NODEID;
|
||||
to.node = SPECIAL_NODEID;
|
||||
flags.is_only = is_only;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is just a wrapper around TurnRestriction used in the extractor.
|
||||
*
|
||||
* Could be merged with TurnRestriction. For now the type-destiction makes sense
|
||||
* as the format in which the restriction is presented in the extractor and in the
|
||||
* preprocessing is different. (see restriction_parser.cpp)
|
||||
*/
|
||||
struct InputRestrictionContainer
|
||||
// construction for WayRestrictions
|
||||
explicit TurnRestriction(WayRestriction way_restriction, bool is_only = false)
|
||||
: node_or_way(way_restriction)
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
|
||||
InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, EdgeID vw)
|
||||
{
|
||||
restriction.from.way = fromWay;
|
||||
restriction.to.way = toWay;
|
||||
restriction.via.way = vw;
|
||||
}
|
||||
explicit InputRestrictionContainer(bool is_only = false)
|
||||
{
|
||||
restriction.from.way = SPECIAL_EDGEID;
|
||||
restriction.to.way = SPECIAL_EDGEID;
|
||||
restriction.via.node = SPECIAL_NODEID;
|
||||
restriction.flags.is_only = is_only;
|
||||
flags.is_only = is_only;
|
||||
}
|
||||
|
||||
static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0); }
|
||||
static InputRestrictionContainer max_value()
|
||||
explicit TurnRestriction()
|
||||
{
|
||||
return InputRestrictionContainer(SPECIAL_EDGEID, SPECIAL_EDGEID, SPECIAL_EDGEID);
|
||||
node_or_way = NodeRestriction{SPECIAL_EDGEID, SPECIAL_NODEID, SPECIAL_EDGEID};
|
||||
}
|
||||
|
||||
WayRestriction &AsWayRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return boost::get<WayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const WayRestriction &AsWayRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
|
||||
return boost::get<WayRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
NodeRestriction &AsNodeRestriction()
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return boost::get<NodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
const NodeRestriction &AsNodeRestriction() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
|
||||
return boost::get<NodeRestriction>(node_or_way);
|
||||
}
|
||||
|
||||
RestrictionType Type() const
|
||||
{
|
||||
BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
|
||||
return static_cast<RestrictionType>(node_or_way.which());
|
||||
}
|
||||
|
||||
// check if all elements of the edge are considered valid
|
||||
bool Valid() const
|
||||
{
|
||||
if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
auto const &restriction = AsWayRestriction();
|
||||
return restriction.in_restriction.Valid() && restriction.out_restriction.Valid();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const &restriction = AsNodeRestriction();
|
||||
return restriction.Valid();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::string representation;
|
||||
if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
auto const &way = AsWayRestriction();
|
||||
representation =
|
||||
"In: " + way.in_restriction.ToString() + " Out: " + way.out_restriction.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const &node = AsNodeRestriction();
|
||||
representation = node.ToString();
|
||||
}
|
||||
representation += " is_only: " + std::to_string(flags.is_only);
|
||||
return representation;
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByFrom
|
||||
struct ConditionalTurnRestriction : TurnRestriction
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
|
||||
{
|
||||
return a.restriction.from.way < b.restriction.from.way;
|
||||
}
|
||||
value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
|
||||
{
|
||||
return a.restriction.to.way < b.restriction.to.way;
|
||||
}
|
||||
value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
std::vector<util::OpeningHours> condition;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
46
include/extractor/restriction_compressor.hpp
Normal file
46
include/extractor/restriction_compressor.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct NodeRestriction;
|
||||
struct TurnRestriction;
|
||||
|
||||
// OSRM stores restrictions in the form node -> node -> node instead of way -> node -> way (or
|
||||
// way->way->way) as it is done in OSM. These restrictions need to match the state of graph
|
||||
// compression which we perform in the graph compressor that removes certain degree two nodes from
|
||||
// the graph (all but the ones with penalties/barriers, as of the state of writing).
|
||||
// Since this graph compression ins performed after creating the restrictions in the extraction
|
||||
// phase, we need to update the involved nodes whenever one of the nodes is compressed.
|
||||
//
|
||||
//
|
||||
// !!!! Will bind to the restrictions vector and modify it in-place !!!!
|
||||
class RestrictionCompressor
|
||||
{
|
||||
public:
|
||||
RestrictionCompressor(std::vector<TurnRestriction> &restrictions);
|
||||
|
||||
// account for the compression of `from-via-to` into `from-to`
|
||||
void Compress(const NodeID from, const NodeID via, const NodeID to);
|
||||
|
||||
private:
|
||||
// a turn restriction is given as `from head via node to tail`. Edges ending at `head` being
|
||||
// contracted move the head pointer to their respective head. Edges starting at tail move the
|
||||
// tail values to their respective tails. Way turn restrictions are represented by two
|
||||
// node-restrictions, so we can focus on them alone
|
||||
boost::unordered_multimap<NodeID, NodeRestriction *> heads;
|
||||
boost::unordered_multimap<NodeID, NodeRestriction *> tails;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
|
@ -69,6 +69,7 @@ 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
|
||||
|
@ -3,8 +3,7 @@
|
||||
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -38,13 +37,15 @@ class ScriptingEnvironment;
|
||||
* ...----(a)-----(via)------(b)----...
|
||||
* So it can be represented by the tripe (a, via, b).
|
||||
*/
|
||||
|
||||
class RestrictionParser
|
||||
{
|
||||
public:
|
||||
RestrictionParser(bool use_turn_restrictions,
|
||||
bool parse_conditionals,
|
||||
std::vector<std::string> &restrictions);
|
||||
std::vector<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
|
||||
boost::optional<InputConditionalTurnRestriction>
|
||||
TryParse(const osmium::Relation &relation) const;
|
||||
|
||||
private:
|
||||
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
|
||||
|
@ -57,12 +57,12 @@ class ScriptingEnvironment
|
||||
virtual void ProcessTurn(ExtractionTurn &turn) = 0;
|
||||
virtual void ProcessSegment(ExtractionSegment &segment) = 0;
|
||||
|
||||
virtual void ProcessElements(
|
||||
const osmium::memory::Buffer &buffer,
|
||||
virtual void
|
||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<boost::optional<InputRestrictionContainer>> &resulting_restrictions) = 0;
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -67,12 +67,12 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
||||
void ProcessTurn(ExtractionTurn &turn) override;
|
||||
void ProcessSegment(ExtractionSegment &segment) override;
|
||||
|
||||
void ProcessElements(
|
||||
const osmium::memory::Buffer &buffer,
|
||||
void
|
||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
||||
const RestrictionParser &restriction_parser,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<boost::optional<InputRestrictionContainer>> &resulting_restrictions) override;
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
||||
|
||||
private:
|
||||
void InitContext(LuaScriptingContext &context);
|
||||
|
@ -137,41 +137,67 @@ inline void write(storage::io::FileWriter &writer,
|
||||
storage::serialization::write(writer, node_data_container.classes);
|
||||
}
|
||||
|
||||
// read/write for conditional turn restrictions file
|
||||
inline void read(storage::io::FileReader &reader, std::vector<TurnRestriction> &restrictions)
|
||||
inline void read(storage::io::FileReader &reader, NodeRestriction &restriction)
|
||||
{
|
||||
auto num_indices = reader.ReadElementCount64();
|
||||
restrictions.reserve(num_indices);
|
||||
TurnRestriction restriction;
|
||||
while (num_indices > 0)
|
||||
{
|
||||
bool is_only;
|
||||
reader.ReadInto(restriction.via);
|
||||
reader.ReadInto(restriction.from);
|
||||
reader.ReadInto(restriction.via);
|
||||
reader.ReadInto(restriction.to);
|
||||
reader.ReadInto(is_only);
|
||||
auto num_conditions = reader.ReadElementCount64();
|
||||
restriction.condition.resize(num_conditions);
|
||||
for (uint64_t i = 0; i < num_conditions; i++)
|
||||
{
|
||||
reader.ReadInto(restriction.condition[i].modifier);
|
||||
storage::serialization::read(reader, restriction.condition[i].times);
|
||||
storage::serialization::read(reader, restriction.condition[i].weekdays);
|
||||
storage::serialization::read(reader, restriction.condition[i].monthdays);
|
||||
}
|
||||
restriction.flags.is_only = is_only;
|
||||
|
||||
restrictions.push_back(std::move(restriction));
|
||||
num_indices--;
|
||||
inline void write(storage::io::FileWriter &writer, const NodeRestriction &restriction)
|
||||
{
|
||||
writer.WriteOne(restriction.from);
|
||||
writer.WriteOne(restriction.via);
|
||||
writer.WriteOne(restriction.to);
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader, WayRestriction &restriction)
|
||||
{
|
||||
read(reader, restriction.in_restriction);
|
||||
read(reader, restriction.out_restriction);
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer, const WayRestriction &restriction)
|
||||
{
|
||||
write(writer, restriction.in_restriction);
|
||||
write(writer, restriction.out_restriction);
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
||||
{
|
||||
reader.ReadInto(restriction.flags);
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
WayRestriction way_restriction;
|
||||
read(reader, way_restriction);
|
||||
restriction.node_or_way = std::move(way_restriction);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
NodeRestriction node_restriction;
|
||||
read(reader, node_restriction);
|
||||
restriction.node_or_way = std::move(node_restriction);
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer, const TurnRestriction &restriction)
|
||||
{
|
||||
writer.WriteOne(restriction.via);
|
||||
writer.WriteOne(restriction.from);
|
||||
writer.WriteOne(restriction.to);
|
||||
writer.WriteOne(restriction.flags.is_only);
|
||||
writer.WriteOne(restriction.flags);
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
write(writer, boost::get<WayRestriction>(restriction.node_or_way));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
write(writer, boost::get<NodeRestriction>(restriction.node_or_way));
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer, const ConditionalTurnRestriction &restriction)
|
||||
{
|
||||
write(writer, static_cast<TurnRestriction>(restriction));
|
||||
writer.WriteElementCount64(restriction.condition.size());
|
||||
for (const auto &c : restriction.condition)
|
||||
{
|
||||
@ -181,6 +207,72 @@ inline void write(storage::io::FileWriter &writer, const TurnRestriction &restri
|
||||
storage::serialization::write(writer, c.monthdays);
|
||||
}
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader, ConditionalTurnRestriction &restriction)
|
||||
{
|
||||
TurnRestriction base;
|
||||
read(reader, base);
|
||||
reinterpret_cast<TurnRestriction &>(restriction) = std::move(base);
|
||||
auto num_conditions = reader.ReadElementCount64();
|
||||
restriction.condition.resize(num_conditions);
|
||||
for (uint64_t i = 0; i < num_conditions; i++)
|
||||
{
|
||||
reader.ReadInto(restriction.condition[i].modifier);
|
||||
storage::serialization::read(reader, restriction.condition[i].times);
|
||||
storage::serialization::read(reader, restriction.condition[i].weekdays);
|
||||
storage::serialization::read(reader, restriction.condition[i].monthdays);
|
||||
}
|
||||
}
|
||||
|
||||
// read/write for conditional turn restrictions file
|
||||
inline void read(storage::io::FileReader &reader, std::vector<TurnRestriction> &restrictions)
|
||||
{
|
||||
auto num_indices = reader.ReadElementCount64();
|
||||
restrictions.reserve(num_indices);
|
||||
TurnRestriction restriction;
|
||||
while (num_indices > 0)
|
||||
{
|
||||
read(reader, restriction);
|
||||
restrictions.push_back(std::move(restriction));
|
||||
num_indices--;
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer, const std::vector<TurnRestriction> &restrictions)
|
||||
{
|
||||
std::uint64_t num_indices = restrictions.size();
|
||||
writer.WriteElementCount64(num_indices);
|
||||
auto const write_restriction = [&writer](const auto &restriction) {
|
||||
write(writer, restriction);
|
||||
};
|
||||
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
|
||||
}
|
||||
|
||||
// read/write for conditional turn restrictions file
|
||||
inline void read(storage::io::FileReader &reader,
|
||||
std::vector<ConditionalTurnRestriction> &restrictions)
|
||||
{
|
||||
auto num_indices = reader.ReadElementCount64();
|
||||
restrictions.reserve(num_indices);
|
||||
ConditionalTurnRestriction restriction;
|
||||
while (num_indices > 0)
|
||||
{
|
||||
read(reader, restriction);
|
||||
restrictions.push_back(std::move(restriction));
|
||||
num_indices--;
|
||||
}
|
||||
}
|
||||
|
||||
inline void write(storage::io::FileWriter &writer,
|
||||
const std::vector<ConditionalTurnRestriction> &restrictions)
|
||||
{
|
||||
std::uint64_t num_indices = restrictions.size();
|
||||
writer.WriteElementCount64(num_indices);
|
||||
auto const write_restriction = [&writer](const auto &restriction) {
|
||||
write(writer, restriction);
|
||||
};
|
||||
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,12 +52,12 @@ using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
|
||||
static_assert(std::is_pod<OSMWayID>(), "OSMWayID is not a valid alias");
|
||||
|
||||
static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::max()};
|
||||
static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint32_t>::max()};
|
||||
static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::max()};
|
||||
|
||||
static const OSMNodeID MAX_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::max()};
|
||||
static const OSMNodeID MIN_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::min()};
|
||||
static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint32_t>::max()};
|
||||
static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint32_t>::min()};
|
||||
static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::max()};
|
||||
static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::min()};
|
||||
|
||||
using OSMNodeID_weak = std::uint64_t;
|
||||
using OSMEdgeID_weak = std::uint64_t;
|
||||
|
@ -139,7 +139,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
WriteEdges(file_out);
|
||||
|
||||
PrepareRestrictions();
|
||||
WriteRestrictions(restrictions_file_name);
|
||||
WriteConditionalRestrictions(restrictions_file_name);
|
||||
WriteCharData(name_file_name);
|
||||
}
|
||||
|
||||
@ -633,46 +633,19 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
|
||||
util::Log() << "Processed " << max_internal_node_id << " nodes";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteRestrictions(const std::string &path)
|
||||
void ExtractionContainers::WriteConditionalRestrictions(const std::string &path)
|
||||
{
|
||||
// serialize restrictions
|
||||
std::uint64_t written_restriction_count = 0;
|
||||
std::uint64_t written_restriction_count = conditional_turn_restrictions.size();
|
||||
storage::io::FileWriter restrictions_out_file(path,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
|
||||
restrictions_out_file.WriteElementCount64(written_restriction_count);
|
||||
|
||||
for (const auto &restriction_container : restrictions_list)
|
||||
{
|
||||
if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
|
||||
SPECIAL_NODEID != restriction_container.restriction.via.node &&
|
||||
SPECIAL_NODEID != restriction_container.restriction.to.node)
|
||||
{
|
||||
if (!restriction_container.restriction.condition.empty())
|
||||
{
|
||||
// write conditional turn restrictions to disk, for use in contractor later
|
||||
extractor::serialization::write(restrictions_out_file,
|
||||
restriction_container.restriction);
|
||||
++written_restriction_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// save unconditional turn restriction to memory, for use in ebg later
|
||||
unconditional_turn_restrictions.push_back(
|
||||
std::move(restriction_container.restriction));
|
||||
}
|
||||
}
|
||||
}
|
||||
restrictions_out_file.SkipToBeginning();
|
||||
restrictions_out_file.WriteElementCount64(written_restriction_count);
|
||||
util::Log() << "number of restrictions saved to memory: "
|
||||
<< unconditional_turn_restrictions.size();
|
||||
serialization::write(restrictions_out_file, conditional_turn_restrictions);
|
||||
util::Log() << "number of conditional restrictions written to disk: "
|
||||
<< written_restriction_count;
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareRestrictions()
|
||||
{
|
||||
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting used ways ... ";
|
||||
@ -684,211 +657,211 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
log << "ok, after " << TIMER_SEC(sort_ways) << "s";
|
||||
}
|
||||
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting " << restrictions_list.size() << " restriction. by from... ";
|
||||
TIMER_START(sort_restrictions);
|
||||
tbb::parallel_sort(
|
||||
restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByFrom());
|
||||
TIMER_STOP(sort_restrictions);
|
||||
log << "ok, after " << TIMER_SEC(sort_restrictions) << "s";
|
||||
}
|
||||
// contain the start/end nodes of each way that is part of an restriction
|
||||
std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways;
|
||||
|
||||
// enter invalid IDs into the above maps to indicate that we want to find out about start/end
|
||||
// nodes of these ways
|
||||
const auto mark_ids = [&](auto const &turn_restriction) {
|
||||
FirstAndLastSegmentOfWay dummy_segment{
|
||||
MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
|
||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Fixing restriction starts ... " << std::flush;
|
||||
TIMER_START(fix_restriction_starts);
|
||||
auto restrictions_iterator = restrictions_list.begin();
|
||||
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
||||
const auto restrictions_list_end = restrictions_list.end();
|
||||
const auto way_start_end_id_list_end = way_start_end_id_list.cend();
|
||||
|
||||
while (way_start_and_end_iterator != way_start_end_id_list_end &&
|
||||
restrictions_iterator != restrictions_list_end)
|
||||
{
|
||||
if (way_start_and_end_iterator->way_id <
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.from.way)})
|
||||
{
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (way_start_and_end_iterator->way_id >
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.from.way)})
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: "
|
||||
<< restrictions_iterator->restriction.from.way;
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(
|
||||
way_start_and_end_iterator->way_id ==
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.from.way)});
|
||||
|
||||
// we do not remap the via id yet, since we will need it for the to node as well
|
||||
const OSMNodeID via_osm_node_id =
|
||||
OSMNodeID{restrictions_iterator->restriction.via.node};
|
||||
|
||||
// check if via is actually valid, if not invalidate
|
||||
auto via_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), via_osm_node_id);
|
||||
if (via_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid node: " << via_osm_node_id;
|
||||
restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (way_start_and_end_iterator->first_segment_source_id == via_osm_node_id)
|
||||
{
|
||||
// assign new from node id
|
||||
const auto from_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
way_start_and_end_iterator->first_segment_target_id);
|
||||
if (from_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Way references invalid node: "
|
||||
<< way_start_and_end_iterator->first_segment_target_id;
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
restrictions_iterator->restriction.from.node = from_node_id;
|
||||
}
|
||||
else if (way_start_and_end_iterator->last_segment_target_id == via_osm_node_id)
|
||||
{
|
||||
// assign new from node id
|
||||
const auto from_node_id =
|
||||
mapExternalToInternalNodeID(used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
way_start_and_end_iterator->last_segment_source_id);
|
||||
if (from_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Way references invalid node: "
|
||||
<< way_start_and_end_iterator->last_segment_target_id;
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
restrictions_iterator->restriction.from.node = from_node_id;
|
||||
const auto &way = turn_restriction.AsWayRestriction();
|
||||
referenced_ways[OSMWayID{way.from}] = dummy_segment;
|
||||
referenced_ways[OSMWayID{way.to}] = dummy_segment;
|
||||
referenced_ways[OSMWayID{way.via}] = dummy_segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it's neither, this is an invalid restriction
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
const auto &node = turn_restriction.AsNodeRestriction();
|
||||
referenced_ways[OSMWayID{node.from}] = dummy_segment;
|
||||
referenced_ways[OSMWayID{node.to}] = dummy_segment;
|
||||
}
|
||||
};
|
||||
|
||||
TIMER_STOP(fix_restriction_starts);
|
||||
log << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s";
|
||||
}
|
||||
// update the values for all edges already sporting SPECIAL_NODEID
|
||||
const auto set_ids = [&](auto const &start_end) {
|
||||
auto itr = referenced_ways.find(start_end.way_id);
|
||||
if (itr != referenced_ways.end())
|
||||
itr->second = start_end;
|
||||
};
|
||||
|
||||
// prepare for extracting source/destination nodes for all restrictions
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting restrictions. by to ... " << std::flush;
|
||||
TIMER_START(sort_restrictions_to);
|
||||
tbb::parallel_sort(
|
||||
restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByTo());
|
||||
TIMER_STOP(sort_restrictions_to);
|
||||
log << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s";
|
||||
log << "Collecting start/end information on " << restrictions_list.size()
|
||||
<< " restrictions...";
|
||||
TIMER_START(prepare_restrictions);
|
||||
std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids);
|
||||
std::for_each(way_start_end_id_list.cbegin(), way_start_end_id_list.cend(), set_ids);
|
||||
TIMER_STOP(prepare_restrictions);
|
||||
log << "ok, after " << TIMER_SEC(prepare_restrictions) << "s";
|
||||
}
|
||||
|
||||
auto const to_internal = [&](auto const osm_node) {
|
||||
auto internal = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), OSMNodeID{osm_node});
|
||||
if (internal == SPECIAL_NODEID)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Fixing restriction ends ... " << std::flush;
|
||||
TIMER_START(fix_restriction_ends);
|
||||
auto restrictions_iterator = restrictions_list.begin();
|
||||
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
||||
const auto way_start_end_id_list_end_ = way_start_end_id_list.cend();
|
||||
const auto restrictions_list_end_ = restrictions_list.end();
|
||||
util::Log(logDEBUG) << "Restriction references invalid node: " << osm_node;
|
||||
}
|
||||
return internal;
|
||||
};
|
||||
|
||||
while (way_start_and_end_iterator != way_start_end_id_list_end_ &&
|
||||
restrictions_iterator != restrictions_list_end_)
|
||||
// Given:
|
||||
// a -- b - ????????? - c -- d
|
||||
// Given
|
||||
// a -- b - ????????? - c -- d as via segment
|
||||
// and either
|
||||
// d -- e - ????????? - f -- g or
|
||||
// h -- i - ????????? - j -- a
|
||||
// (d,e) or (j,a) as entry-segment
|
||||
auto const find_node_restriction =
|
||||
[&](auto const &segment, auto const &via_segment, auto const via_node) {
|
||||
// connected at the front of the segment
|
||||
if (via_node == MAX_OSM_NODEID || segment.first_segment_source_id == via_node)
|
||||
{
|
||||
if (way_start_and_end_iterator->way_id <
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.to.way)})
|
||||
if (segment.first_segment_source_id == via_segment.first_segment_source_id)
|
||||
{
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
return NodeRestriction{to_internal(segment.first_segment_target_id),
|
||||
to_internal(segment.first_segment_source_id),
|
||||
to_internal(via_segment.first_segment_target_id)};
|
||||
}
|
||||
if (restrictions_iterator->restriction.from.node == SPECIAL_NODEID ||
|
||||
restrictions_iterator->restriction.via.node == SPECIAL_NODEID)
|
||||
else if (segment.first_segment_source_id == via_segment.last_segment_target_id)
|
||||
{
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
return NodeRestriction{to_internal(segment.first_segment_target_id),
|
||||
to_internal(segment.first_segment_source_id),
|
||||
to_internal(via_segment.last_segment_source_id)};
|
||||
}
|
||||
if (way_start_and_end_iterator->way_id >
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.to.way)})
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: "
|
||||
<< restrictions_iterator->restriction.to.way;
|
||||
restrictions_iterator->restriction.to.way = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(
|
||||
way_start_and_end_iterator->way_id ==
|
||||
OSMWayID{static_cast<std::uint32_t>(restrictions_iterator->restriction.to.way)});
|
||||
const OSMNodeID via_osm_node_id =
|
||||
OSMNodeID{restrictions_iterator->restriction.via.node};
|
||||
|
||||
// assign new via node id
|
||||
const auto via_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), via_osm_node_id);
|
||||
BOOST_ASSERT(via_node_id != SPECIAL_NODEID);
|
||||
restrictions_iterator->restriction.via.node = via_node_id;
|
||||
// connected at the end of the segment
|
||||
if (via_node == MAX_OSM_NODEID || segment.last_segment_target_id == via_node)
|
||||
{
|
||||
if (segment.last_segment_target_id == via_segment.first_segment_source_id)
|
||||
{
|
||||
return NodeRestriction{to_internal(segment.last_segment_source_id),
|
||||
to_internal(segment.last_segment_target_id),
|
||||
to_internal(via_segment.first_segment_target_id)};
|
||||
}
|
||||
else if (segment.last_segment_target_id == via_segment.last_segment_target_id)
|
||||
{
|
||||
return NodeRestriction{to_internal(segment.last_segment_source_id),
|
||||
to_internal(segment.last_segment_target_id),
|
||||
to_internal(via_segment.last_segment_source_id)};
|
||||
}
|
||||
}
|
||||
|
||||
if (way_start_and_end_iterator->first_segment_source_id == via_osm_node_id)
|
||||
// unconnected
|
||||
util::Log(logDEBUG) << "Restriction references unconnected way: " << segment.way_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
};
|
||||
|
||||
// translate the turn from one segment onto another into a node restriction (the ways can only
|
||||
// be connected at a single location)
|
||||
auto const get_node_restriction_from_OSM_ids = [&](
|
||||
auto const from_id, auto const to_id, const OSMNodeID via_node = MAX_OSM_NODEID) {
|
||||
auto const from_segment_itr = referenced_ways.find(OSMWayID{from_id});
|
||||
if (from_segment_itr->second.way_id != OSMWayID{from_id})
|
||||
{
|
||||
const auto to_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
way_start_and_end_iterator->first_segment_target_id);
|
||||
if (to_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Way references invalid node: "
|
||||
<< way_start_and_end_iterator->first_segment_source_id;
|
||||
restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << from_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
restrictions_iterator->restriction.to.node = to_node_id;
|
||||
}
|
||||
else if (way_start_and_end_iterator->last_segment_target_id == via_osm_node_id)
|
||||
|
||||
auto const to_segment_itr = referenced_ways.find(OSMWayID{to_id});
|
||||
if (to_segment_itr->second.way_id != OSMWayID{to_id})
|
||||
{
|
||||
const auto to_node_id =
|
||||
mapExternalToInternalNodeID(used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
way_start_and_end_iterator->last_segment_source_id);
|
||||
if (to_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Way references invalid node: "
|
||||
<< way_start_and_end_iterator->last_segment_source_id;
|
||||
restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << to_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
restrictions_iterator->restriction.to.node = to_node_id;
|
||||
return find_node_restriction(from_segment_itr->second, to_segment_itr->second, via_node);
|
||||
};
|
||||
|
||||
// transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs)
|
||||
// returns true on successful transformation, false in case of invalid references
|
||||
const auto transform = [&](auto const &external_type, auto &internal_type) {
|
||||
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
auto const &external = external_type.AsWayRestriction();
|
||||
// check if we were able to resolve all the involved ways
|
||||
auto const from_restriction =
|
||||
get_node_restriction_from_OSM_ids(external.from, external.via);
|
||||
auto const to_restriction =
|
||||
get_node_restriction_from_OSM_ids(external.via, external.to);
|
||||
|
||||
// failed to translate either of the involved nodes?
|
||||
if (!from_restriction.Valid() || !to_restriction.Valid())
|
||||
return false;
|
||||
|
||||
// point located at both via and segment is alway on `second`, to FSSF is the order we
|
||||
// need
|
||||
WayRestriction way_restriction{from_restriction, to_restriction};
|
||||
internal_type.node_or_way = std::move(way_restriction);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it's neither, this is an invalid restriction
|
||||
restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
TIMER_STOP(fix_restriction_ends);
|
||||
log << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s";
|
||||
BOOST_ASSERT(external_type.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
auto const &external = external_type.AsNodeRestriction();
|
||||
auto const via_node = to_internal(external.via);
|
||||
|
||||
// check if we were able to resolve all the involved ways
|
||||
auto restriction = get_node_restriction_from_OSM_ids(
|
||||
external.from, external.to, OSMNodeID{external.via});
|
||||
|
||||
if (!restriction.Valid())
|
||||
{
|
||||
std::cout << " >>> Invalid" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (restriction.via != via_node)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << external.via;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal_type.node_or_way = std::move(restriction);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// wrapper function to handle distinction between conditional and unconditional turn
|
||||
// restrictions
|
||||
const auto transform_into_internal_types = [&](auto &external_restriction) {
|
||||
// unconditional restriction
|
||||
if (external_restriction.condition.empty())
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
restriction.flags = external_restriction.flags;
|
||||
if (transform(external_restriction, restriction))
|
||||
unconditional_turn_restrictions.push_back(restriction);
|
||||
}
|
||||
// conditional turn restriction
|
||||
else
|
||||
{
|
||||
ConditionalTurnRestriction restriction;
|
||||
restriction.flags = external_restriction.flags;
|
||||
restriction.condition = std::move(external_restriction.condition);
|
||||
if (transform(external_restriction, restriction))
|
||||
conditional_turn_restrictions.push_back(restriction);
|
||||
}
|
||||
};
|
||||
|
||||
// Transforming the restrictions into the dedicated internal types
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Collecting start/end information on " << restrictions_list.size()
|
||||
<< " restrictions...";
|
||||
TIMER_START(transform);
|
||||
std::for_each(
|
||||
restrictions_list.begin(), restrictions_list.end(), transform_into_internal_types);
|
||||
TIMER_STOP(transform);
|
||||
log << "ok, after " << TIMER_SEC(transform) << "s";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
@ -259,7 +259,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
SharedBuffer buffer;
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes;
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
|
||||
std::vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
|
||||
std::vector<InputConditionalTurnRestriction> resulting_restrictions;
|
||||
};
|
||||
|
||||
tbb::filter_t<void, SharedBuffer> buffer_reader(
|
||||
@ -454,7 +454,6 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
|
||||
auto restriction_map = std::make_shared<RestrictionMap>(turn_restrictions);
|
||||
auto node_based_graph =
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_lights, coordinates, osm_node_ids);
|
||||
|
||||
@ -462,12 +461,13 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
GraphCompressor graph_compressor;
|
||||
graph_compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
*restriction_map,
|
||||
turn_restrictions,
|
||||
*node_based_graph,
|
||||
compressed_edge_container);
|
||||
|
||||
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
||||
|
||||
auto restriction_map = std::make_shared<RestrictionMap>(turn_restrictions);
|
||||
EdgeBasedGraphFactory edge_based_graph_factory(
|
||||
node_based_graph,
|
||||
compressed_edge_container,
|
||||
|
@ -73,19 +73,12 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractorCallbacks::ProcessRestriction(
|
||||
const boost::optional<InputRestrictionContainer> &restriction)
|
||||
void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestriction &restriction)
|
||||
{
|
||||
if (restriction)
|
||||
{
|
||||
external_memory.restrictions_list.push_back(restriction.get());
|
||||
// util::Log() << "from: " << restriction.get().restriction.from.node <<
|
||||
// ",via: " << restriction.get().restriction.via.node <<
|
||||
// ", to: " << restriction.get().restriction.to.node <<
|
||||
// ", only: " << (restriction.get().restriction.flags.is_only ?
|
||||
// "y" : "n");
|
||||
}
|
||||
external_memory.restrictions_list.push_back(restriction);
|
||||
// util::Log() << restriction.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the geometry contained in the ```input_way``` and the tags computed
|
||||
* by the lua profile inside ```parsed_way``` and computes all edge segments.
|
||||
|
@ -1,13 +1,18 @@
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/percent.hpp"
|
||||
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@ -15,13 +20,35 @@ namespace extractor
|
||||
|
||||
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
RestrictionMap &restriction_map,
|
||||
std::vector<TurnRestriction> &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);
|
||||
|
||||
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
|
||||
// indicated `directed` barriers
|
||||
std::unordered_set<NodeID> restriction_via_nodes;
|
||||
|
||||
const auto remember_via_nodes = [&](const auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
const auto &node = restriction.AsNodeRestriction();
|
||||
restriction_via_nodes.insert(node.via);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
restriction_via_nodes.insert(way.in_restriction.via);
|
||||
restriction_via_nodes.insert(way.out_restriction.via);
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
|
||||
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
util::Percent progress(log, original_number_of_nodes);
|
||||
@ -43,7 +70,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
}
|
||||
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (restriction_map.IsViaNode(node_v))
|
||||
if (restriction_via_nodes.count(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -199,11 +226,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);
|
||||
|
||||
restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
|
||||
restriction_compressor.Compress(node_u, node_v, node_w);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(forward_e1,
|
||||
|
104
src/extractor/restriction_compressor.cpp
Normal file
104
src/extractor/restriction_compressor.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restrictions)
|
||||
{
|
||||
// add a node restriction ptr to the heads/tails maps, needs to be a reference!
|
||||
auto index = [&](auto &element) {
|
||||
heads.insert(std::make_pair(element.from, &element));
|
||||
tails.insert(std::make_pair(element.to, &element));
|
||||
};
|
||||
// !needs to be reference, so we can get the correct address
|
||||
const auto index_heads_and_tails = [&](auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
auto &way_restriction = restriction.AsWayRestriction();
|
||||
index(way_restriction.in_restriction);
|
||||
index(way_restriction.out_restriction);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
auto &node_restriction = restriction.AsNodeRestriction();
|
||||
index(node_restriction);
|
||||
}
|
||||
};
|
||||
|
||||
// add all restrictions as their respective head-tail pointers
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_heads_and_tails);
|
||||
}
|
||||
|
||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
{
|
||||
const auto get_value = [](const auto pair) { return pair.second; };
|
||||
|
||||
// extract all head ptrs and move them from via to from.
|
||||
auto all_heads_range = heads.equal_range(via);
|
||||
std::vector<NodeRestriction *> head_ptrs;
|
||||
std::transform(
|
||||
all_heads_range.first, all_heads_range.second, std::back_inserter(head_ptrs), get_value);
|
||||
|
||||
const auto update_head = [&](auto ptr) {
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
BOOST_ASSERT(ptr->from == via);
|
||||
if (ptr->via == to)
|
||||
{
|
||||
ptr->from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == from);
|
||||
ptr->from = to;
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(head_ptrs.begin(), head_ptrs.end(), update_head);
|
||||
|
||||
const auto reinsert_head = [&](auto ptr) { heads.insert(std::make_pair(ptr->from, ptr)); };
|
||||
|
||||
// update the ptrs in our mapping
|
||||
heads.erase(via);
|
||||
std::for_each(head_ptrs.begin(), head_ptrs.end(), reinsert_head);
|
||||
|
||||
// extract all tail ptrs and move them from via to to
|
||||
auto all_tails_range = tails.equal_range(via);
|
||||
std::vector<NodeRestriction *> tail_ptrs;
|
||||
std::transform(
|
||||
all_tails_range.first, all_tails_range.second, std::back_inserter(tail_ptrs), get_value);
|
||||
|
||||
const auto update_tail = [&](auto ptr) {
|
||||
BOOST_ASSERT(ptr->to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (ptr->via == from)
|
||||
{
|
||||
ptr->to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == to);
|
||||
ptr->to = from;
|
||||
}
|
||||
};
|
||||
|
||||
const auto reinsert_tail = [&](auto ptr) { tails.insert(std::make_pair(ptr->to, ptr)); };
|
||||
|
||||
std::for_each(tail_ptrs.begin(), tail_ptrs.end(), update_tail);
|
||||
|
||||
// update tail ptrs in mapping
|
||||
tails.erase(via);
|
||||
std::for_each(tail_ptrs.begin(), tail_ptrs.end(), reinsert_tail);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
@ -1,5 +1,7 @@
|
||||
#include "extractor/restriction_map.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@ -11,17 +13,23 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
|
||||
// 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(restriction.from.node < std::numeric_limits<NodeID>::max());
|
||||
BOOST_ASSERT(restriction.via.node < std::numeric_limits<NodeID>::max());
|
||||
m_restriction_start_nodes.insert(restriction.from.node);
|
||||
m_no_turn_via_node_set.insert(restriction.via.node);
|
||||
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>(restriction.from.node),
|
||||
static_cast<NodeID>(restriction.via.node)};
|
||||
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);
|
||||
@ -47,8 +55,7 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
|
||||
}
|
||||
}
|
||||
++m_count;
|
||||
BOOST_ASSERT(restriction.to.node < std::numeric_limits<NodeID>::max());
|
||||
m_restriction_bucket_list.at(index).emplace_back(restriction.to.node,
|
||||
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to,
|
||||
restriction.flags.is_only);
|
||||
}
|
||||
}
|
||||
|
@ -54,14 +54,13 @@ RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
|
||||
* in the corresponding profile. We use it for both namespacing restrictions, as in
|
||||
* restriction:motorcar as well as whitelisting if its in except:motorcar.
|
||||
*/
|
||||
std::vector<InputRestrictionContainer>
|
||||
boost::optional<InputConditionalTurnRestriction>
|
||||
RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
{
|
||||
std::vector<InputRestrictionContainer> parsed_restrictions;
|
||||
// return if turn restrictions should be ignored
|
||||
if (!use_turn_restrictions)
|
||||
{
|
||||
return {};
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
osmium::tags::KeyFilter filter(false);
|
||||
@ -90,14 +89,14 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
// if it's not a restriction, continue;
|
||||
if (std::distance(fi_begin, fi_end) == 0)
|
||||
{
|
||||
return {};
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
// check if the restriction should be ignored
|
||||
const char *except = relation.get_value_by_key("except");
|
||||
if (except != nullptr && ShouldIgnoreRestriction(except))
|
||||
{
|
||||
return {};
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
bool is_only_restriction = false;
|
||||
@ -119,11 +118,17 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
}
|
||||
else // unrecognized value type
|
||||
{
|
||||
return {};
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
InputRestrictionContainer restriction_container(is_only_restriction);
|
||||
// we pretend every restriction is a conditional restriction. If we do not find any restriction,
|
||||
// we can trim away the vector after parsing
|
||||
InputConditionalTurnRestriction restriction_container;
|
||||
restriction_container.flags.is_only = is_only_restriction;
|
||||
|
||||
boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
|
||||
bool is_node_restriction;
|
||||
|
||||
for (const auto &member : relation.members())
|
||||
{
|
||||
@ -136,33 +141,35 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
switch (member.type())
|
||||
{
|
||||
case osmium::item_type::node:
|
||||
{
|
||||
|
||||
// Make sure nodes appear only in the role if a via node
|
||||
if (0 == strcmp("from", role) || 0 == strcmp("to", role))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(0 == strcmp("via", role));
|
||||
|
||||
via = static_cast<std::uint64_t>(member.ref());
|
||||
is_node_restriction = true;
|
||||
// set via node id
|
||||
restriction_container.restriction.via.node = member.ref();
|
||||
break;
|
||||
|
||||
}
|
||||
case osmium::item_type::way:
|
||||
BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
|
||||
0 == strcmp("via", role));
|
||||
if (0 == strcmp("from", role))
|
||||
{
|
||||
restriction_container.restriction.from.way = member.ref();
|
||||
from = static_cast<std::uint64_t>(member.ref());
|
||||
}
|
||||
else if (0 == strcmp("to", role))
|
||||
{
|
||||
restriction_container.restriction.to.way = member.ref();
|
||||
to = static_cast<std::uint64_t>(member.ref());
|
||||
}
|
||||
else if (0 == strcmp("via", role))
|
||||
{
|
||||
via = static_cast<std::uint64_t>(member.ref());
|
||||
is_node_restriction = false;
|
||||
}
|
||||
// else if (0 == strcmp("via", role))
|
||||
// {
|
||||
// not yet suppported
|
||||
// restriction_container.restriction.via.way = member.ref();
|
||||
// }
|
||||
break;
|
||||
case osmium::item_type::relation:
|
||||
// not yet supported, but who knows what the future holds...
|
||||
@ -194,20 +201,29 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
std::vector<util::OpeningHours> hours = util::ParseOpeningHours(p.condition);
|
||||
// found unrecognized condition, continue
|
||||
if (hours.empty())
|
||||
return {};
|
||||
return boost::none;
|
||||
|
||||
restriction_container.restriction.condition = std::move(hours);
|
||||
restriction_container.condition = std::move(hours);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// push back a copy of turn restriction
|
||||
if (restriction_container.restriction.via.node != SPECIAL_NODEID &&
|
||||
restriction_container.restriction.from.node != SPECIAL_NODEID &&
|
||||
restriction_container.restriction.to.node != SPECIAL_NODEID)
|
||||
parsed_restrictions.push_back(restriction_container);
|
||||
|
||||
return parsed_restrictions;
|
||||
if (from && via && to)
|
||||
{
|
||||
if (is_node_restriction)
|
||||
{
|
||||
restriction_container.node_or_way = InputNodeRestriction{*from, *via, *to};
|
||||
}
|
||||
else
|
||||
{
|
||||
restriction_container.node_or_way = InputWayRestriction{*from, *via, *to};
|
||||
}
|
||||
return restriction_container;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
|
||||
|
@ -613,11 +613,10 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
const RestrictionParser &restriction_parser,
|
||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||
std::vector<boost::optional<InputRestrictionContainer>> &resulting_restrictions)
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
|
||||
{
|
||||
ExtractionNode result_node;
|
||||
ExtractionWay result_way;
|
||||
std::vector<InputRestrictionContainer> result_res;
|
||||
auto &local_context = this->GetSol2Context();
|
||||
|
||||
for (auto entity = buffer.cbegin(), end = buffer.cend(); entity != end; ++entity)
|
||||
@ -645,12 +644,13 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
static_cast<const osmium::Way &>(*entity), std::move(result_way)));
|
||||
break;
|
||||
case osmium::item_type::relation:
|
||||
result_res.clear();
|
||||
result_res =
|
||||
restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity));
|
||||
for (const InputRestrictionContainer &r : result_res)
|
||||
{
|
||||
resulting_restrictions.push_back(r);
|
||||
auto result_res =
|
||||
restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity));
|
||||
if (result_res)
|
||||
{
|
||||
resulting_restrictions.push_back(*result_res);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -444,22 +444,18 @@ updateTurnPenalties(const UpdaterConfig &config,
|
||||
}
|
||||
|
||||
bool IsRestrictionValid(const Timezoner &tz_handler,
|
||||
const extractor::TurnRestriction &turn,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const extractor::PackedOSMIDs &osm_node_ids)
|
||||
const extractor::ConditionalTurnRestriction &turn,
|
||||
const std::vector<util::Coordinate> &coordinates)
|
||||
{
|
||||
const auto via_node = osm_node_ids[turn.via.node];
|
||||
const auto from_node = osm_node_ids[turn.from.node];
|
||||
const auto to_node = osm_node_ids[turn.to.node];
|
||||
if (turn.condition.empty())
|
||||
{
|
||||
osrm::util::Log(logWARNING) << "Condition parsing failed for the turn " << from_node
|
||||
<< " -> " << via_node << " -> " << to_node;
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!turn.condition.empty());
|
||||
|
||||
const auto lon = static_cast<double>(toFloating(coordinates[turn.via.node].lon));
|
||||
const auto lat = static_cast<double>(toFloating(coordinates[turn.via.node].lat));
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
// Get local time of the restriction
|
||||
@ -482,9 +478,8 @@ bool IsRestrictionValid(const Timezoner &tz_handler,
|
||||
std::vector<std::uint64_t>
|
||||
updateConditionalTurns(const UpdaterConfig &config,
|
||||
std::vector<TurnPenalty> &turn_weight_penalties,
|
||||
const std::vector<extractor::TurnRestriction> &conditional_turns,
|
||||
const std::vector<extractor::ConditionalTurnRestriction> &conditional_turns,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
Timezoner time_zone_handler)
|
||||
{
|
||||
// Mapped file pointer for turn indices
|
||||
@ -501,18 +496,28 @@ updateConditionalTurns(const UpdaterConfig &config,
|
||||
std::unordered_set<std::tuple<NodeID, NodeID, NodeID>,
|
||||
std::hash<std::tuple<NodeID, NodeID, NodeID>>>
|
||||
is_no_set;
|
||||
for (const auto &c : conditional_turns)
|
||||
for (const auto &node_or_way : conditional_turns)
|
||||
{
|
||||
// only add restrictions to the lookups if the restriction is valid now
|
||||
if (!IsRestrictionValid(time_zone_handler, c, coordinates, osm_node_ids))
|
||||
// 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 (c.flags.is_only)
|
||||
|
||||
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.flags.is_only)
|
||||
{
|
||||
is_only_lookup.lookup.push_back({std::make_tuple(c.from.node, c.via.node), c.to.node});
|
||||
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.node, c.via.node, c.to.node)});
|
||||
is_no_set.insert({std::make_tuple(c.from, c.via, c.to)});
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,7 +638,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
load_profile_properties);
|
||||
}
|
||||
|
||||
std::vector<extractor::TurnRestriction> conditional_turns;
|
||||
std::vector<extractor::ConditionalTurnRestriction> conditional_turns;
|
||||
if (update_conditional_turns)
|
||||
{
|
||||
using storage::io::FileReader;
|
||||
@ -691,12 +696,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,
|
||||
osm_node_ids,
|
||||
time_zone_handler);
|
||||
auto updated_turn_penalties = updateConditionalTurns(
|
||||
config, turn_weight_penalties, conditional_turns, coordinates, 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.
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(graph_compressor)
|
||||
|
||||
@ -51,7 +53,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
RestrictionMap map;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
|
||||
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
|
||||
@ -68,7 +70,7 @@ 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, map, graph, container);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
|
||||
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID);
|
||||
@ -88,7 +90,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
RestrictionMap map;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
|
||||
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
|
||||
@ -118,7 +120,7 @@ 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, map, graph, container);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
|
||||
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
|
||||
@ -140,7 +142,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
RestrictionMap map;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
|
||||
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
|
||||
@ -157,7 +159,7 @@ 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, map, graph, container);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
|
||||
@ -173,7 +175,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
RestrictionMap map;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
|
||||
std::vector<InputEdge> edges = {
|
||||
@ -184,7 +186,7 @@ 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, map, graph, container);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
|
||||
@ -199,7 +201,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
RestrictionMap map;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
|
||||
std::vector<InputEdge> edges = {
|
||||
@ -208,7 +210,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
|
||||
edges[1].data.reversed = true;
|
||||
|
||||
Graph graph(5, edges);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
|
||||
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
|
||||
|
Loading…
Reference in New Issue
Block a user