Calculating segregated node-based edges.
This commit is contained in:
parent
f460a9f17e
commit
ee7912f882
@ -47,6 +47,7 @@ namespace extractor
|
|||||||
|
|
||||||
class ScriptingEnvironment;
|
class ScriptingEnvironment;
|
||||||
struct ProfileProperties;
|
struct ProfileProperties;
|
||||||
|
class NodeBasedGraphFactory;
|
||||||
|
|
||||||
class Extractor
|
class Extractor
|
||||||
{
|
{
|
||||||
@ -100,6 +101,8 @@ class Extractor
|
|||||||
void WriteConditionalRestrictions(
|
void WriteConditionalRestrictions(
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||||
|
|
||||||
|
size_t FindSegregatedNodes(NodeBasedGraphFactory &factory);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,13 @@ class NodeBasedGraphFactory
|
|||||||
// node-based graph to represent the OSM network. This includes geometry compression, annotation
|
// node-based graph to represent the OSM network. This includes geometry compression, annotation
|
||||||
// data optimisation and many other aspects. After this step, the edge-based graph factory can
|
// data optimisation and many other aspects. After this step, the edge-based graph factory can
|
||||||
// turn the graph into the routing graph to be used with the navigation algorithms.
|
// turn the graph into the routing graph to be used with the navigation algorithms.
|
||||||
NodeBasedGraphFactory(const boost::filesystem::path &input_file,
|
NodeBasedGraphFactory(const boost::filesystem::path &input_file);
|
||||||
ScriptingEnvironment &scripting_environment,
|
|
||||||
|
void CompressAll(ScriptingEnvironment &scripting_environment,
|
||||||
std::vector<TurnRestriction> &turn_restrictions,
|
std::vector<TurnRestriction> &turn_restrictions,
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||||
|
|
||||||
auto const &GetGraph() const { return compressed_output_graph; }
|
auto &GetGraph() { return compressed_output_graph; }
|
||||||
auto const &GetBarriers() const { return barriers; }
|
auto const &GetBarriers() const { return barriers; }
|
||||||
auto const &GetTrafficSignals() const { return traffic_signals; }
|
auto const &GetTrafficSignals() const { return traffic_signals; }
|
||||||
auto &GetCompressedEdges() { return compressed_edge_container; }
|
auto &GetCompressedEdges() { return compressed_edge_container; }
|
||||||
|
@ -22,7 +22,7 @@ struct NodeBasedEdgeData
|
|||||||
{
|
{
|
||||||
NodeBasedEdgeData()
|
NodeBasedEdgeData()
|
||||||
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}),
|
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}),
|
||||||
reversed(false), annotation_data(-1)
|
reversed(false), segregated(false), annotation_data(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ struct NodeBasedEdgeData
|
|||||||
extractor::NodeBasedEdgeClassification flags,
|
extractor::NodeBasedEdgeClassification flags,
|
||||||
AnnotationID annotation_data)
|
AnnotationID annotation_data)
|
||||||
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed),
|
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed),
|
||||||
flags(flags), annotation_data(annotation_data)
|
segregated(false), flags(flags), annotation_data(annotation_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ struct NodeBasedEdgeData
|
|||||||
EdgeWeight duration;
|
EdgeWeight duration;
|
||||||
GeometryID geometry_id;
|
GeometryID geometry_id;
|
||||||
bool reversed : 1;
|
bool reversed : 1;
|
||||||
|
bool segregated : 1;
|
||||||
extractor::NodeBasedEdgeClassification flags;
|
extractor::NodeBasedEdgeClassification flags;
|
||||||
AnnotationID annotation_data;
|
AnnotationID annotation_data;
|
||||||
};
|
};
|
||||||
|
@ -212,10 +212,19 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
|||||||
std::vector<EdgeWeight> edge_based_node_weights;
|
std::vector<EdgeWeight> edge_based_node_weights;
|
||||||
|
|
||||||
// Create a node-based graph from the OSRM file
|
// Create a node-based graph from the OSRM file
|
||||||
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
|
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"));
|
||||||
scripting_environment,
|
|
||||||
turn_restrictions,
|
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
|
||||||
conditional_turn_restrictions);
|
TIMER_START(segregated);
|
||||||
|
|
||||||
|
const size_t segregated_count = FindSegregatedNodes(node_based_graph_factory);
|
||||||
|
|
||||||
|
TIMER_STOP(segregated);
|
||||||
|
util::Log() << "ok, after " << TIMER_SEC(segregated) << "s";
|
||||||
|
util::Log() << "Segregated edges count = " << segregated_count;
|
||||||
|
|
||||||
|
node_based_graph_factory.CompressAll(
|
||||||
|
scripting_environment, turn_restrictions, conditional_turn_restrictions);
|
||||||
|
|
||||||
util::Log() << "Writing nodes for nodes-based and edges-based graphs ...";
|
util::Log() << "Writing nodes for nodes-based and edges-based graphs ...";
|
||||||
auto const &coordinates = node_based_graph_factory.GetCoordinates();
|
auto const &coordinates = node_based_graph_factory.GetCoordinates();
|
||||||
@ -826,5 +835,214 @@ void Extractor::WriteCompressedNodeBasedGraph(const std::string &path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EdgeInfo
|
||||||
|
{
|
||||||
|
NodeID node;
|
||||||
|
|
||||||
|
util::StringView name;
|
||||||
|
|
||||||
|
// 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming
|
||||||
|
int direction;
|
||||||
|
|
||||||
|
ClassData road_class;
|
||||||
|
|
||||||
|
struct LessName
|
||||||
|
{
|
||||||
|
bool operator()(EdgeInfo const &e1, EdgeInfo const &e2) const { return e1.name < e2.name; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool IsSegregated(std::vector<EdgeInfo> v1, std::vector<EdgeInfo> v2, EdgeInfo const ¤t)
|
||||||
|
{
|
||||||
|
if (v1.size() < 2 || v2.size() < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto const sort_by_name_fn = [](std::vector<EdgeInfo> &v) {
|
||||||
|
std::sort(v.begin(), v.end(), EdgeInfo::LessName());
|
||||||
|
};
|
||||||
|
|
||||||
|
sort_by_name_fn(v1);
|
||||||
|
sort_by_name_fn(v2);
|
||||||
|
|
||||||
|
// Internal edge with the name should be connected with any other neibour edge with the same
|
||||||
|
// name, e.g. isolated edge with unique name is not segregated.
|
||||||
|
// b - 'b' road continues here
|
||||||
|
// |
|
||||||
|
// - - a - |
|
||||||
|
// b - segregated edge
|
||||||
|
// - - a - |
|
||||||
|
if (!current.name.empty())
|
||||||
|
{
|
||||||
|
auto const findNameFn = [¤t](std::vector<EdgeInfo> const &v) {
|
||||||
|
return std::binary_search(v.begin(), v.end(), current, EdgeInfo::LessName());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!findNameFn(v1) && !findNameFn(v2))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EdgeInfo> intersect;
|
||||||
|
std::set_intersection(v1.begin(),
|
||||||
|
v1.end(),
|
||||||
|
v2.begin(),
|
||||||
|
v2.end(),
|
||||||
|
std::back_inserter(intersect),
|
||||||
|
EdgeInfo::LessName());
|
||||||
|
|
||||||
|
intersect.erase(std::remove_if(intersect.begin(),
|
||||||
|
intersect.end(),
|
||||||
|
[](EdgeInfo const &info) { return info.name.empty(); }),
|
||||||
|
intersect.end());
|
||||||
|
|
||||||
|
return intersect.size() >= 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// set_intersection like routine to count equal name pairs, std function is
|
||||||
|
// not acceptable because of duplicates {a, a, b} ∩ {a, a, c} == {a, a}.
|
||||||
|
std::vector<std::pair<EdgeInfo const *, EdgeInfo const *>> commons;
|
||||||
|
|
||||||
|
auto i1 = v1.begin();
|
||||||
|
auto i2 = v2.begin();
|
||||||
|
|
||||||
|
while (i1 != v1.end() && i2 != v2.end())
|
||||||
|
{
|
||||||
|
if (i1->name_id == i2->name_id)
|
||||||
|
{
|
||||||
|
if (i1->name_id != EMPTY_NAMEID)
|
||||||
|
commons.push_back(std::make_pair(&(*i1), &(*i2)));
|
||||||
|
|
||||||
|
++i1;
|
||||||
|
++i2;
|
||||||
|
}
|
||||||
|
else if (i1->name_id < i2->name_id)
|
||||||
|
++i1;
|
||||||
|
else
|
||||||
|
++i2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (commons.size() >= 2);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @todo Process standalone U-turns.
|
||||||
|
/*
|
||||||
|
switch (commons.size())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
case 1:
|
||||||
|
// ingoing + outgoing edges
|
||||||
|
if (commons.front().first->direction + commons.front().second->direction != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Extractor::FindSegregatedNodes(NodeBasedGraphFactory &factory)
|
||||||
|
{
|
||||||
|
util::NameTable names(config.GetPath(".osrm.names").string());
|
||||||
|
|
||||||
|
auto &graph = factory.GetGraph();
|
||||||
|
auto const &annotation = factory.GetAnnotationData();
|
||||||
|
auto const &coordinates = factory.GetCoordinates();
|
||||||
|
|
||||||
|
auto const get_edge_name = [&](auto const &data) {
|
||||||
|
/// @todo Make string normalization/lowercase/trim for comparison ...
|
||||||
|
|
||||||
|
auto const id = annotation[data.annotation_data].name_id;
|
||||||
|
BOOST_ASSERT(id != INVALID_NAMEID);
|
||||||
|
return names.GetNameForID(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const get_edge_classes = [&](auto const &data) {
|
||||||
|
return annotation[data.annotation_data].classes;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
|
||||||
|
std::vector<EdgeInfo> info;
|
||||||
|
|
||||||
|
for (auto const &e : edges1)
|
||||||
|
{
|
||||||
|
NodeID const target = graph.GetTarget(e);
|
||||||
|
if (target == node2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto const &data = graph.GetEdgeData(e);
|
||||||
|
info.push_back(
|
||||||
|
{target, get_edge_name(data), data.reversed ? 1 : 0, get_edge_classes(data)});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.empty())
|
||||||
|
return info;
|
||||||
|
|
||||||
|
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
|
||||||
|
return e1.node < e2.node;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge equal infos with correct direction.
|
||||||
|
auto curr = info.begin();
|
||||||
|
auto next = curr;
|
||||||
|
while (++next != info.end())
|
||||||
|
{
|
||||||
|
if (curr->node == next->node)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(curr->name == next->name);
|
||||||
|
BOOST_ASSERT(curr->road_class == next->road_class);
|
||||||
|
BOOST_ASSERT(curr->direction != next->direction);
|
||||||
|
curr->direction = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
curr = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.erase(
|
||||||
|
std::unique(info.begin(),
|
||||||
|
info.end(),
|
||||||
|
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
|
||||||
|
info.end());
|
||||||
|
|
||||||
|
return info;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const isSegregatedFn = [&](
|
||||||
|
auto const &edgeData, auto const &edges1, NodeID node1, auto const &edges2, NodeID node2) {
|
||||||
|
return IsSegregated(collect_edge_info_fn(edges1, node2),
|
||||||
|
collect_edge_info_fn(edges2, node1),
|
||||||
|
{node1, get_edge_name(edgeData), 0, get_edge_classes(edgeData)});
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_set<EdgeID> processed;
|
||||||
|
size_t segregated_count = 0;
|
||||||
|
|
||||||
|
for (NodeID sourceID = 0; sourceID < graph.GetNumberOfNodes(); ++sourceID)
|
||||||
|
{
|
||||||
|
auto const sourceEdges = graph.GetAdjacentEdgeRange(sourceID);
|
||||||
|
for (EdgeID edgeID : sourceEdges)
|
||||||
|
{
|
||||||
|
auto &edgeData = graph.GetEdgeData(edgeID);
|
||||||
|
|
||||||
|
if (edgeData.reversed || edgeData.segregated || !processed.insert(edgeID).second)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
NodeID const targetID = graph.GetTarget(edgeID);
|
||||||
|
|
||||||
|
if (osrm::util::coordinate_calculation::haversineDistance(coordinates[sourceID],
|
||||||
|
coordinates[targetID]) > 30.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto const targetEdges = graph.GetAdjacentEdgeRange(targetID);
|
||||||
|
|
||||||
|
if (isSegregatedFn(edgeData, sourceEdges, sourceID, targetEdges, targetID))
|
||||||
|
{
|
||||||
|
++segregated_count;
|
||||||
|
edgeData.segregated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return segregated_count;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace extractor
|
} // namespace extractor
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
@ -15,13 +15,16 @@ namespace osrm
|
|||||||
namespace extractor
|
namespace extractor
|
||||||
{
|
{
|
||||||
|
|
||||||
NodeBasedGraphFactory::NodeBasedGraphFactory(
|
NodeBasedGraphFactory::NodeBasedGraphFactory(const boost::filesystem::path &input_file)
|
||||||
const boost::filesystem::path &input_file,
|
{
|
||||||
|
LoadDataFromFile(input_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeBasedGraphFactory::CompressAll(
|
||||||
ScriptingEnvironment &scripting_environment,
|
ScriptingEnvironment &scripting_environment,
|
||||||
std::vector<TurnRestriction> &turn_restrictions,
|
std::vector<TurnRestriction> &turn_restrictions,
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
||||||
{
|
{
|
||||||
LoadDataFromFile(input_file);
|
|
||||||
Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions);
|
Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions);
|
||||||
CompressGeometry();
|
CompressGeometry();
|
||||||
CompressAnnotationData();
|
CompressAnnotationData();
|
||||||
|
Loading…
Reference in New Issue
Block a user