osrm-backend/Contractor/EdgeBasedGraphFactory.cpp

776 lines
30 KiB
C++
Raw Normal View History

2011-10-10 11:52:47 -04:00
/*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
2011-10-10 11:52:47 -04:00
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
2011-10-10 11:52:47 -04:00
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2011-10-10 11:52:47 -04:00
#include "EdgeBasedGraphFactory.h"
2013-12-13 17:26:57 -05:00
#include "../Util/ComputeAngle.h"
#include "../DataStructures/BFSComponentExplorer.h"
2013-12-13 17:26:57 -05:00
#include <boost/assert.hpp>
#include <boost/foreach.hpp>
2014-01-04 06:10:22 -05:00
#include <fstream>
#include <iomanip>
#include <numeric>
2013-11-29 12:49:02 -05:00
2013-08-14 05:59:46 -04:00
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
std::unique_ptr<RestrictionMap> restriction_map,
2014-05-08 17:07:16 -04:00
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
std::vector<NodeInfo> &m_node_info_list,
SpeedProfileProperties &speed_profile)
: speed_profile(speed_profile),
m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
m_node_info_list(m_node_info_list), m_node_based_graph(node_based_graph),
m_restriction_map(std::move(restriction_map)), max_id(0)
2013-11-29 13:00:00 -05:00
{
2014-05-06 17:52:04 -04:00
// insert into unordered sets for fast lookup
2014-05-08 17:07:16 -04:00
m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
2014-05-08 17:07:16 -04:00
m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
2014-01-04 06:10:22 -05:00
}
2014-05-08 17:07:16 -04:00
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
{
BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
2013-08-14 12:43:01 -04:00
m_edge_based_edge_list.swap(output_edge_list);
}
2014-05-08 17:07:16 -04:00
void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
{
#ifndef NDEBUG
2014-05-08 17:07:16 -04:00
BOOST_FOREACH (const EdgeBasedNode &node, m_edge_based_node_list)
{
2014-02-26 09:55:04 -05:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
2011-12-13 04:12:41 -05:00
}
#endif
2013-08-14 12:43:01 -04:00
nodes.swap(m_edge_based_node_list);
}
2014-05-08 17:07:16 -04:00
void EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeIterator u,
NodeIterator v,
EdgeIterator e1,
bool belongs_to_tiny_cc)
{
2014-02-11 05:42:24 -05:00
// merge edges together into one EdgeBasedNode
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(v != SPECIAL_NODEID);
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
2014-02-11 05:42:24 -05:00
2014-04-23 11:03:26 -04:00
#ifndef NDEBUG
2014-02-11 05:42:24 -05:00
// find forward edge id and
2014-02-28 11:14:38 -05:00
const EdgeID e1b = m_node_based_graph->FindEdge(u, v);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(e1 == e1b);
2014-04-23 11:03:26 -04:00
#endif
2014-04-24 12:13:50 -04:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(e1);
2014-02-11 05:42:24 -05:00
// find reverse edge id and
const EdgeID e2 = m_node_based_graph->FindEdge(v, u);
2014-02-27 13:49:53 -05:00
#ifndef NDEBUG
2014-05-08 17:07:16 -04:00
if (e2 == m_node_based_graph->EndEdges(v))
{
2014-02-27 13:49:53 -05:00
SimpleLogger().Write(logWARNING) << "Did not find edge (" << v << "," << u << ")";
}
#endif
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(e2 != SPECIAL_EDGEID);
BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(v));
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
{
2014-02-27 13:49:53 -05:00
return;
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e1) ==
m_geometry_compressor.HasEntryForID(e2));
if (m_geometry_compressor.HasEntryForID(e1))
{
2014-02-28 11:14:38 -05:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e2));
2014-02-11 05:42:24 -05:00
// reconstruct geometry and put in each individual edge with its offset
2014-05-08 17:07:16 -04:00
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());
2014-02-27 13:49:53 -05:00
// reconstruct bidirectional edge with individual weights and put each into the NN index
std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
2014-02-27 13:49:53 -05:00
// quick'n'dirty prefix sum as std::partial_sum needs addtional casts
2014-04-10 16:44:17 -04:00
// TODO: move to lambda function with C++11
int temp_sum = 0;
for (unsigned i = 0; i < forward_geometry.size(); ++i)
{
forward_dist_prefix_sum[i] = temp_sum;
temp_sum += forward_geometry[i].second;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(forward_data.distance >= temp_sum);
}
temp_sum = 0;
2014-05-08 17:07:16 -04:00
for (unsigned i = 0; i < reverse_geometry.size(); ++i)
{
temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(reverse_data.distance >= temp_sum);
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
const unsigned geometry_size = forward_geometry.size();
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(geometry_size > 1);
2014-02-26 09:55:04 -05:00
NodeID current_edge_start_coordinate_id = u;
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
{
max_id = std::max(forward_data.edgeBasedNodeID, max_id);
}
if (SPECIAL_NODEID != reverse_data.edgeBasedNodeID)
{
max_id = std::max(reverse_data.edgeBasedNodeID, max_id);
}
// traverse arrays from start and end respectively
2014-05-08 17:07:16 -04:00
for (unsigned i = 0; i < geometry_size; ++i)
{
BOOST_ASSERT(current_edge_start_coordinate_id ==
reverse_geometry[geometry_size - 1 - i].first);
2014-02-26 09:55:04 -05:00
const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_start_coordinate_id);
2014-02-27 13:49:53 -05:00
// build edges
m_edge_based_node_list.emplace_back(
2014-05-08 17:07:16 -04:00
EdgeBasedNode(forward_data.edgeBasedNodeID,
reverse_data.edgeBasedNodeID,
current_edge_start_coordinate_id,
current_edge_target_coordinate_id,
forward_data.nameID,
forward_geometry[i].second,
reverse_geometry[i].second,
forward_dist_prefix_sum[i],
reverse_dist_prefix_sum[i],
m_geometry_compressor.GetPositionForID(e1),
i,
belongs_to_tiny_cc));
2014-02-26 09:55:04 -05:00
current_edge_start_coordinate_id = current_edge_target_coordinate_id;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(u != m_edge_based_node_list.back().u ||
v != m_edge_based_node_list.back().v);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(u != m_edge_based_node_list.back().v ||
v != m_edge_based_node_list.back().u);
2014-02-26 09:55:04 -05:00
}
2014-02-28 11:14:38 -05:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(current_edge_start_coordinate_id == v);
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
}
else
{
BOOST_ASSERT(!m_geometry_compressor.HasEntryForID(e2));
2014-05-08 17:07:16 -04:00
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
{
BOOST_ASSERT(forward_data.forward);
}
2014-05-08 17:07:16 -04:00
if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
{
BOOST_ASSERT(reverse_data.forward);
}
2014-05-08 17:07:16 -04:00
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID)
{
BOOST_ASSERT(!forward_data.forward);
}
2014-05-08 17:07:16 -04:00
if (reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
{
BOOST_ASSERT(!reverse_data.forward);
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
m_edge_based_node_list.emplace_back(EdgeBasedNode(forward_data.edgeBasedNodeID,
reverse_data.edgeBasedNodeID,
u,
v,
forward_data.nameID,
forward_data.distance,
reverse_data.distance,
0,
0,
SPECIAL_EDGEID,
0,
belongs_to_tiny_cc));
BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
}
}
void EdgeBasedGraphFactory::FlushVectorToStream(
2014-05-08 17:07:16 -04:00
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
{
edge_data_file.write((char *)&(original_edge_data_vector[0]),
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
original_edge_data_vector.clear();
}
2014-05-08 17:07:16 -04:00
void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
const std::string &geometry_filename,
lua_State *lua_state)
{
CompressGeometry();
RenumberEdges();
GenerateEdgeExpandedNodes();
GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state);
2014-05-08 17:07:16 -04:00
m_geometry_compressor.SerializeInternalVector(geometry_filename);
}
void EdgeBasedGraphFactory::CompressGeometry()
{
2014-01-04 06:10:22 -05:00
SimpleLogger().Write() << "Removing graph geometry while preserving topology";
const unsigned original_number_of_nodes = m_node_based_graph->GetNumberOfNodes();
const unsigned original_number_of_edges = m_node_based_graph->GetNumberOfEdges();
2014-01-04 06:10:22 -05:00
Percent p(original_number_of_nodes);
unsigned removed_node_count = 0;
2014-05-08 17:07:16 -04:00
for (NodeID v = 0; v < original_number_of_nodes; ++v)
{
2014-01-04 06:10:22 -05:00
p.printStatus(v);
2013-11-29 12:49:02 -05:00
2014-01-04 06:10:22 -05:00
// only contract degree 2 vertices
2014-05-08 17:07:16 -04:00
if (2 != m_node_based_graph->GetOutDegree(v))
{
2014-01-04 06:10:22 -05:00
continue;
}
// don't contract barrier node
2014-05-08 17:07:16 -04:00
if (m_barrier_nodes.end() != m_barrier_nodes.find(v))
{
2014-01-04 06:10:22 -05:00
continue;
}
2014-05-08 17:07:16 -04:00
const bool reverse_edge_order =
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
2014-01-04 06:10:22 -05:00
const EdgeIterator forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
2014-01-04 06:10:22 -05:00
const EdgeIterator reverse_e2 = m_node_based_graph->BeginEdges(v) + 1 - reverse_edge_order;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
2014-01-04 06:10:22 -05:00
2014-05-08 17:07:16 -04:00
const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
2014-01-04 06:10:22 -05:00
const NodeIterator w = m_node_based_graph->GetTarget(forward_e2);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_NODEID != w);
BOOST_ASSERT(v != w);
2014-01-04 06:10:22 -05:00
const NodeIterator u = m_node_based_graph->GetTarget(reverse_e2);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_NODEID != u);
BOOST_ASSERT(u != v);
2014-01-04 06:10:22 -05:00
const EdgeIterator forward_e1 = m_node_based_graph->FindEdge(u, v);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_node_based_graph->EndEdges(u) != forward_e1);
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
BOOST_ASSERT(v == m_node_based_graph->GetTarget(forward_e1));
2014-01-04 06:10:22 -05:00
const EdgeIterator reverse_e1 = m_node_based_graph->FindEdge(w, v);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
BOOST_ASSERT(v == m_node_based_graph->GetTarget(reverse_e1));
2014-01-04 06:10:22 -05:00
2014-05-08 17:07:16 -04:00
const EdgeData &fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
const EdgeData &rev_edge_data1 = m_node_based_graph->GetEdgeData(reverse_e1);
2014-01-04 06:10:22 -05:00
2014-05-08 17:07:16 -04:00
if ((m_node_based_graph->FindEdge(u, w) != m_node_based_graph->EndEdges(u)) ||
(m_node_based_graph->FindEdge(w, u) != m_node_based_graph->EndEdges(w)))
{
2014-01-04 06:10:22 -05:00
continue;
}
2014-05-08 17:07:16 -04:00
if ( // TODO: rename to IsCompatibleTo
fwd_edge_data1.IsEqualTo(fwd_edge_data2) && rev_edge_data1.IsEqualTo(rev_edge_data2))
{
// Get distances before graph is modified
const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
const int forward_weight2 = m_node_based_graph->GetEdgeData(forward_e2).distance;
2014-01-04 06:10:22 -05:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(0 != forward_weight1);
BOOST_ASSERT(0 != forward_weight2);
const int reverse_weight1 = m_node_based_graph->GetEdgeData(reverse_e1).distance;
const int reverse_weight2 = m_node_based_graph->GetEdgeData(reverse_e2).distance;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != forward_weight2);
2014-02-11 05:42:24 -05:00
2014-05-08 17:07:16 -04:00
const bool add_traffic_signal_penalty =
(m_traffic_lights.find(v) != m_traffic_lights.end());
2014-03-21 14:19:33 -04:00
2014-01-04 06:10:22 -05:00
// 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;
2014-03-21 14:19:33 -04:00
if (add_traffic_signal_penalty)
{
2014-05-08 17:07:16 -04:00
m_node_based_graph->GetEdgeData(forward_e1).distance +=
speed_profile.trafficSignalPenalty;
m_node_based_graph->GetEdgeData(reverse_e1).distance +=
speed_profile.trafficSignalPenalty;
2014-03-21 14:19:33 -04:00
}
2014-01-04 06:10:22 -05:00
// extend e1's to targets of e2's
m_node_based_graph->SetTarget(forward_e1, w);
m_node_based_graph->SetTarget(reverse_e1, u);
2014-01-04 06:10:22 -05:00
// remove e2's (if bidir, otherwise only one)
m_node_based_graph->DeleteEdge(v, forward_e2);
m_node_based_graph->DeleteEdge(v, reverse_e2);
// update any involved turn restrictions
2014-05-08 17:07:16 -04:00
m_restriction_map->FixupStartingTurnRestriction(u, v, w);
m_restriction_map->FixupArrivingTurnRestriction(u, v, w);
2014-01-04 06:10:22 -05:00
2014-05-08 17:07:16 -04:00
m_restriction_map->FixupStartingTurnRestriction(w, v, u);
m_restriction_map->FixupArrivingTurnRestriction(w, v, u);
2014-01-04 06:10:22 -05:00
2014-02-11 05:42:24 -05:00
// store compressed geometry in container
m_geometry_compressor.CompressEdge(
forward_e1,
forward_e2,
v,
w,
2014-05-08 17:07:16 -04:00
forward_weight1 +
(add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0),
forward_weight2);
2014-02-11 05:42:24 -05:00
m_geometry_compressor.CompressEdge(
reverse_e1,
reverse_e2,
v,
u,
2014-05-08 17:07:16 -04:00
reverse_weight1,
reverse_weight2 +
(add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0));
2014-01-04 06:10:22 -05:00
++removed_node_count;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
m_node_based_graph->GetEdgeData(reverse_e1).nameID);
2014-01-04 06:10:22 -05:00
}
}
SimpleLogger().Write() << "removed " << removed_node_count << " nodes";
m_geometry_compressor.PrintStatistics();
unsigned new_node_count = 0;
unsigned new_edge_count = 0;
2014-05-08 17:07:16 -04:00
for (unsigned i = 0; i < m_node_based_graph->GetNumberOfNodes(); ++i)
{
if (m_node_based_graph->GetOutDegree(i) > 0)
{
2014-01-04 06:10:22 -05:00
++new_node_count;
new_edge_count += (m_node_based_graph->EndEdges(i) - m_node_based_graph->BeginEdges(i));
}
}
SimpleLogger().Write() << "new nodes: " << new_node_count << ", edges " << new_edge_count;
2014-05-08 17:07:16 -04:00
SimpleLogger().Write() << "Node compression ratio: "
<< new_node_count / (double)original_number_of_nodes;
SimpleLogger().Write() << "Edge compression ratio: "
<< new_edge_count / (double)original_number_of_edges;
}
2014-01-04 06:10:22 -05:00
/**
* Writes the id of the edge in the edge expanded graph (into the egde in the node based graph)
*/
void EdgeBasedGraphFactory::RenumberEdges()
{
// renumber edge based node IDs
2014-02-11 05:42:24 -05:00
unsigned numbered_edges_count = 0;
2014-05-08 17:07:16 -04:00
for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
++current_node)
{
for (EdgeIterator current_edge = m_node_based_graph->BeginEdges(current_node);
current_edge < m_node_based_graph->EndEdges(current_node);
++current_edge)
{
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
if (!edge_data.forward)
{
2014-01-04 06:10:22 -05:00
continue;
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
2014-02-11 05:42:24 -05:00
edge_data.edgeBasedNodeID = numbered_edges_count;
++numbered_edges_count;
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edgeBasedNodeID);
2014-01-04 06:10:22 -05:00
}
}
m_number_of_edge_based_nodes = numbered_edges_count;
}
2012-04-20 12:34:49 -04:00
/**
* Creates the nodes in the edge expanded graph from edges in the node-based graph.
*/
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
{
SimpleLogger().Write() << "Identifying components of the road network";
2014-05-08 17:07:16 -04:00
// Run a BFS on the undirected graph and identify small components
BFSComponentExplorer<NodeBasedDynamicGraph> component_explorer(
2014-05-08 17:07:16 -04:00
*m_node_based_graph, *m_restriction_map, m_barrier_nodes);
component_explorer.run();
2013-08-14 12:43:01 -04:00
2014-05-08 17:07:16 -04:00
SimpleLogger().Write() << "identified: " << component_explorer.getNumberOfComponents()
<< " many components";
2014-02-27 13:49:53 -05:00
SimpleLogger().Write() << "generating edge-expanded nodes";
2012-07-13 11:01:21 -04:00
Percent p(m_node_based_graph->GetNumberOfNodes());
2014-02-11 05:42:24 -05:00
2014-05-08 17:07:16 -04:00
// 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 != SPECIAL_NODEID);
BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
2013-08-16 05:08:07 -04:00
p.printIncrement();
2014-05-08 17:07:16 -04:00
for (EdgeID e1 = m_node_based_graph->BeginEdges(u),
last_edge = m_node_based_graph->EndEdges(u);
e1 < last_edge;
++e1)
{
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
{
2014-02-27 13:49:53 -05:00
// continue;
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
2014-02-27 13:49:53 -05:00
const NodeID v = m_node_based_graph->GetTarget(e1);
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_NODEID != v);
2014-02-11 05:42:24 -05:00
// pick only every other edge
2014-05-08 17:07:16 -04:00
if (u > v)
{
2014-02-11 05:42:24 -05:00
continue;
}
2014-02-27 13:49:53 -05:00
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(u < v);
BOOST_ASSERT(edge_data.type != SHRT_MAX);
2013-08-14 12:43:01 -04:00
2014-05-08 17:07:16 -04:00
// 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_explorer.getComponentSize(u),
component_explorer.getComponentSize(v));
2013-08-14 12:43:01 -04:00
2014-05-08 17:07:16 -04:00
const bool component_is_tiny = (size_of_component < 1000);
InsertEdgeBasedNode(u, v, e1, component_is_tiny);
}
}
2014-05-08 17:07:16 -04:00
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
<< " nodes in edge-expanded graph";
}
/**
* Actually it also generates OriginalEdgeData and serializes them...
*/
2014-05-08 17:07:16 -04:00
void
EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
lua_State *lua_state)
{
SimpleLogger().Write() << "generating edge-expanded edges";
2013-08-16 05:08:07 -04:00
unsigned node_based_edge_counter = 0;
2014-05-08 17:07:16 -04:00
unsigned original_edges_counter = 0;
2014-05-08 17:07:16 -04:00
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
2014-05-08 17:07:16 -04:00
// writes a dummy value that is updated later
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
std::vector<OriginalEdgeData> original_edge_data_vector;
2014-05-08 17:07:16 -04:00
original_edge_data_vector.reserve(1024 * 1024);
2014-05-08 17:07:16 -04:00
// Loop over all turns and generate new set of edges.
// Three nested loop look super-linear, but we are dealing with a (kind of)
// linear number of turns only.
2014-01-04 06:10:22 -05:00
unsigned restricted_turns_counter = 0;
unsigned skipped_uturns_counter = 0;
unsigned skipped_barrier_turns_counter = 0;
2014-02-11 05:42:24 -05:00
unsigned compressed = 0;
Percent p(m_node_based_graph->GetNumberOfNodes());
2014-04-28 13:37:42 -04:00
for (NodeIterator u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
{
2014-05-08 17:07:16 -04:00
for (EdgeIterator e1 = m_node_based_graph->BeginEdges(u),
last_edge_u = m_node_based_graph->EndEdges(u);
e1 < last_edge_u;
++e1)
2014-04-28 13:37:42 -04:00
{
2014-05-08 17:07:16 -04:00
if (!m_node_based_graph->GetEdgeData(e1).forward)
{
2014-02-11 05:42:24 -05:00
continue;
}
2013-11-29 13:00:00 -05:00
++node_based_edge_counter;
2013-11-28 09:26:13 -05:00
const NodeIterator v = m_node_based_graph->GetTarget(e1);
2014-05-08 17:07:16 -04:00
const NodeID to_node_of_only_restriction =
m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
for (EdgeIterator e2 = m_node_based_graph->BeginEdges(v),
last_edge_v = m_node_based_graph->EndEdges(v);
e2 < last_edge_v;
++e2)
{
2014-04-28 13:37:42 -04:00
if (!m_node_based_graph->GetEdgeData(e2).forward)
{
2014-02-11 05:42:24 -05:00
continue;
}
2013-08-14 12:43:01 -04:00
const NodeIterator w = m_node_based_graph->GetTarget(e2);
2014-02-27 13:49:53 -05:00
2014-05-08 17:07:16 -04:00
if ((to_node_of_only_restriction != SPECIAL_NODEID) &&
(w != to_node_of_only_restriction))
2014-04-28 13:37:42 -04:00
{
2014-05-08 17:07:16 -04:00
// We are at an only_-restriction but not at the right turn.
2014-01-04 06:10:22 -05:00
++restricted_turns_counter;
2011-12-05 08:45:45 -05:00
continue;
}
2013-01-27 08:16:32 -05:00
2014-04-28 13:37:42 -04:00
if (is_barrier_node)
{
if (u != w)
{
2014-01-04 06:10:22 -05:00
++skipped_barrier_turns_counter;
2013-12-11 15:36:32 -05:00
continue;
}
2014-04-28 13:37:42 -04:00
}
else
{
if ((u == w) && (m_node_based_graph->GetOutDegree(v) > 1))
{
2014-01-04 06:10:22 -05:00
++skipped_uturns_counter;
2013-12-11 15:36:32 -05:00
continue;
}
}
2014-05-08 17:07:16 -04:00
// only add an edge if turn is not a U-turn except when it is
// at the end of a dead-end street
if (m_restriction_map->CheckIfTurnIsRestricted(u, v, w) &&
(to_node_of_only_restriction == SPECIAL_NODEID) &&
(w != to_node_of_only_restriction))
2014-04-28 13:37:42 -04:00
{
2014-01-04 06:10:22 -05:00
++restricted_turns_counter;
2013-11-28 09:26:13 -05:00
continue;
}
2013-11-28 09:26:13 -05:00
2014-05-08 17:07:16 -04:00
// only add an edge if turn is not prohibited
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
2014-03-21 14:19:33 -04:00
BOOST_ASSERT(edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID);
BOOST_ASSERT(edge_data1.forward);
BOOST_ASSERT(edge_data2.forward);
2013-11-28 09:26:13 -05:00
// the following is the core of the loop.
2013-11-28 09:26:13 -05:00
unsigned distance = edge_data1.distance;
2014-04-28 13:37:42 -04:00
if (m_traffic_lights.find(v) != m_traffic_lights.end())
{
2013-11-28 09:26:13 -05:00
distance += speed_profile.trafficSignalPenalty;
}
2014-01-27 06:55:17 -05:00
const int turn_penalty = GetTurnPenalty(u, v, w, lua_state);
2014-02-11 05:42:24 -05:00
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w);
if (turn_instruction == TurnInstruction::UTurn)
2014-04-28 13:37:42 -04:00
{
2013-11-28 09:26:13 -05:00
distance += speed_profile.uTurnPenalty;
}
distance += turn_penalty;
2013-11-28 09:26:13 -05:00
2014-01-04 06:10:22 -05:00
const bool edge_is_compressed = m_geometry_compressor.HasEntryForID(e1);
2014-02-27 13:49:53 -05:00
2014-04-28 13:37:42 -04:00
if (edge_is_compressed)
{
2014-02-11 05:42:24 -05:00
++compressed;
2014-01-04 06:10:22 -05:00
}
2014-05-08 17:07:16 -04:00
original_edge_data_vector.push_back(OriginalEdgeData(
(edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
edge_data1.nameID,
turn_instruction,
edge_is_compressed));
2014-02-27 13:49:53 -05:00
2013-11-29 13:00:00 -05:00
++original_edges_counter;
2013-11-28 09:26:13 -05:00
2014-05-08 17:07:16 -04:00
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
2014-04-28 13:37:42 -04:00
{
FlushVectorToStream(edge_data_file, original_edge_data_vector);
2013-11-28 09:26:13 -05:00
}
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edgeBasedNodeID);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edgeBasedNodeID);
m_edge_based_edge_list.emplace_back(EdgeBasedEdge(edge_data1.edgeBasedNodeID,
edge_data2.edgeBasedNodeID,
m_edge_based_edge_list.size(),
distance,
true,
false));
2011-10-10 11:52:47 -04:00
}
}
p.printIncrement();
2011-10-10 11:52:47 -04:00
}
2014-05-08 17:07:16 -04:00
FlushVectorToStream(edge_data_file, original_edge_data_vector);
2014-05-08 17:07:16 -04:00
edge_data_file.seekp(std::ios::beg);
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
2013-08-14 12:43:01 -04:00
edge_data_file.close();
2014-04-10 16:44:17 -04:00
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
SimpleLogger().Write() << "Edge-expanded graph ...";
SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
2014-05-08 17:07:16 -04:00
SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
"defined by "
<< m_restriction_map->size() << " restrictions";
SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
}
2014-05-08 17:07:16 -04:00
int EdgeBasedGraphFactory::GetTurnPenalty(const NodeID u,
const NodeID v,
const NodeID w,
lua_State *lua_state) const
{
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
2014-05-08 17:07:16 -04:00
if (speed_profile.has_turn_penalty_function)
{
try
{
// call lua profile to compute turn penalty
return luabind::call_function<int>(lua_state, "turn_function", 180. - angle);
}
catch (const luabind::error &er)
{
2013-08-13 12:33:20 -04:00
SimpleLogger().Write(logWARNING) << er.what();
2013-02-23 02:33:33 -05:00
}
}
2013-08-13 12:33:20 -04:00
return 0;
}
2014-05-08 17:07:16 -04:00
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w)
const
{
if (u == w)
{
return TurnInstruction::UTurn;
2012-02-29 14:02:04 -05:00
}
const EdgeIterator edge1 = m_node_based_graph->FindEdge(u, v);
const EdgeIterator edge2 = m_node_based_graph->FindEdge(v, w);
2011-11-17 12:04:49 -05:00
2014-05-08 17:07:16 -04:00
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
2011-11-17 12:04:49 -05:00
2014-05-08 17:07:16 -04:00
if (!data1.contraFlow && data2.contraFlow)
{
return TurnInstruction::EnterAgainstAllowedDirection;
}
2014-05-08 17:07:16 -04:00
if (data1.contraFlow && !data2.contraFlow)
{
return TurnInstruction::LeaveAgainstAllowedDirection;
}
2014-05-08 17:07:16 -04:00
// roundabouts need to be handled explicitely
if (data1.roundabout && data2.roundabout)
{
// Is a turn possible? If yes, we stay on the roundabout!
if (1 == m_node_based_graph->GetOutDegree(v))
{
// No turn possible.
return TurnInstruction::NoTurn;
2011-11-23 12:40:54 -05:00
}
return TurnInstruction::StayOnRoundAbout;
2011-11-23 12:40:54 -05:00
}
2014-05-08 17:07:16 -04:00
// Does turn start or end on roundabout?
if (data1.roundabout || data2.roundabout)
{
// We are entering the roundabout
if ((!data1.roundabout) && data2.roundabout)
{
return TurnInstruction::EnterRoundAbout;
2013-02-27 13:47:04 -05:00
}
2014-05-08 17:07:16 -04:00
// We are leaving the roundabout
if (data1.roundabout && (!data2.roundabout))
{
return TurnInstruction::LeaveRoundAbout;
2013-02-27 13:47:04 -05:00
}
2011-11-17 12:04:49 -05:00
}
2014-05-08 17:07:16 -04:00
// If street names stay the same and if we are certain that it is not a
// a segment of a roundabout, we skip it.
if (data1.nameID == data2.nameID)
{
// TODO: Here we should also do a small graph exploration to check for
2013-08-14 12:43:01 -04:00
// more complex situations
2014-05-08 17:07:16 -04:00
if (0 != data1.nameID)
{
return TurnInstruction::NoTurn;
2014-05-08 17:07:16 -04:00
}
else if (m_node_based_graph->GetOutDegree(v) <= 2)
{
return TurnInstruction::NoTurn;
2013-08-14 12:43:01 -04:00
}
}
2011-11-23 12:40:54 -05:00
2014-05-08 17:07:16 -04:00
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
2011-11-17 12:04:49 -05:00
}
2014-05-08 17:07:16 -04:00
unsigned EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
{
2014-02-11 05:42:24 -05:00
return m_number_of_edge_based_nodes;
2011-10-10 11:52:47 -04:00
}