Unpacking of intermediate paths
This commit is contained in:
@@ -45,6 +45,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
SpeedProfileProperties speed_profile
|
||||
) : speed_profile(speed_profile),
|
||||
m_turn_restrictions_count(0),
|
||||
m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
|
||||
m_node_info_list(node_info_list)
|
||||
{
|
||||
BOOST_FOREACH(const TurnRestriction & restriction, input_restrictions_list) {
|
||||
@@ -106,7 +107,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
BOOST_ASSERT( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = import_edge.isRoundabout();
|
||||
edge.data.ignoreInGrid = import_edge.ignoreInGrid();
|
||||
edge.data.ignore_in_grid = import_edge.ignoreInGrid();
|
||||
edge.data.nameID = import_edge.name();
|
||||
edge.data.type = import_edge.type();
|
||||
edge.data.isAccessRestricted = import_edge.isAccessRestricted();
|
||||
@@ -134,9 +135,9 @@ void EdgeBasedGraphFactory::FixupArrivingTurnRestriction(
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) {
|
||||
BOOST_ASSERT( u != UINT_MAX );
|
||||
BOOST_ASSERT( v != UINT_MAX );
|
||||
BOOST_ASSERT( w != UINT_MAX );
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( v != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( w != std::numeric_limits<unsigned>::max() );
|
||||
|
||||
std::vector<NodeID> predecessors;
|
||||
for(
|
||||
@@ -173,9 +174,9 @@ void EdgeBasedGraphFactory::FixupStartingTurnRestriction(
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) {
|
||||
BOOST_ASSERT( u != UINT_MAX );
|
||||
BOOST_ASSERT( v != UINT_MAX );
|
||||
BOOST_ASSERT( w != UINT_MAX );
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( v != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( w != std::numeric_limits<unsigned>::max() );
|
||||
|
||||
const std::pair<NodeID, NodeID> old_start = std::make_pair(v,w);
|
||||
RestrictionMap::const_iterator restriction_iterator;
|
||||
@@ -215,8 +216,8 @@ NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(
|
||||
const NodeID u,
|
||||
const NodeID v
|
||||
) const {
|
||||
BOOST_ASSERT( u != UINT_MAX );
|
||||
BOOST_ASSERT( v != UINT_MAX );
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( v != std::numeric_limits<unsigned>::max() );
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iter;
|
||||
restriction_iter = m_restriction_map.find(restriction_source);
|
||||
@@ -231,7 +232,7 @@ NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
bool EdgeBasedGraphFactory::CheckIfTurnIsRestricted(
|
||||
@@ -239,9 +240,9 @@ bool EdgeBasedGraphFactory::CheckIfTurnIsRestricted(
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const {
|
||||
BOOST_ASSERT( u != UINT_MAX );
|
||||
BOOST_ASSERT( v != UINT_MAX );
|
||||
BOOST_ASSERT( w != UINT_MAX );
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( v != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( w != std::numeric_limits<unsigned>::max() );
|
||||
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iter;
|
||||
@@ -264,29 +265,85 @@ bool EdgeBasedGraphFactory::CheckIfTurnIsRestricted(
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::InsertEdgeBasedNode(
|
||||
EdgeIterator e1,
|
||||
NodeIterator u,
|
||||
NodeIterator v,
|
||||
bool belongsToTinyComponent
|
||||
bool belongs_to_tiny_cc
|
||||
) {
|
||||
BOOST_ASSERT( u != UINT_MAX );
|
||||
BOOST_ASSERT( v != UINT_MAX );
|
||||
BOOST_ASSERT( e1 != UINT_MAX );
|
||||
EdgeData & data = m_node_based_graph->GetEdgeData(e1);
|
||||
EdgeBasedNode currentNode;
|
||||
currentNode.nameID = data.nameID;
|
||||
currentNode.lat1 = m_node_info_list[u].lat;
|
||||
currentNode.lon1 = m_node_info_list[u].lon;
|
||||
currentNode.lat2 = m_node_info_list[v].lat;
|
||||
currentNode.lon2 = m_node_info_list[v].lon;
|
||||
if( m_geometry_compressor.HasEntryForID(e1) ) {
|
||||
//reconstruct geometry and put in each individual edge with its offset
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( v != std::numeric_limits<unsigned>::max() );
|
||||
|
||||
// find forward edge id and
|
||||
const EdgeID e1 = m_node_based_graph->FindEdge(u, v);
|
||||
BOOST_ASSERT( e1 != std::numeric_limits<unsigned>::max() );
|
||||
const EdgeData & forward_data = m_node_based_graph->GetEdgeData(e1);
|
||||
|
||||
if( forward_data.ignore_in_grid ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "skipped edge at " << m_node_info_list[u].lat << "," <<
|
||||
// m_node_info_list[u].lon << " - " <<
|
||||
// m_node_info_list[v].lat << "," <<
|
||||
// m_node_info_list[v].lon;
|
||||
|
||||
return;
|
||||
}
|
||||
currentNode.belongsToTinyComponent = belongsToTinyComponent;
|
||||
currentNode.id = data.edgeBasedNodeID;
|
||||
currentNode.ignoreInGrid = data.ignoreInGrid;
|
||||
currentNode.weight = data.distance;
|
||||
m_edge_based_node_list.push_back(currentNode);
|
||||
|
||||
// find reverse edge id and
|
||||
const EdgeID e2 = m_node_based_graph->FindEdge(v, u);
|
||||
BOOST_ASSERT( e2 != std::numeric_limits<unsigned>::max() );
|
||||
const EdgeData & reverse_data = m_node_based_graph->GetEdgeData(e2);
|
||||
|
||||
if( m_geometry_compressor.HasEntryForID(e1) ) {
|
||||
BOOST_ASSERT( m_geometry_compressor.HasEntryForID(e2) );
|
||||
|
||||
// reconstruct geometry and put in each individual edge with its offset
|
||||
const std::vector<GeometryCompressor::CompressedNode> & forward_geometry = m_geometry_compressor.GetBucketReference(e1);
|
||||
const std::vector<GeometryCompressor::CompressedNode> & reverse_geometry = m_geometry_compressor.GetBucketReference(e2);
|
||||
BOOST_ASSERT( forward_geometry.size() == reverse_geometry.size() );
|
||||
BOOST_ASSERT( 0 != forward_geometry.size() );
|
||||
for( unsigned i = 0; i < reverse_geometry.size(); ++i ) {
|
||||
if( forward_geometry[i].first != reverse_geometry[reverse_geometry.size()-1-i].first ) {
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write() << "size1: " << forward_geometry.size() << ", size2: " << reverse_geometry.size();
|
||||
SimpleLogger().Write() << "index1: " << i << ", index2: " << reverse_geometry.size()-1-i;
|
||||
SimpleLogger().Write() << forward_geometry[0].first << "!=" << reverse_geometry[reverse_geometry.size()-1-i].first;
|
||||
BOOST_FOREACH(const GeometryCompressor::CompressedNode geometry_node, forward_geometry) {
|
||||
SimpleLogger().Write(logDEBUG) << "fwd node " << geometry_node.first << "," << m_node_info_list[geometry_node.first].lat/COORDINATE_PRECISION << "," << m_node_info_list[geometry_node.first].lon/COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_FOREACH(const GeometryCompressor::CompressedNode geometry_node, reverse_geometry) {
|
||||
SimpleLogger().Write(logDEBUG) << "rev node " << geometry_node.first << "," << m_node_info_list[geometry_node.first].lat/COORDINATE_PRECISION << "," << m_node_info_list[geometry_node.first].lon/COORDINATE_PRECISION;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
BOOST_ASSERT( forward_geometry[i].first == reverse_geometry[reverse_geometry.size()-1-i].first );
|
||||
|
||||
//TODO reconstruct bidirectional edge with weights.
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
// SimpleLogger().Write(logDEBUG) << "start " << m_node_info_list[u].lat << "," << m_node_info_list[u].lon;
|
||||
// SimpleLogger().Write(logDEBUG) << "target " << m_node_info_list[v].lat << "," << m_node_info_list[v].lon;
|
||||
// BOOST_ASSERT( false );
|
||||
} //else {
|
||||
//TODO: emplace back with C++11
|
||||
m_edge_based_node_list.push_back(
|
||||
EdgeBasedNode(
|
||||
forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
m_node_info_list[u].lat,
|
||||
m_node_info_list[u].lon,
|
||||
m_node_info_list[v].lat,
|
||||
m_node_info_list[v].lon,
|
||||
belongs_to_tiny_cc,
|
||||
forward_data.nameID, //TODO use also reverse name id?
|
||||
forward_data.distance,
|
||||
reverse_data.distance,
|
||||
0,
|
||||
0
|
||||
)
|
||||
);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -329,25 +386,25 @@ void EdgeBasedGraphFactory::Run(
|
||||
|
||||
const bool reverse_edge_order = !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
|
||||
const EdgeIterator forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
|
||||
BOOST_ASSERT( UINT_MAX != forward_e2 );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != forward_e2 );
|
||||
const EdgeIterator reverse_e2 = m_node_based_graph->BeginEdges(v) + 1 - reverse_edge_order;
|
||||
BOOST_ASSERT( UINT_MAX != reverse_e2 );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != reverse_e2 );
|
||||
|
||||
const EdgeData & fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
|
||||
const EdgeData & rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
|
||||
|
||||
const NodeIterator w = m_node_based_graph->GetTarget(forward_e2);
|
||||
BOOST_ASSERT( UINT_MAX != w );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != w );
|
||||
BOOST_ASSERT( v != w );
|
||||
const NodeIterator u = m_node_based_graph->GetTarget(reverse_e2);
|
||||
BOOST_ASSERT( UINT_MAX != u );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != u );
|
||||
BOOST_ASSERT( u != v );
|
||||
|
||||
const EdgeIterator forward_e1 = m_node_based_graph->FindEdge(u, v);
|
||||
BOOST_ASSERT( UINT_MAX != forward_e1 );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != forward_e1 );
|
||||
BOOST_ASSERT( v == m_node_based_graph->GetTarget(forward_e1));
|
||||
const EdgeIterator reverse_e1 = m_node_based_graph->FindEdge(w, v);
|
||||
BOOST_ASSERT( UINT_MAX != reverse_e1 );
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != reverse_e1 );
|
||||
BOOST_ASSERT( v == m_node_based_graph->GetTarget(reverse_e1));
|
||||
|
||||
const EdgeData & fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
|
||||
@@ -367,6 +424,12 @@ void EdgeBasedGraphFactory::Run(
|
||||
m_node_based_graph->SetTarget(forward_e1, w);
|
||||
m_node_based_graph->SetTarget(reverse_e1, u);
|
||||
|
||||
const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
|
||||
// const int forward_weight2 = fwd_edge_data2.distance;
|
||||
|
||||
const int reverse_weight1 = m_node_based_graph->GetEdgeData(reverse_e1).distance;
|
||||
// const int reverse_weight2 = rev_edge_data2.distance;
|
||||
|
||||
// add weight of e2's to e1
|
||||
m_node_based_graph->GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
m_node_based_graph->GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
@@ -382,9 +445,21 @@ void EdgeBasedGraphFactory::Run(
|
||||
FixupStartingTurnRestriction( w, v, u );
|
||||
FixupArrivingTurnRestriction( w, v, u );
|
||||
|
||||
//TODO: store compressed geometry in container
|
||||
m_geometry_compressor.CompressEdge( forward_e1, forward_e2, v );
|
||||
m_geometry_compressor.CompressEdge( reverse_e1, reverse_e2, v );
|
||||
// store compressed geometry in container
|
||||
m_geometry_compressor.CompressEdge(
|
||||
forward_e1,
|
||||
forward_e2,
|
||||
v,
|
||||
forward_weight1//,
|
||||
// forward_weight2
|
||||
);
|
||||
m_geometry_compressor.CompressEdge(
|
||||
reverse_e1,
|
||||
reverse_e2,
|
||||
v,
|
||||
reverse_weight1//,
|
||||
// reverse_weight2
|
||||
);
|
||||
|
||||
++removed_node_count;
|
||||
}
|
||||
@@ -405,8 +480,7 @@ void EdgeBasedGraphFactory::Run(
|
||||
SimpleLogger().Write() << "Edge compression ratio: " << new_edge_count/(double)original_number_of_edges;
|
||||
|
||||
//Extract routing graph
|
||||
DeallocatingVector<NodeBasedEdge> edges_list;
|
||||
NodeBasedEdge new_edge;
|
||||
unsigned numbered_edges_count = 0;
|
||||
for(NodeID source = 0; source < m_node_based_graph->GetNumberOfNodes(); ++source) {
|
||||
for(
|
||||
EdgeID current_edge_id = m_node_based_graph->BeginEdges(source);
|
||||
@@ -414,44 +488,37 @@ void EdgeBasedGraphFactory::Run(
|
||||
++current_edge_id
|
||||
) {
|
||||
const NodeID target = m_node_based_graph->GetTarget(current_edge_id);
|
||||
const EdgeData & edge_data = m_node_based_graph->GetEdgeData(current_edge_id);
|
||||
if( source > target ) {
|
||||
EdgeData & edge_data = m_node_based_graph->GetEdgeData(current_edge_id);
|
||||
if( 0 == numbered_edges_count ){
|
||||
SimpleLogger().Write(logDEBUG) << "uninitialized edge based node id: " << edge_data.edgeBasedNodeID;
|
||||
}
|
||||
if( !edge_data.forward ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "skipped edge (" << source << "," << target << ")=[" << current_edge_id << "]";
|
||||
continue;
|
||||
}
|
||||
if( edge_data.forward) {
|
||||
new_edge.source = source;
|
||||
new_edge.target = target;
|
||||
new_edge.data = edge_data;
|
||||
new_edge.data.edgeBasedNodeID = edges_list.size();
|
||||
edges_list.push_back(new_edge);
|
||||
if( edge_data.edgeBasedNodeID != std::numeric_limits<unsigned>::max() ) {//source > target ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "skipping edge based node id: " << edge_data.edgeBasedNodeID;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT( numbered_edges_count < m_node_based_graph->GetNumberOfEdges() );
|
||||
edge_data.edgeBasedNodeID = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
|
||||
const EdgeID reverse_edge_id = m_node_based_graph->FindEdge(target, source);
|
||||
BOOST_ASSERT( reverse_edge_id != m_node_based_graph->EndEdges(target));
|
||||
|
||||
const EdgeData & reverse_edge_data = m_node_based_graph->GetEdgeData(reverse_edge_id);
|
||||
if( reverse_edge_data.forward ) {
|
||||
new_edge.source = target;
|
||||
new_edge.target = source;
|
||||
new_edge.data = reverse_edge_data;
|
||||
new_edge.data.edgeBasedNodeID = edges_list.size();
|
||||
edges_list.push_back(new_edge);
|
||||
EdgeData & reverse_edge_data = m_node_based_graph->GetEdgeData(reverse_edge_id);
|
||||
if( !reverse_edge_data.forward ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT( numbered_edges_count < m_node_based_graph->GetNumberOfEdges() );
|
||||
reverse_edge_data.edgeBasedNodeID = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
}
|
||||
}
|
||||
m_node_based_graph.reset();
|
||||
|
||||
std::sort( edges_list.begin(), edges_list.end() );
|
||||
|
||||
//Instantiate routing graph
|
||||
m_node_based_graph = boost::make_shared<NodeBasedDynamicGraph>(
|
||||
original_number_of_nodes,
|
||||
edges_list
|
||||
);
|
||||
|
||||
DeallocatingVector<NodeBasedEdge>().swap(edges_list);
|
||||
BOOST_ASSERT(0 == edges_list.size() );
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "numbered " << numbered_edges_count << " edge-expanded nodes";
|
||||
SimpleLogger().Write() << "Identifying components of the road network";
|
||||
|
||||
unsigned node_based_edge_counter = 0;
|
||||
@@ -479,12 +546,15 @@ void EdgeBasedGraphFactory::Run(
|
||||
"generating edge-expanded nodes";
|
||||
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
//loop over all edges and generate new set of nodes
|
||||
for(
|
||||
NodeIterator u = 0, end = m_node_based_graph->GetNumberOfNodes();
|
||||
u < end;
|
||||
++u
|
||||
) {
|
||||
BOOST_ASSERT( u != std::numeric_limits<unsigned>::max() );
|
||||
BOOST_ASSERT( u < m_node_based_graph->GetNumberOfNodes() );
|
||||
p.printIncrement();
|
||||
for(
|
||||
EdgeIterator e1 = m_node_based_graph->BeginEdges(u),
|
||||
@@ -492,24 +562,32 @@ void EdgeBasedGraphFactory::Run(
|
||||
e1 < last_edge;
|
||||
++e1
|
||||
) {
|
||||
BOOST_ASSERT( e1 != std::numeric_limits<unsigned>::max() );
|
||||
NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
BOOST_ASSERT( std::numeric_limits<unsigned>::max() != v );
|
||||
// pick only every other edge
|
||||
if( u > v ) {
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT( u < v );
|
||||
BOOST_ASSERT(
|
||||
m_node_based_graph->GetEdgeData(e1).type != SHRT_MAX
|
||||
);
|
||||
|
||||
if(m_node_based_graph->GetEdgeData(e1).type != SHRT_MAX) {
|
||||
BOOST_ASSERT_MSG(e1 != UINT_MAX, "edge id invalid");
|
||||
BOOST_ASSERT_MSG(u != UINT_MAX, "souce node invalid");
|
||||
BOOST_ASSERT_MSG(v != UINT_MAX, "target node invalid");
|
||||
//Note: edges that end on barrier nodes or on a turn restriction
|
||||
//may actually be in two distinct components. We choose the smallest
|
||||
const unsigned size_of_component = std::min(
|
||||
component_index_size[component_index_list[u]],
|
||||
component_index_size[component_index_list[v]]
|
||||
);
|
||||
const unsigned size_of_component = std::min(
|
||||
component_index_size[component_index_list[u]],
|
||||
component_index_size[component_index_list[v]]
|
||||
);
|
||||
|
||||
InsertEdgeBasedNode( e1, u, v, size_of_component < 1000 );
|
||||
}
|
||||
InsertEdgeBasedNode( u, v, size_of_component < 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check if correct, suspect two off by ones here
|
||||
m_number_of_edge_based_nodes = numbered_edges_count;
|
||||
|
||||
SimpleLogger().Write()
|
||||
<< "Generated " << m_edge_based_node_list.size() << " nodes in " <<
|
||||
"edge-expanded graph";
|
||||
@@ -534,6 +612,7 @@ void EdgeBasedGraphFactory::Run(
|
||||
unsigned restricted_turns_counter = 0;
|
||||
unsigned skipped_uturns_counter = 0;
|
||||
unsigned skipped_barrier_turns_counter = 0;
|
||||
unsigned compressed = 0;
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
for(
|
||||
NodeIterator u = 0, end = m_node_based_graph->GetNumberOfNodes();
|
||||
@@ -546,6 +625,10 @@ void EdgeBasedGraphFactory::Run(
|
||||
e1 < last_edge_u;
|
||||
++e1
|
||||
) {
|
||||
if( !m_node_based_graph->GetEdgeData(e1).forward ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++node_based_edge_counter;
|
||||
const NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
const NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v);
|
||||
@@ -557,9 +640,12 @@ void EdgeBasedGraphFactory::Run(
|
||||
e2 < last_edge_v;
|
||||
++e2
|
||||
) {
|
||||
if( !m_node_based_graph->GetEdgeData(e2).forward ) {
|
||||
continue;
|
||||
}
|
||||
const NodeIterator w = m_node_based_graph->GetTarget(e2);
|
||||
if(
|
||||
to_node_of_only_restriction != UINT_MAX &&
|
||||
to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
|
||||
w != to_node_of_only_restriction
|
||||
) {
|
||||
//We are at an only_-restriction but not at the right turn.
|
||||
@@ -583,7 +669,7 @@ void EdgeBasedGraphFactory::Run(
|
||||
//at the end of a dead-end street
|
||||
if (
|
||||
CheckIfTurnIsRestricted(u, v, w) &&
|
||||
(to_node_of_only_restriction == UINT_MAX) &&
|
||||
(to_node_of_only_restriction == std::numeric_limits<unsigned>::max()) &&
|
||||
(w != to_node_of_only_restriction)
|
||||
) {
|
||||
++restricted_turns_counter;
|
||||
@@ -594,12 +680,12 @@ void EdgeBasedGraphFactory::Run(
|
||||
const EdgeData & edge_data1 = m_node_based_graph->GetEdgeData(e1);
|
||||
const EdgeData & edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
||||
|
||||
BOOST_ASSERT(
|
||||
edge_data1.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()
|
||||
);
|
||||
BOOST_ASSERT(
|
||||
edge_data2.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()
|
||||
);
|
||||
// BOOST_ASSERT(
|
||||
// edge_data1.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()
|
||||
// );
|
||||
// BOOST_ASSERT(
|
||||
// edge_data2.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()
|
||||
// );
|
||||
BOOST_ASSERT(
|
||||
edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID
|
||||
);
|
||||
@@ -612,22 +698,26 @@ void EdgeBasedGraphFactory::Run(
|
||||
distance += speed_profile.trafficSignalPenalty;
|
||||
}
|
||||
const int turn_penalty = GetTurnPenalty(u, v, w, lua_state);
|
||||
TurnInstruction turnInstruction = AnalyzeTurn(u, v, w);
|
||||
if(turnInstruction == TurnInstructions.UTurn){
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w);
|
||||
if(turn_instruction == TurnInstructions.UTurn){
|
||||
distance += speed_profile.uTurnPenalty;
|
||||
}
|
||||
distance += turn_penalty;
|
||||
|
||||
const bool edge_is_compressed = m_geometry_compressor.HasEntryForID(e1);
|
||||
if(edge_is_compressed) {
|
||||
m_geometry_compressor.AddNodeIDToCompressedEdge(e1, v);
|
||||
++compressed;
|
||||
m_geometry_compressor.AddLastViaNodeIDToCompressedEdge(e1, v, /*TODO*/ 1);
|
||||
if ( 0 == m_geometry_compressor.GetPositionForID(e1) ) {
|
||||
SimpleLogger().Write(logDEBUG) << "e1: " << e1 << " is zero with via node: " << v;
|
||||
}
|
||||
}
|
||||
|
||||
original_edge_data_vector.push_back(
|
||||
OriginalEdgeData(
|
||||
edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v,
|
||||
(edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
|
||||
edge_data2.nameID,
|
||||
turnInstruction,
|
||||
turn_instruction,
|
||||
edge_is_compressed
|
||||
)
|
||||
);
|
||||
@@ -656,10 +746,13 @@ void EdgeBasedGraphFactory::Run(
|
||||
}
|
||||
FlushVectorToStream( edge_data_file, original_edge_data_vector );
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "compressed: " << compressed;
|
||||
|
||||
edge_data_file.seekp( std::ios::beg );
|
||||
edge_data_file.write( (char*)&original_edges_counter, sizeof(unsigned) );
|
||||
edge_data_file.close();
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "serializing geometry to " << geometry_filename;
|
||||
m_geometry_compressor.SerializeInternalVector( geometry_filename );
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
@@ -769,8 +862,8 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(
|
||||
return TurnInstructions.GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
|
||||
return m_node_based_graph->GetNumberOfEdges();
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const {
|
||||
return m_number_of_edge_based_nodes;
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::BFSCompentExplorer(
|
||||
@@ -787,12 +880,12 @@ void EdgeBasedGraphFactory::BFSCompentExplorer(
|
||||
|
||||
component_index_list.resize(
|
||||
m_node_based_graph->GetNumberOfNodes(),
|
||||
UINT_MAX
|
||||
std::numeric_limits<unsigned>::max()
|
||||
);
|
||||
|
||||
//put unexplorered node with parent pointer into queue
|
||||
for( NodeID node = 0, end = m_node_based_graph->GetNumberOfNodes(); node < end; ++node) {
|
||||
if(UINT_MAX == component_index_list[node]) {
|
||||
if(std::numeric_limits<unsigned>::max() == component_index_list[node]) {
|
||||
bfs_queue.push(std::make_pair(node, node));
|
||||
//mark node as read
|
||||
component_index_list[node] = current_component;
|
||||
@@ -818,7 +911,7 @@ void EdgeBasedGraphFactory::BFSCompentExplorer(
|
||||
NodeIterator w = m_node_based_graph->GetTarget(e2);
|
||||
|
||||
if(
|
||||
to_node_of_only_restriction != UINT_MAX &&
|
||||
to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
|
||||
w != to_node_of_only_restriction
|
||||
) {
|
||||
// At an only_-restriction but not at the right turn
|
||||
@@ -829,7 +922,7 @@ void EdgeBasedGraphFactory::BFSCompentExplorer(
|
||||
//when it is at the end of a dead-end street.
|
||||
if (!CheckIfTurnIsRestricted(u, v, w) ) {
|
||||
//only add an edge if turn is not prohibited
|
||||
if(UINT_MAX == component_index_list[w]) {
|
||||
if(std::numeric_limits<unsigned>::max() == component_index_list[w]) {
|
||||
//insert next (node, parent) only if w has
|
||||
//not yet been explored
|
||||
//mark node as read
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
lua_State *myLuaState
|
||||
) const;
|
||||
|
||||
unsigned GetNumberOfNodes() const;
|
||||
unsigned GetNumberOfEdgeBasedNodes() const;
|
||||
|
||||
struct SpeedProfileProperties{
|
||||
SpeedProfileProperties() :
|
||||
@@ -110,6 +110,11 @@ public:
|
||||
|
||||
private:
|
||||
struct NodeBasedEdgeData {
|
||||
NodeBasedEdgeData() {
|
||||
//TODO: proper c'tor
|
||||
edgeBasedNodeID = UINT_MAX;
|
||||
}
|
||||
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID;
|
||||
@@ -119,7 +124,7 @@ private:
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
bool ignore_in_grid:1;
|
||||
bool contraFlow:1;
|
||||
|
||||
void SwapDirectionFlags() {
|
||||
@@ -132,12 +137,13 @@ private:
|
||||
return (forward == other.forward) &&
|
||||
(backward == other.backward) &&
|
||||
(nameID == other.nameID) &&
|
||||
(ignoreInGrid == other.ignoreInGrid) &&
|
||||
(ignore_in_grid == other.ignore_in_grid) &&
|
||||
(contraFlow == other.contraFlow);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned m_turn_restrictions_count;
|
||||
unsigned m_number_of_edge_based_nodes;
|
||||
|
||||
typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
|
||||
typedef NodeBasedDynamicGraph::InputEdge NodeBasedEdge;
|
||||
@@ -173,7 +179,6 @@ private:
|
||||
) const;
|
||||
|
||||
void InsertEdgeBasedNode(
|
||||
NodeBasedDynamicGraph::EdgeIterator e1,
|
||||
NodeBasedDynamicGraph::NodeIterator u,
|
||||
NodeBasedDynamicGraph::NodeIterator v,
|
||||
bool belongsToTinyComponent
|
||||
|
||||
@@ -37,7 +37,7 @@ int current_free_list_maximum = 0;
|
||||
int UniqueNumber () { return ++current_free_list_maximum; }
|
||||
|
||||
GeometryCompressor::GeometryCompressor() {
|
||||
m_free_list.resize(100);
|
||||
m_free_list.reserve(100);
|
||||
IncreaseFreeList();
|
||||
}
|
||||
|
||||
@@ -49,68 +49,91 @@ void GeometryCompressor::IncreaseFreeList() {
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryCompressor::HasEntryForID(const EdgeID edge_id) {
|
||||
bool GeometryCompressor::HasEntryForID(const EdgeID edge_id) const {
|
||||
return (m_edge_id_to_list_index_map.find(edge_id) != m_edge_id_to_list_index_map.end());
|
||||
}
|
||||
|
||||
unsigned GeometryCompressor::GetPositionForID(const EdgeID edge_id) {
|
||||
unsigned GeometryCompressor::GetPositionForID(const EdgeID edge_id) const {
|
||||
boost::unordered_map<EdgeID, unsigned>::const_iterator map_iterator;
|
||||
map_iterator = m_edge_id_to_list_index_map.find(edge_id);
|
||||
BOOST_ASSERT( map_iterator != m_edge_id_to_list_index_map.end() );
|
||||
BOOST_ASSERT( map_iterator->second < m_compressed_geometries.size() );
|
||||
return map_iterator->second;
|
||||
}
|
||||
|
||||
void GeometryCompressor::AddNodeIDToCompressedEdge(
|
||||
void GeometryCompressor::AddLastViaNodeIDToCompressedEdge(
|
||||
const EdgeID edge_id,
|
||||
const NodeID node_id
|
||||
const NodeID node_id,
|
||||
const EdgeWeight weight
|
||||
) {
|
||||
unsigned index = GetPositionForID(edge_id);
|
||||
BOOST_ASSERT( index < m_compressed_geometries.size() );
|
||||
m_compressed_geometries[index].push_back( node_id );
|
||||
if( !m_compressed_geometries[index].empty() ) {
|
||||
if( m_compressed_geometries[index].back().first == node_id ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT( node_id != m_compressed_geometries[index].back().first );
|
||||
m_compressed_geometries[index].push_back( std::make_pair(node_id, weight) );
|
||||
BOOST_ASSERT( node_id == m_compressed_geometries[index].back().first );
|
||||
}
|
||||
|
||||
void GeometryCompressor::SerializeInternalVector(
|
||||
const std::string & path
|
||||
) const {
|
||||
//TODO: remove super-trivial geometries
|
||||
|
||||
std::ofstream geometry_out_stream( path.c_str(), std::ios::binary );
|
||||
const unsigned compressed_edge_count = m_compressed_geometries.size()+1;
|
||||
BOOST_ASSERT( UINT_MAX != compressed_edge_count );
|
||||
const unsigned number_of_compressed_geometries = m_compressed_geometries.size()+1;
|
||||
BOOST_ASSERT( UINT_MAX != number_of_compressed_geometries );
|
||||
geometry_out_stream.write(
|
||||
(char*)&compressed_edge_count,
|
||||
(char*)&number_of_compressed_geometries,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "number_of_compressed_geometries: " << number_of_compressed_geometries;
|
||||
|
||||
// write indices array
|
||||
unsigned prefix_sum_of_list_indices = 0;
|
||||
for(unsigned i = 0; i < m_compressed_geometries.size(); ++i ) {
|
||||
const std::vector<unsigned> & current_vector = m_compressed_geometries[i];
|
||||
const unsigned unpacked_size = current_vector.size();
|
||||
BOOST_ASSERT( UINT_MAX != unpacked_size );
|
||||
geometry_out_stream.write(
|
||||
(char*)&prefix_sum_of_list_indices,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
const std::vector<CompressedNode> & current_vector = m_compressed_geometries.at(i);
|
||||
const unsigned unpacked_size = current_vector.size();
|
||||
BOOST_ASSERT( UINT_MAX != unpacked_size );
|
||||
prefix_sum_of_list_indices += unpacked_size;
|
||||
}
|
||||
// write sentinel element
|
||||
// sentinel element
|
||||
geometry_out_stream.write(
|
||||
(char*)&prefix_sum_of_list_indices,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
// number of geometry entries to follow, it is the (inclusive) prefix sum
|
||||
geometry_out_stream.write(
|
||||
(char*)&prefix_sum_of_list_indices,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "number of geometry nodes: " << prefix_sum_of_list_indices;
|
||||
unsigned control_sum = 0;
|
||||
// write compressed geometries
|
||||
for(unsigned i = 0; i < m_compressed_geometries.size(); ++i ) {
|
||||
const std::vector<unsigned> & current_vector = m_compressed_geometries[i];
|
||||
const std::vector<CompressedNode> & current_vector = m_compressed_geometries[i];
|
||||
const unsigned unpacked_size = current_vector.size();
|
||||
control_sum += unpacked_size;
|
||||
BOOST_ASSERT( UINT_MAX != unpacked_size );
|
||||
for(unsigned j = 0; j < unpacked_size; ++j) {
|
||||
BOOST_FOREACH(const CompressedNode current_node, current_vector ) {
|
||||
geometry_out_stream.write(
|
||||
(char*)&(current_vector[j]),
|
||||
sizeof(unsigned)
|
||||
(char*)&(current_node.first),
|
||||
sizeof(NodeID)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT( control_sum == prefix_sum_of_list_indices );
|
||||
// all done, let's close the resource
|
||||
geometry_out_stream.close();
|
||||
}
|
||||
@@ -118,8 +141,11 @@ void GeometryCompressor::SerializeInternalVector(
|
||||
void GeometryCompressor::CompressEdge(
|
||||
const EdgeID surviving_edge_id,
|
||||
const EdgeID removed_edge_id,
|
||||
const NodeID via_node_id
|
||||
const NodeID via_node_id,
|
||||
const EdgeWeight weight1//,
|
||||
// const EdgeWeight weight2
|
||||
) {
|
||||
|
||||
BOOST_ASSERT( UINT_MAX != surviving_edge_id );
|
||||
BOOST_ASSERT( UINT_MAX != removed_edge_id );
|
||||
BOOST_ASSERT( UINT_MAX != via_node_id );
|
||||
@@ -138,60 +164,80 @@ void GeometryCompressor::CompressEdge(
|
||||
// create a new entry in the map
|
||||
if( 0 == m_free_list.size() ) {
|
||||
// make sure there is a place to put the entries
|
||||
// SimpleLogger().Write() << "increased free list";
|
||||
IncreaseFreeList();
|
||||
}
|
||||
BOOST_ASSERT( !m_free_list.empty() );
|
||||
// SimpleLogger().Write() << "free list size: " << m_free_list.size();
|
||||
m_edge_id_to_list_index_map[surviving_edge_id] = m_free_list.back();
|
||||
m_free_list.pop_back();
|
||||
}
|
||||
const unsigned surving_list_id = m_edge_id_to_list_index_map[surviving_edge_id];
|
||||
BOOST_ASSERT( surving_list_id == GetPositionForID(surviving_edge_id));
|
||||
|
||||
// SimpleLogger().Write() << "surviving edge id " << surviving_edge_id << " is listed at " << surving_list_id;
|
||||
BOOST_ASSERT( surving_list_id < m_compressed_geometries.size() );
|
||||
|
||||
std::vector<NodeID> & compressed_id_list = m_compressed_geometries[surving_list_id];
|
||||
compressed_id_list.push_back(via_node_id);
|
||||
BOOST_ASSERT( 0 < compressed_id_list.size() );
|
||||
std::vector<CompressedNode> & surviving_geometry_list = m_compressed_geometries[surving_list_id];
|
||||
if( !surviving_geometry_list.empty() ) {
|
||||
BOOST_ASSERT( via_node_id != surviving_geometry_list.back().first );
|
||||
}
|
||||
surviving_geometry_list.push_back( std::make_pair(via_node_id, weight1) );
|
||||
BOOST_ASSERT( 0 < surviving_geometry_list.size() );
|
||||
BOOST_ASSERT( !surviving_geometry_list.empty() );
|
||||
|
||||
// Find any existing list for removed_edge_id
|
||||
typename boost::unordered_map<EdgeID, unsigned>::const_iterator map_iterator;
|
||||
map_iterator = m_edge_id_to_list_index_map.find(removed_edge_id);
|
||||
if( m_edge_id_to_list_index_map.end() != map_iterator ) {
|
||||
const unsigned index = map_iterator->second;
|
||||
BOOST_ASSERT( index < m_compressed_geometries.size() );
|
||||
typename boost::unordered_map<EdgeID, unsigned>::const_iterator remove_list_iterator;
|
||||
remove_list_iterator = m_edge_id_to_list_index_map.find(removed_edge_id);
|
||||
if( m_edge_id_to_list_index_map.end() != remove_list_iterator ) {
|
||||
const unsigned list_to_remove_index = remove_list_iterator->second;
|
||||
BOOST_ASSERT( list_to_remove_index == GetPositionForID(removed_edge_id));
|
||||
BOOST_ASSERT( list_to_remove_index < m_compressed_geometries.size() );
|
||||
|
||||
std::vector<CompressedNode> & remove_geometry_list = m_compressed_geometries[list_to_remove_index];
|
||||
// found an existing list, append it to the list of surviving_edge_id
|
||||
compressed_id_list.insert(
|
||||
compressed_id_list.end(),
|
||||
m_compressed_geometries[index].begin(),
|
||||
m_compressed_geometries[index].end()
|
||||
surviving_geometry_list.insert(
|
||||
surviving_geometry_list.end(),
|
||||
remove_geometry_list.begin(),
|
||||
remove_geometry_list.end()
|
||||
);
|
||||
|
||||
//remove the list of removed_edge_id
|
||||
m_edge_id_to_list_index_map.erase(map_iterator);
|
||||
m_edge_id_to_list_index_map.erase(remove_list_iterator);
|
||||
BOOST_ASSERT( m_edge_id_to_list_index_map.end() == m_edge_id_to_list_index_map.find(removed_edge_id) );
|
||||
m_compressed_geometries[index].clear();
|
||||
BOOST_ASSERT( 0 == m_compressed_geometries[index].size() );
|
||||
m_free_list.push_back(index);
|
||||
BOOST_ASSERT( index == m_free_list.back() );
|
||||
remove_geometry_list.clear();
|
||||
BOOST_ASSERT( 0 == remove_geometry_list.size() );
|
||||
m_free_list.push_back(list_to_remove_index);
|
||||
BOOST_ASSERT( list_to_remove_index == m_free_list.back() );
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryCompressor::PrintStatistics() const {
|
||||
unsigned removed_edge_count = 0;
|
||||
const unsigned surviving_edge_count = m_compressed_geometries.size()-m_free_list.size();
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
const unsigned compressed_edges = m_compressed_geometries.size();
|
||||
|
||||
BOOST_ASSERT( m_compressed_geometries.size() + m_free_list.size() > 0 );
|
||||
|
||||
unsigned long longest_chain_length = 0;
|
||||
BOOST_FOREACH(const std::vector<unsigned> & current_vector, m_compressed_geometries) {
|
||||
removed_edge_count += current_vector.size();
|
||||
BOOST_FOREACH(const std::vector<CompressedNode> & current_vector, m_compressed_geometries) {
|
||||
number_of_compressed_geometries += current_vector.size();
|
||||
longest_chain_length = std::max(longest_chain_length, current_vector.size());
|
||||
}
|
||||
BOOST_ASSERT(0 == surviving_edge_count % 2);
|
||||
BOOST_ASSERT(0 == compressed_edges % 2);
|
||||
SimpleLogger().Write() <<
|
||||
"surviving edges: " << surviving_edge_count <<
|
||||
", compressed edges: " << removed_edge_count <<
|
||||
"compressed edges: " << compressed_edges <<
|
||||
", compressed geometries: " << number_of_compressed_geometries <<
|
||||
", longest chain length: " << longest_chain_length <<
|
||||
", comp ratio: " << ((float)surviving_edge_count/std::max(removed_edge_count, 1u) ) <<
|
||||
", avg: chain length: " << (float)removed_edge_count/std::max(1u, surviving_edge_count);
|
||||
", cmpr ratio: " << ((float)compressed_edges/std::max(number_of_compressed_geometries, 1u) ) <<
|
||||
", avg chain length: " << (float)number_of_compressed_geometries/std::max(1u, compressed_edges);
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"No bytes: " << 4*surviving_edge_count + removed_edge_count*4;
|
||||
"No bytes: " << 4*compressed_edges + number_of_compressed_geometries*4 +8;
|
||||
}
|
||||
|
||||
const std::vector<GeometryCompressor::CompressedNode> & GeometryCompressor::GetBucketReference(
|
||||
const EdgeID edge_id
|
||||
) const {
|
||||
const unsigned index = m_edge_id_to_list_index_map.at( edge_id );
|
||||
return m_compressed_geometries.at( index );
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
@@ -37,23 +38,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
class GeometryCompressor {
|
||||
public:
|
||||
typedef std::pair<NodeID, EdgeWeight> CompressedNode;
|
||||
|
||||
GeometryCompressor();
|
||||
void CompressEdge(
|
||||
const EdgeID first_edge_id,
|
||||
const EdgeID second_edge_id,
|
||||
const NodeID via_node_id
|
||||
const NodeID via_node_id,
|
||||
const EdgeWeight weight1//,
|
||||
// const EdgeWeight weight2
|
||||
);
|
||||
|
||||
void AddLastViaNodeIDToCompressedEdge(
|
||||
const EdgeID edge_id,
|
||||
const NodeID node_id,
|
||||
const EdgeWeight weight
|
||||
);
|
||||
bool HasEntryForID(const EdgeID edge_id) const;
|
||||
void PrintStatistics() const;
|
||||
bool HasEntryForID(const EdgeID edge_id);
|
||||
void AddNodeIDToCompressedEdge(const EdgeID edge_id, const NodeID node_id);
|
||||
unsigned GetPositionForID(const EdgeID edge_id);
|
||||
void SerializeInternalVector(const std::string & path) const;
|
||||
unsigned GetPositionForID(const EdgeID edge_id) const;
|
||||
const std::vector<GeometryCompressor::CompressedNode> & GetBucketReference(const EdgeID edge_id) const;
|
||||
|
||||
private:
|
||||
|
||||
void IncreaseFreeList();
|
||||
|
||||
std::vector<std::vector<NodeID> > m_compressed_geometries;
|
||||
std::vector<std::vector<CompressedNode> > m_compressed_geometries;
|
||||
std::vector<unsigned> m_free_list;
|
||||
boost::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user