Move files in src/ include/

This commit is contained in:
Patrick Niklaus
2016-01-02 13:55:06 +01:00
parent 758d402305
commit bfc6c9b89d
184 changed files with 0 additions and 608 deletions
+240
View File
@@ -0,0 +1,240 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "compressed_edge_container.hpp"
#include "../util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <limits>
#include <string>
#include <iostream>
CompressedEdgeContainer::CompressedEdgeContainer()
{
m_free_list.reserve(100);
IncreaseFreeList();
}
void CompressedEdgeContainer::IncreaseFreeList()
{
m_compressed_geometries.resize(m_compressed_geometries.size() + 100);
for (unsigned i = 100; i > 0; --i)
{
m_free_list.emplace_back(free_list_maximum);
++free_list_maximum;
}
}
bool CompressedEdgeContainer::HasEntryForID(const EdgeID edge_id) const
{
auto iter = m_edge_id_to_list_index_map.find(edge_id);
return iter != m_edge_id_to_list_index_map.end();
}
unsigned CompressedEdgeContainer::GetPositionForID(const EdgeID edge_id) const
{
auto 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 CompressedEdgeContainer::SerializeInternalVector(const std::string &path) const
{
boost::filesystem::fstream geometry_out_stream(path, std::ios::binary | std::ios::out);
const unsigned compressed_geometries = m_compressed_geometries.size() + 1;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != compressed_geometries);
geometry_out_stream.write((char *)&compressed_geometries, sizeof(unsigned));
// write indices array
unsigned prefix_sum_of_list_indices = 0;
for (const auto &elem : m_compressed_geometries)
{
geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
const std::vector<CompressedNode> &current_vector = elem;
const unsigned unpacked_size = current_vector.size();
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
prefix_sum_of_list_indices += unpacked_size;
}
// 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));
unsigned control_sum = 0;
// write compressed geometries
for (auto &elem : m_compressed_geometries)
{
const std::vector<CompressedNode> &current_vector = elem;
const unsigned unpacked_size = current_vector.size();
control_sum += unpacked_size;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
for (const CompressedNode current_node : current_vector)
{
geometry_out_stream.write((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();
}
void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
const EdgeID edge_id_2,
const NodeID via_node_id,
const NodeID target_node_id,
const EdgeWeight weight1,
const EdgeWeight weight2)
{
// remove super-trivial geometries
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_2);
BOOST_ASSERT(SPECIAL_NODEID != via_node_id);
BOOST_ASSERT(SPECIAL_NODEID != target_node_id);
BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight1);
BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight2);
// append list of removed edge_id plus via node to surviving edge id:
// <surv_1, .. , surv_n, via_node_id, rem_1, .. rem_n
//
// General scheme:
// 1. append via node id to list of edge_id_1
// 2. find list for edge_id_2, if yes add all elements and delete it
// Add via node id. List is created if it does not exist
if (!HasEntryForID(edge_id_1))
{
// create a new entry in the map
if (0 == m_free_list.size())
{
// make sure there is a place to put the entries
IncreaseFreeList();
}
BOOST_ASSERT(!m_free_list.empty());
m_edge_id_to_list_index_map[edge_id_1] = m_free_list.back();
m_free_list.pop_back();
}
// find bucket index
const auto iter = m_edge_id_to_list_index_map.find(edge_id_1);
BOOST_ASSERT(iter != m_edge_id_to_list_index_map.end());
const unsigned edge_bucket_id1 = iter->second;
BOOST_ASSERT(edge_bucket_id1 == GetPositionForID(edge_id_1));
BOOST_ASSERT(edge_bucket_id1 < m_compressed_geometries.size());
std::vector<CompressedNode> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
// note we don't save the start coordinate: it is implicitly given by edge 1
// weight1 is the distance to the (currently) last coordinate in the bucket
if (edge_bucket_list1.empty())
{
edge_bucket_list1.emplace_back(via_node_id, weight1);
}
BOOST_ASSERT(0 < edge_bucket_list1.size());
BOOST_ASSERT(!edge_bucket_list1.empty());
if (HasEntryForID(edge_id_2))
{
// second edge is not atomic anymore
const unsigned list_to_remove_index = GetPositionForID(edge_id_2);
BOOST_ASSERT(list_to_remove_index < m_compressed_geometries.size());
std::vector<CompressedNode> &edge_bucket_list2 =
m_compressed_geometries[list_to_remove_index];
// found an existing list, append it to the list of edge_id_1
edge_bucket_list1.insert(edge_bucket_list1.end(), edge_bucket_list2.begin(),
edge_bucket_list2.end());
// remove the list of edge_id_2
m_edge_id_to_list_index_map.erase(edge_id_2);
BOOST_ASSERT(m_edge_id_to_list_index_map.end() ==
m_edge_id_to_list_index_map.find(edge_id_2));
edge_bucket_list2.clear();
BOOST_ASSERT(0 == edge_bucket_list2.size());
m_free_list.emplace_back(list_to_remove_index);
BOOST_ASSERT(list_to_remove_index == m_free_list.back());
}
else
{
// we are certain that the second edge is atomic.
edge_bucket_list1.emplace_back(target_node_id, weight2);
}
}
void CompressedEdgeContainer::PrintStatistics() const
{
const uint64_t compressed_edges = m_compressed_geometries.size();
BOOST_ASSERT(0 == compressed_edges % 2);
BOOST_ASSERT(m_compressed_geometries.size() + m_free_list.size() > 0);
uint64_t compressed_geometries = 0;
uint64_t longest_chain_length = 0;
for (const std::vector<CompressedNode> &current_vector : m_compressed_geometries)
{
compressed_geometries += current_vector.size();
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
}
SimpleLogger().Write() << "Geometry successfully removed:"
"\n compressed edges: " << compressed_edges
<< "\n compressed geometries: " << compressed_geometries
<< "\n longest chain length: " << longest_chain_length
<< "\n cmpr ratio: " << ((float)compressed_edges /
std::max(compressed_geometries, (uint64_t)1))
<< "\n avg chain length: "
<< (float)compressed_geometries /
std::max((uint64_t)1, compressed_edges);
}
const CompressedEdgeContainer::EdgeBucket&
CompressedEdgeContainer::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);
}
NodeID CompressedEdgeContainer::GetFirstEdgeTargetID(const EdgeID edge_id) const
{
const auto &bucket = GetBucketReference(edge_id);
BOOST_ASSERT(bucket.size() >= 2);
return bucket.front().first;
}
NodeID CompressedEdgeContainer::GetLastEdgeSourceID(const EdgeID edge_id) const
{
const auto &bucket = GetBucketReference(edge_id);
BOOST_ASSERT(bucket.size() >= 2);
return bucket[bucket.size() - 2].first;
}
+689
View File
@@ -0,0 +1,689 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "edge_based_graph_factory.hpp"
#include "../algorithms/coordinate_calculation.hpp"
#include "../data_structures/percent.hpp"
#include "../util/compute_angle.hpp"
#include "../util/integer_range.hpp"
#include "../util/lua_util.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/debug_geometry.hpp"
#include <boost/assert.hpp>
#include <fstream>
#include <iomanip>
#include <limits>
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
std::shared_ptr<const RestrictionMap> restriction_map,
const std::vector<QueryNode> &node_info_list,
SpeedProfileProperties speed_profile)
: m_max_edge_id(0), m_node_info_list(node_info_list), m_node_based_graph(std::move(node_based_graph)),
m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
speed_profile(std::move(speed_profile))
{
}
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
{
BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
using std::swap; // Koenig swap
swap(m_edge_based_edge_list, output_edge_list);
}
void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
{
#ifndef NDEBUG
for (const EdgeBasedNode &node : m_edge_based_node_list)
{
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);
}
#endif
using std::swap; // Koenig swap
swap(nodes, m_edge_based_node_list);
}
void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
{
using std::swap; // Koenig swap
swap(m_edge_based_node_is_startpoint, node_is_startpoint);
}
unsigned EdgeBasedGraphFactory::GetHighestEdgeID()
{
return m_max_edge_id;
}
void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
const NodeID node_v)
{
// merge edges together into one EdgeBasedNode
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
// find forward edge id and
const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
// find reverse edge id and
const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
if (forward_data.edge_id == SPECIAL_NODEID &&
reverse_data.edge_id == SPECIAL_NODEID)
{
return;
}
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
m_compressed_edge_container.HasEntryForID(edge_id_2));
if (m_compressed_edge_container.HasEntryForID(edge_id_1))
{
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
// reconstruct geometry and put in each individual edge with its offset
const auto& forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
const auto& reverse_geometry = m_compressed_edge_container.GetBucketReference(edge_id_2);
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
BOOST_ASSERT(0 != forward_geometry.size());
const unsigned geometry_size = static_cast<unsigned>(forward_geometry.size());
BOOST_ASSERT(geometry_size > 1);
// 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);
// quick'n'dirty prefix sum as std::partial_sum needs addtional casts
// TODO: move to lambda function with C++11
int temp_sum = 0;
for (const auto i : osrm::irange(0u, geometry_size))
{
forward_dist_prefix_sum[i] = temp_sum;
temp_sum += forward_geometry[i].second;
BOOST_ASSERT(forward_data.distance >= temp_sum);
}
temp_sum = 0;
for (const auto i : osrm::irange(0u, geometry_size))
{
temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
// BOOST_ASSERT(reverse_data.distance >= temp_sum);
}
NodeID current_edge_source_coordinate_id = node_u;
// traverse arrays from start and end respectively
for (const auto i : osrm::irange(0u, geometry_size))
{
BOOST_ASSERT(current_edge_source_coordinate_id ==
reverse_geometry[geometry_size - 1 - i].first);
const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
// build edges
m_edge_based_node_list.emplace_back(
forward_data.edge_id, reverse_data.edge_id,
current_edge_source_coordinate_id, current_edge_target_coordinate_id,
forward_data.name_id, forward_geometry[i].second,
reverse_geometry[geometry_size - 1 - i].second, forward_dist_prefix_sum[i],
reverse_dist_prefix_sum[i], m_compressed_edge_container.GetPositionForID(edge_id_1),
false, INVALID_COMPONENTID, i, forward_data.travel_mode, reverse_data.travel_mode);
m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
node_v != m_edge_based_node_list.back().v);
BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
node_v != m_edge_based_node_list.back().u);
}
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
}
else
{
BOOST_ASSERT(!m_compressed_edge_container.HasEntryForID(edge_id_2));
if (forward_data.edge_id != SPECIAL_NODEID)
{
BOOST_ASSERT(!forward_data.reversed);
}
else
{
BOOST_ASSERT(forward_data.reversed);
}
if (reverse_data.edge_id != SPECIAL_NODEID)
{
BOOST_ASSERT(!reverse_data.reversed);
}
else
{
BOOST_ASSERT(reverse_data.reversed);
}
BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID ||
reverse_data.edge_id != SPECIAL_NODEID);
m_edge_based_node_list.emplace_back(
forward_data.edge_id, reverse_data.edge_id, node_u, node_v,
forward_data.name_id, forward_data.distance, reverse_data.distance, 0, 0, SPECIAL_EDGEID,
false, INVALID_COMPONENTID, 0, forward_data.travel_mode, reverse_data.travel_mode);
m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
}
}
void EdgeBasedGraphFactory::FlushVectorToStream(
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
{
if (original_edge_data_vector.empty())
{
return;
}
edge_data_file.write((char *)&(original_edge_data_vector[0]),
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
original_edge_data_vector.clear();
}
#ifdef DEBUG_GEOMETRY
void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
lua_State *lua_state,
const std::string &edge_segment_lookup_filename,
const std::string &edge_penalty_filename,
const bool generate_edge_lookup,
const std::string &debug_turns_path)
#else
void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
lua_State *lua_state,
const std::string &edge_segment_lookup_filename,
const std::string &edge_penalty_filename,
const bool generate_edge_lookup)
#endif
{
TIMER_START(renumber);
m_max_edge_id = RenumberEdges() - 1;
TIMER_STOP(renumber);
TIMER_START(generate_nodes);
GenerateEdgeExpandedNodes();
TIMER_STOP(generate_nodes);
TIMER_START(generate_edges);
#ifdef DEBUG_GEOMETRY
GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
edge_segment_lookup_filename,edge_penalty_filename,
generate_edge_lookup, debug_turns_path);
#else
GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
edge_segment_lookup_filename,edge_penalty_filename,
generate_edge_lookup);
#endif
TIMER_STOP(generate_edges);
SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
}
/// Renumbers all _forward_ edges and sets the edge_id.
/// A specific numbering is not important. Any unique ID will do.
/// Returns the number of edge based nodes.
unsigned EdgeBasedGraphFactory::RenumberEdges()
{
// renumber edge based node of outgoing edges
unsigned numbered_edges_count = 0;
for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
{
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
// only number incoming edges
if (edge_data.reversed)
{
continue;
}
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
edge_data.edge_id = numbered_edges_count;
++numbered_edges_count;
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
}
}
return numbered_edges_count;
}
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
{
Percent progress(m_node_based_graph->GetNumberOfNodes());
// loop over all edges and generate new set of nodes
for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
progress.printStatus(node_u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
const NodeID node_v = m_node_based_graph->GetTarget(e1);
BOOST_ASSERT(SPECIAL_NODEID != node_v);
// pick only every other edge, since we have every edge as an outgoing
// and incoming egde
if (node_u > node_v)
{
continue;
}
BOOST_ASSERT(node_u < node_v);
// if we found a non-forward edge reverse and try again
if (edge_data.edge_id == SPECIAL_NODEID)
{
InsertEdgeBasedNode(node_v, node_u);
}
else
{
InsertEdgeBasedNode(node_u, node_v);
}
}
}
BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
<< " nodes in edge-expanded graph";
}
/// Actually it also generates OriginalEdgeData and serializes them...
#ifdef DEBUG_GEOMETRY
void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &original_edge_data_filename, lua_State *lua_state,
const std::string &edge_segment_lookup_filename,
const std::string &edge_fixed_penalties_filename,
const bool generate_edge_lookup,
const std::string &debug_turns_path)
#else
void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &original_edge_data_filename, lua_State *lua_state,
const std::string &edge_segment_lookup_filename,
const std::string &edge_fixed_penalties_filename,
const bool generate_edge_lookup)
#endif
{
SimpleLogger().Write() << "generating edge-expanded edges";
unsigned node_based_edge_counter = 0;
unsigned original_edges_counter = 0;
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
std::ofstream edge_segment_file;
std::ofstream edge_penalty_file;
if (generate_edge_lookup)
{
edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
}
// 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;
original_edge_data_vector.reserve(1024 * 1024);
// 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.
unsigned restricted_turns_counter = 0;
unsigned skipped_uturns_counter = 0;
unsigned skipped_barrier_turns_counter = 0;
unsigned compressed = 0;
Percent progress(m_node_based_graph->GetNumberOfNodes());
#ifdef DEBUG_GEOMETRY
DEBUG_TURNS_START(debug_turns_path);
#endif
for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
//progress.printStatus(node_u);
for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{
if (m_node_based_graph->GetEdgeData(e1).reversed)
{
continue;
}
++node_based_edge_counter;
const NodeID node_v = m_node_based_graph->GetTarget(e1);
const NodeID only_restriction_to_node =
m_restriction_map->CheckForEmanatingIsOnlyTurn(node_u, node_v);
const bool is_barrier_node = m_barrier_nodes.find(node_v) != m_barrier_nodes.end();
for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
{
if (m_node_based_graph->GetEdgeData(e2).reversed)
{
continue;
}
const NodeID node_w = m_node_based_graph->GetTarget(e2);
if ((only_restriction_to_node != SPECIAL_NODEID) &&
(node_w != only_restriction_to_node))
{
// We are at an only_-restriction but not at the right turn.
++restricted_turns_counter;
continue;
}
if (is_barrier_node)
{
if (node_u != node_w)
{
++skipped_barrier_turns_counter;
continue;
}
}
else
{
if ((node_u == node_w) && (m_node_based_graph->GetOutDegree(node_v) > 1))
{
++skipped_uturns_counter;
continue;
}
}
// 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(node_u, node_v, node_w) &&
(only_restriction_to_node == SPECIAL_NODEID) &&
(node_w != only_restriction_to_node))
{
// We are at an only_-restriction but not at the right turn.
++restricted_turns_counter;
continue;
}
// 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);
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
BOOST_ASSERT(!edge_data1.reversed);
BOOST_ASSERT(!edge_data2.reversed);
// the following is the core of the loop.
unsigned distance = edge_data1.distance;
if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
{
distance += speed_profile.traffic_signal_penalty;
DEBUG_SIGNAL(node_v, m_node_info_list, speed_profile.traffic_signal_penalty);
}
// unpack last node of first segment if packed
const auto first_coordinate =
m_node_info_list[(m_compressed_edge_container.HasEntryForID(e1)
? m_compressed_edge_container.GetLastEdgeSourceID(e1)
: node_u)];
// unpack first node of second segment if packed
const auto third_coordinate =
m_node_info_list[(m_compressed_edge_container.HasEntryForID(e2)
? m_compressed_edge_container.GetFirstEdgeTargetID(e2)
: node_w)];
const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
first_coordinate, m_node_info_list[node_v], third_coordinate);
const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
if (turn_instruction == TurnInstruction::UTurn)
{
distance += speed_profile.u_turn_penalty;
DEBUG_UTURN(node_v, m_node_info_list, speed_profile.u_turn_penalty);
}
DEBUG_TURN(node_v, m_node_info_list, first_coordinate, turn_angle, turn_penalty);
distance += turn_penalty;
const bool edge_is_compressed = m_compressed_edge_container.HasEntryForID(e1);
if (edge_is_compressed)
{
++compressed;
}
original_edge_data_vector.emplace_back(
(edge_is_compressed ? m_compressed_edge_container.GetPositionForID(e1) : node_v),
edge_data1.name_id, turn_instruction, edge_is_compressed,
edge_data2.travel_mode);
++original_edges_counter;
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
{
FlushVectorToStream(edge_data_file, original_edge_data_vector);
}
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
// NOTE: potential overflow here if we hit 2^32 routable edges
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
m_edge_based_edge_list.size(), distance, true, false);
// Here is where we write out the mapping between the edge-expanded edges, and
// the node-based edges that are originally used to calculate the `distance`
// for the edge-expanded edges. About 40 lines back, there is:
//
// unsigned distance = edge_data1.distance;
//
// This tells us that the weight for an edge-expanded-edge is based on the weight
// of the *source* node-based edge. Therefore, we will look up the individual
// segments of the source node-based edge, and write out a mapping between
// those and the edge-based-edge ID.
// External programs can then use this mapping to quickly perform
// updates to the edge-expanded-edge based directly on its ID.
if (generate_edge_lookup)
{
unsigned fixed_penalty = distance - edge_data1.distance;
edge_penalty_file.write(reinterpret_cast<const char *>(&fixed_penalty), sizeof(fixed_penalty));
if (edge_is_compressed)
{
const auto node_based_edges = m_compressed_edge_container.GetBucketReference(e1);
NodeID previous = node_u;
const unsigned node_count = node_based_edges.size()+1;
edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
const QueryNode &first_node = m_node_info_list[previous];
edge_segment_file.write(reinterpret_cast<const char *>(&first_node.node_id), sizeof(first_node.node_id));
for (auto target_node : node_based_edges)
{
const QueryNode &from = m_node_info_list[previous];
const QueryNode &to = m_node_info_list[target_node.first];
const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
edge_segment_file.write(reinterpret_cast<const char *>(&target_node.second), sizeof(target_node.second));
previous = target_node.first;
}
}
else
{
static const unsigned node_count = 2;
const QueryNode from = m_node_info_list[node_u];
const QueryNode to = m_node_info_list[node_v];
const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
edge_segment_file.write(reinterpret_cast<const char *>(&from.node_id), sizeof(from.node_id));
edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
edge_segment_file.write(reinterpret_cast<const char *>(&edge_data1.distance), sizeof(edge_data1.distance));
}
}
}
}
}
DEBUG_TURNS_STOP();
FlushVectorToStream(edge_data_file, original_edge_data_vector);
edge_data_file.seekp(std::ios::beg);
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
edge_data_file.close();
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";
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";
}
int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
{
if (speed_profile.has_turn_penalty_function)
{
try
{
// call lua profile to compute turn penalty
double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
return static_cast<int>(penalty);
}
catch (const luabind::error &er)
{
SimpleLogger().Write(logWARNING) << er.what();
}
}
return 0;
}
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
const NodeID node_v,
const NodeID node_w,
const double angle) const
{
if (node_u == node_w)
{
return TurnInstruction::UTurn;
}
const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
// 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->GetDirectedOutDegree(node_v))
{
// No turn possible.
return TurnInstruction::NoTurn;
}
return TurnInstruction::StayOnRoundAbout;
}
// 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;
}
// We are leaving the roundabout
if (data1.roundabout && (!data2.roundabout))
{
return TurnInstruction::LeaveRoundAbout;
}
}
// 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.name_id == data2.name_id && data1.travel_mode == data2.travel_mode)
{
// TODO: Here we should also do a small graph exploration to check for
// more complex situations
if (0 != data1.name_id || m_node_based_graph->GetOutDegree(node_v) <= 2)
{
return TurnInstruction::NoTurn;
}
}
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
}
+66
View File
@@ -0,0 +1,66 @@
/*
Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "external_memory_node.hpp"
#include "query_node.hpp"
#include <limits>
ExternalMemoryNode::ExternalMemoryNode(
int lat, int lon, OSMNodeID node_id, bool barrier, bool traffic_lights)
: QueryNode(lat, lon, node_id), barrier(barrier), traffic_lights(traffic_lights)
{
}
ExternalMemoryNode::ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
ExternalMemoryNode ExternalMemoryNode::min_value()
{
return ExternalMemoryNode(0, 0, MIN_OSM_NODEID, false, false);
}
ExternalMemoryNode ExternalMemoryNode::max_value()
{
return ExternalMemoryNode(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(),
MAX_OSM_NODEID, false, false);
}
bool ExternalMemoryNodeSTXXLCompare::operator()(const ExternalMemoryNode &left,
const ExternalMemoryNode &right) const
{
return left.node_id < right.node_id;
}
ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::max_value()
{
return ExternalMemoryNode::max_value();
}
ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::min_value()
{
return ExternalMemoryNode::min_value();
}
+739
View File
@@ -0,0 +1,739 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "extraction_containers.hpp"
#include "extraction_way.hpp"
#include "../algorithms/coordinate_calculation.hpp"
#include "../data_structures/node_id.hpp"
#include "../data_structures/range_table.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include "../util/fingerprint.hpp"
#include "../util/lua_util.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/ref.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <luabind/luabind.hpp>
#include <stxxl/sort>
#include <chrono>
#include <limits>
static const int WRITE_BLOCK_BUFFER_SIZE = 8000;
ExtractionContainers::ExtractionContainers()
{
// Check if stxxl can be instantiated
stxxl::vector<unsigned> dummy_vector;
// Insert the empty string, it has no data and is zero length
name_lengths.push_back(0);
}
ExtractionContainers::~ExtractionContainers()
{
// FIXME isn't this done implicitly of the stxxl::vectors go out of scope?
used_node_id_list.clear();
all_nodes_list.clear();
all_edges_list.clear();
name_char_data.clear();
name_lengths.clear();
restrictions_list.clear();
way_start_end_id_list.clear();
}
/**
* Processes the collected data and serializes it.
* At this point nodes are still referenced by their OSM id.
*
* - map start-end nodes of ways to ways used int restrictions to compute compressed
* trippe representation
* - filter nodes list to nodes that are referenced by ways
* - merge edges with nodes to include location of start/end points and serialize
*
*/
void ExtractionContainers::PrepareData(const std::string &output_file_name,
const std::string &restrictions_file_name,
const std::string &name_file_name,
lua_State *segment_state)
{
try
{
std::ofstream file_out_stream;
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
const FingerPrint fingerprint = FingerPrint::GetValid();
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
PrepareNodes();
WriteNodes(file_out_stream);
PrepareEdges(segment_state);
WriteEdges(file_out_stream);
file_out_stream.close();
PrepareRestrictions();
WriteRestrictions(restrictions_file_name);
WriteNames(name_file_name);
}
catch (const std::exception &e)
{
std::cerr << "Caught Execption:" << e.what() << std::endl;
}
}
void ExtractionContainers::WriteNames(const std::string& names_file_name) const
{
std::cout << "[extractor] writing street name index ... " << std::flush;
TIMER_START(write_name_index);
boost::filesystem::ofstream name_file_stream(names_file_name, std::ios::binary);
unsigned total_length = 0;
for (const unsigned &name_length : name_lengths)
{
total_length += name_length;
}
// builds and writes the index
RangeTable<> name_index_range(name_lengths);
name_file_stream << name_index_range;
name_file_stream.write((char *)&total_length, sizeof(unsigned));
// write all chars consecutively
char write_buffer[WRITE_BLOCK_BUFFER_SIZE];
unsigned buffer_len = 0;
for (const char &c : name_char_data)
{
write_buffer[buffer_len++] = c;
if (buffer_len >= WRITE_BLOCK_BUFFER_SIZE)
{
name_file_stream.write(write_buffer, WRITE_BLOCK_BUFFER_SIZE);
buffer_len = 0;
}
}
name_file_stream.write(write_buffer, buffer_len);
name_file_stream.close();
TIMER_STOP(write_name_index);
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
}
void ExtractionContainers::PrepareNodes()
{
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
TIMER_START(sorting_used_nodes);
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
TIMER_STOP(sorting_used_nodes);
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
TIMER_START(erasing_dups);
auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
used_node_id_list.resize(new_end - used_node_id_list.begin());
TIMER_STOP(erasing_dups);
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
TIMER_START(sorting_nodes);
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
stxxl_memory);
TIMER_STOP(sorting_nodes);
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
std::cout << "[extractor] Building node id map ... " << std::flush;
TIMER_START(id_map);
external_to_internal_node_id_map.reserve(used_node_id_list.size());
auto node_iter = all_nodes_list.begin();
auto ref_iter = used_node_id_list.begin();
const auto all_nodes_list_end = all_nodes_list.end();
const auto used_node_id_list_end = used_node_id_list.end();
// Note: despite being able to handle 64 bit OSM node ids, we can't
// handle > uint32_t actual usable nodes. This should be OK for a while
// because we usually route on a *lot* less than 2^32 of the OSM
// graph nodes.
std::size_t internal_id = 0;
// compute the intersection of nodes that were referenced and nodes we actually have
while (node_iter != all_nodes_list_end && ref_iter != used_node_id_list_end)
{
if (node_iter->node_id < *ref_iter)
{
node_iter++;
continue;
}
if (node_iter->node_id > *ref_iter)
{
ref_iter++;
continue;
}
BOOST_ASSERT(node_iter->node_id == *ref_iter);
external_to_internal_node_id_map[*ref_iter] = static_cast<NodeID>(internal_id++);
node_iter++;
ref_iter++;
}
if (internal_id > std::numeric_limits<NodeID>::max())
{
throw osrm::exception("There are too many nodes remaining after filtering, OSRM only supports 2^32 unique nodes");
}
max_internal_node_id = boost::numeric_cast<NodeID>(internal_id);
TIMER_STOP(id_map);
std::cout << "ok, after " << TIMER_SEC(id_map) << "s" << std::endl;
}
void ExtractionContainers::PrepareEdges(lua_State *segment_state)
{
// Sort edges by start.
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
TIMER_START(sort_edges_by_start);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMStartID(), stxxl_memory);
TIMER_STOP(sort_edges_by_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
std::cout << "[extractor] Setting start coords ... " << std::flush;
TIMER_START(set_start_coords);
// Traverse list of edges and nodes in parallel and set start coord
auto node_iterator = all_nodes_list.begin();
auto edge_iterator = all_edges_list.begin();
const auto all_edges_list_end = all_edges_list.end();
const auto all_nodes_list_end = all_nodes_list.end();
while (edge_iterator != all_edges_list_end && node_iterator != all_nodes_list_end)
{
if (edge_iterator->result.osm_source_id < node_iterator->node_id)
{
SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << edge_iterator->result.source;
edge_iterator->result.source = SPECIAL_NODEID;
++edge_iterator;
continue;
}
if (edge_iterator->result.osm_source_id > node_iterator->node_id)
{
node_iterator++;
continue;
}
// remove loops
if (edge_iterator->result.osm_source_id == edge_iterator->result.osm_target_id)
{
edge_iterator->result.source = SPECIAL_NODEID;
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
}
BOOST_ASSERT(edge_iterator->result.osm_source_id == node_iterator->node_id);
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge_iterator->result.source = id_iter->second;
edge_iterator->source_coordinate.lat = node_iterator->lat;
edge_iterator->source_coordinate.lon = node_iterator->lon;
++edge_iterator;
}
// Remove all remaining edges. They are invalid because there are no corresponding nodes for
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
auto markSourcesInvalid = [](InternalExtractorEdge &edge)
{
SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
<< edge.result.source;
edge.result.source = SPECIAL_NODEID;
edge.result.osm_source_id = SPECIAL_OSM_NODEID;
};
std::for_each(edge_iterator, all_edges_list_end, markSourcesInvalid);
TIMER_STOP(set_start_coords);
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
// Sort Edges by target
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
TIMER_START(sort_edges_by_target);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMTargetID(),
stxxl_memory);
TIMER_STOP(sort_edges_by_target);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
// Compute edge weights
std::cout << "[extractor] Computing edge weights ... " << std::flush;
TIMER_START(compute_weights);
node_iterator = all_nodes_list.begin();
edge_iterator = all_edges_list.begin();
const auto all_edges_list_end_ = all_edges_list.end();
const auto all_nodes_list_end_ = all_nodes_list.end();
while (edge_iterator != all_edges_list_end_ && node_iterator != all_nodes_list_end_)
{
// skip all invalid edges
if (edge_iterator->result.source == SPECIAL_NODEID)
{
++edge_iterator;
continue;
}
if (edge_iterator->result.osm_target_id < node_iterator->node_id)
{
SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << OSMNodeID_to_uint64_t(edge_iterator->result.osm_target_id);
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
}
if (edge_iterator->result.osm_target_id > node_iterator->node_id)
{
++node_iterator;
continue;
}
BOOST_ASSERT(edge_iterator->result.osm_target_id == node_iterator->node_id);
BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
BOOST_ASSERT(edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min());
BOOST_ASSERT(edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min());
const double distance = coordinate_calculation::great_circle_distance(
edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
node_iterator->lat, node_iterator->lon);
if (lua_function_exists(segment_state, "segment_function"))
{
luabind::call_function<void>(
segment_state, "segment_function",
boost::cref(edge_iterator->source_coordinate),
boost::cref(*node_iterator),
distance,
boost::ref(edge_iterator->weight_data));
}
const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
switch (data.type)
{
case InternalExtractorEdge::WeightType::EDGE_DURATION:
case InternalExtractorEdge::WeightType::WAY_DURATION:
return data.duration * 10.;
break;
case InternalExtractorEdge::WeightType::SPEED:
return (distance * 10.) / (data.speed / 3.6);
break;
case InternalExtractorEdge::WeightType::INVALID:
osrm::exception("invalid weight type");
}
return -1.0;
}(edge_iterator->weight_data);
auto& edge = edge_iterator->result;
edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge.target = id_iter->second;
// orient edges consistently: source id < target id
// important for multi-edge removal
if (edge.source > edge.target)
{
std::swap(edge.source, edge.target);
// std::swap does not work with bit-fields
bool temp = edge.forward;
edge.forward = edge.backward;
edge.backward = temp;
}
++edge_iterator;
}
// Remove all remaining edges. They are invalid because there are no corresponding nodes for
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
auto markTargetsInvalid = [](InternalExtractorEdge &edge)
{
SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
<< edge.result.target;
edge.result.target = SPECIAL_NODEID;
};
std::for_each(edge_iterator, all_edges_list_end_, markTargetsInvalid);
TIMER_STOP(compute_weights);
std::cout << "ok, after " << TIMER_SEC(compute_weights) << "s" << std::endl;
// Sort edges by start.
std::cout << "[extractor] Sorting edges by renumbered start ... " << std::flush;
TIMER_START(sort_edges_by_renumbered_start);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByInternalStartThenInternalTargetID(), stxxl_memory);
TIMER_STOP(sort_edges_by_renumbered_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
BOOST_ASSERT(all_edges_list.size() > 0);
for (unsigned i = 0; i < all_edges_list.size();)
{
// only invalid edges left
if (all_edges_list[i].result.source == SPECIAL_NODEID)
{
break;
}
// skip invalid edges
if (all_edges_list[i].result.target == SPECIAL_NODEID)
{
++i;
continue;
}
unsigned start_idx = i;
NodeID source = all_edges_list[i].result.source;
NodeID target = all_edges_list[i].result.target;
int min_forward_weight = std::numeric_limits<int>::max();
int min_backward_weight = std::numeric_limits<int>::max();
unsigned min_forward_idx = std::numeric_limits<unsigned>::max();
unsigned min_backward_idx = std::numeric_limits<unsigned>::max();
// find minimal edge in both directions
while (all_edges_list[i].result.source == source &&
all_edges_list[i].result.target == target)
{
if (all_edges_list[i].result.forward && all_edges_list[i].result.weight < min_forward_weight)
{
min_forward_idx = i;
}
if (all_edges_list[i].result.backward && all_edges_list[i].result.weight < min_backward_weight)
{
min_backward_idx = i;
}
// this also increments the outer loop counter!
i++;
}
BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() || min_forward_idx < i);
BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() || min_backward_idx < i);
BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
min_forward_idx != std::numeric_limits<unsigned>::max());
if (min_backward_idx == min_forward_idx)
{
all_edges_list[min_forward_idx].result.is_split = false;
all_edges_list[min_forward_idx].result.forward = true;
all_edges_list[min_forward_idx].result.backward = true;
}
else
{
bool has_forward = min_forward_idx != std::numeric_limits<unsigned>::max();
bool has_backward = min_backward_idx != std::numeric_limits<unsigned>::max();
if (has_forward)
{
all_edges_list[min_forward_idx].result.forward = true;
all_edges_list[min_forward_idx].result.backward = false;
all_edges_list[min_forward_idx].result.is_split = has_backward;
}
if (has_backward)
{
std::swap(all_edges_list[min_backward_idx].result.source,
all_edges_list[min_backward_idx].result.target);
all_edges_list[min_backward_idx].result.forward = true;
all_edges_list[min_backward_idx].result.backward = false;
all_edges_list[min_backward_idx].result.is_split = has_forward;
}
}
// invalidate all unused edges
for (unsigned j = start_idx; j < i; j++)
{
if (j == min_forward_idx || j == min_backward_idx)
{
continue;
}
all_edges_list[j].result.source = SPECIAL_NODEID;
all_edges_list[j].result.target = SPECIAL_NODEID;
}
}
}
void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
{
std::cout << "[extractor] Writing used edges ... " << std::flush;
TIMER_START(write_edges);
// Traverse list of edges and nodes in parallel and set target coord
std::size_t used_edges_counter = 0;
unsigned used_edges_counter_buffer = 0;
auto start_position = file_out_stream.tellp();
file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
for (const auto& edge : all_edges_list)
{
if (edge.result.source == SPECIAL_NODEID || edge.result.target == SPECIAL_NODEID)
{
continue;
}
// IMPORTANT: here, we're using slicing to only write the data from the base
// class of NodeBasedEdgeWithOSM
NodeBasedEdge tmp = edge.result;
file_out_stream.write((char*) &tmp, sizeof(NodeBasedEdge));
used_edges_counter++;
}
if (used_edges_counter > std::numeric_limits<unsigned>::max())
{
throw osrm::exception("There are too many edges, OSRM only supports 2^32");
}
TIMER_STOP(write_edges);
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
std::cout << "[extractor] setting number of edges ... " << std::flush;
used_edges_counter_buffer = boost::numeric_cast<unsigned>(used_edges_counter);
file_out_stream.seekp(start_position);
file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
std::cout << "ok" << std::endl;
SimpleLogger().Write() << "Processed " << used_edges_counter << " edges";
}
void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
{
// write dummy value, will be overwritten later
std::cout << "[extractor] setting number of nodes ... " << std::flush;
file_out_stream.write((char *)&max_internal_node_id, sizeof(unsigned));
std::cout << "ok" << std::endl;
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
TIMER_START(write_nodes);
// identify all used nodes by a merging step of two sorted lists
auto node_iterator = all_nodes_list.begin();
auto node_id_iterator = used_node_id_list.begin();
const auto used_node_id_list_end = used_node_id_list.end();
const auto all_nodes_list_end = all_nodes_list.end();
while (node_id_iterator != used_node_id_list_end && node_iterator != all_nodes_list_end)
{
if (*node_id_iterator < node_iterator->node_id)
{
++node_id_iterator;
continue;
}
if (*node_id_iterator > node_iterator->node_id)
{
++node_iterator;
continue;
}
BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
++node_id_iterator;
++node_iterator;
}
TIMER_STOP(write_nodes);
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
SimpleLogger().Write() << "Processed " << max_internal_node_id << " nodes";
}
void ExtractionContainers::WriteRestrictions(const std::string& path) const
{
// serialize restrictions
std::ofstream restrictions_out_stream;
unsigned written_restriction_count = 0;
restrictions_out_stream.open(path.c_str(), std::ios::binary);
const FingerPrint fingerprint = FingerPrint::GetValid();
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
const auto count_position = restrictions_out_stream.tellp();
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
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)
{
restrictions_out_stream.write((char *)&(restriction_container.restriction),
sizeof(TurnRestriction));
++written_restriction_count;
}
}
restrictions_out_stream.seekp(count_position);
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
restrictions_out_stream.close();
SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
}
void ExtractionContainers::PrepareRestrictions()
{
std::cout << "[extractor] Sorting used ways ... " << std::flush;
TIMER_START(sort_ways);
stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
TIMER_STOP(sort_ways);
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
std::cout << "[extractor] Sorting " << restrictions_list.size()
<< " restriction. by from... " << std::flush;
TIMER_START(sort_restrictions);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByFrom(), stxxl_memory);
TIMER_STOP(sort_restrictions);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
std::cout << "[extractor] 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(restrictions_iterator->restriction.from.way))
{
++way_start_and_end_iterator;
continue;
}
if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.from.way))
{
SimpleLogger().Write(LogLevel::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(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_node_id = OSMNodeID(restrictions_iterator->restriction.via.node);
// check if via is actually valid, if not invalidate
auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
if(via_id_iter == external_to_internal_node_id_map.end())
{
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
++restrictions_iterator;
continue;
}
if (OSMNodeID(way_start_and_end_iterator->first_segment_source_id) == via_node_id)
{
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.from.node = id_iter->second;
}
else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
{
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.from.node = id_iter->second;
}
++restrictions_iterator;
}
TIMER_STOP(fix_restriction_starts);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
TIMER_START(sort_restrictions_to);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByTo(), stxxl_memory);
TIMER_STOP(sort_restrictions_to);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
TIMER_START(fix_restriction_ends);
restrictions_iterator = restrictions_list.begin();
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();
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(restrictions_iterator->restriction.to.way))
{
++way_start_and_end_iterator;
continue;
}
if (restrictions_iterator->restriction.from.node == SPECIAL_NODEID ||
restrictions_iterator->restriction.via.node == SPECIAL_NODEID)
{
++restrictions_iterator;
continue;
}
if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.to.way))
{
SimpleLogger().Write(LogLevel::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(restrictions_iterator->restriction.to.way));
const OSMNodeID via_node_id = OSMNodeID(restrictions_iterator->restriction.via.node);
// assign new via node id
auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
BOOST_ASSERT(via_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.via.node = via_id_iter->second;
if (OSMNodeID(way_start_and_end_iterator->first_segment_source_id) == via_node_id)
{
auto to_id_iter = external_to_internal_node_id_map.find(
OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
{
auto to_id_iter = external_to_internal_node_id_map.find(
OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
++restrictions_iterator;
}
TIMER_STOP(fix_restriction_ends);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
}
+638
View File
@@ -0,0 +1,638 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "extractor.hpp"
#include "extraction_containers.hpp"
#include "extraction_node.hpp"
#include "extraction_way.hpp"
#include "extractor_callbacks.hpp"
#include "restriction_parser.hpp"
#include "scripting_environment.hpp"
#include "../data_structures/raster_source.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include "../util/lua_util.hpp"
#include "../util/graph_loader.hpp"
#include "../typedefs.h"
#include "../data_structures/static_graph.hpp"
#include "../data_structures/static_rtree.hpp"
#include "../data_structures/restriction_map.hpp"
#include "../data_structures/compressed_edge_container.hpp"
#include "../algorithms/tarjan_scc.hpp"
#include "../algorithms/crc32_processor.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/optional/optional.hpp>
#include <luabind/luabind.hpp>
#include <osmium/io/any_input.hpp>
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_init.h>
#include <cstdlib>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>
#include <unordered_map>
#include <vector>
/**
* TODO: Refactor this function into smaller functions for better readability.
*
* This function is the entry point for the whole extraction process. The goal of the extraction
* step is to filter and convert the OSM geometry to something more fitting for routing.
* That includes:
* - extracting turn restrictions
* - splitting ways into (directional!) edge segments
* - checking if nodes are barriers or traffic signal
* - discarding all tag information: All relevant type information for nodes/ways
* is extracted at this point.
*
* The result of this process are the following files:
* .names : Names of all streets, stored as long consecutive string with prefix sum based index
* .osrm : Nodes and edges in a intermediate format that easy to digest for osrm-prepare
* .restrictions : Turn restrictions that are used my osrm-prepare to construct the edge-expanded
* graph
*
*/
int extractor::run()
{
try
{
LogPolicy::GetInstance().Unmute();
TIMER_START(extracting);
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
const auto number_of_threads =
std::min(recommended_num_threads, config.requested_num_threads);
tbb::task_scheduler_init init(number_of_threads);
SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
SimpleLogger().Write() << "Threads: " << number_of_threads;
// setup scripting environment
ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
ExtractionContainers extraction_containers;
auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers);
const osmium::io::File input_file(config.input_path.string());
osmium::io::Reader reader(input_file);
const osmium::io::Header header = reader.header();
std::atomic<unsigned> number_of_nodes{0};
std::atomic<unsigned> number_of_ways{0};
std::atomic<unsigned> number_of_relations{0};
std::atomic<unsigned> number_of_others{0};
SimpleLogger().Write() << "Parsing in progress..";
TIMER_START(parsing);
lua_State *segment_state = scripting_environment.get_lua_state();
if (lua_function_exists(segment_state, "source_function"))
{
// bind a single instance of SourceContainer class to relevant lua state
SourceContainer sources;
luabind::globals(segment_state)["sources"] = sources;
luabind::call_function<void>(segment_state, "source_function");
}
std::string generator = header.get("generator");
if (generator.empty())
{
generator = "unknown tool";
}
SimpleLogger().Write() << "input file generated by " << generator;
// write .timestamp data file
std::string timestamp = header.get("osmosis_replication_timestamp");
if (timestamp.empty())
{
timestamp = "n/a";
}
SimpleLogger().Write() << "timestamp: " << timestamp;
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
timestamp_out.write(timestamp.c_str(), timestamp.length());
timestamp_out.close();
// initialize vectors holding parsed objects
tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
tbb::concurrent_vector<std::pair<std::size_t, ExtractionWay>> resulting_ways;
tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
// setup restriction parser
const RestrictionParser restriction_parser(scripting_environment.get_lua_state());
while (const osmium::memory::Buffer buffer = reader.read())
{
// create a vector of iterators into the buffer
std::vector<osmium::memory::Buffer::const_iterator> osm_elements;
for (auto iter = std::begin(buffer), end = std::end(buffer); iter != end; ++iter)
{
osm_elements.push_back(iter);
}
// clear resulting vectors
resulting_nodes.clear();
resulting_ways.clear();
resulting_restrictions.clear();
// parse OSM entities in parallel, store in resulting vectors
tbb::parallel_for(
tbb::blocked_range<std::size_t>(0, osm_elements.size()),
[&](const tbb::blocked_range<std::size_t> &range)
{
ExtractionNode result_node;
ExtractionWay result_way;
lua_State *local_state = scripting_environment.get_lua_state();
for (auto x = range.begin(), end = range.end(); x != end; ++x)
{
const auto entity = osm_elements[x];
switch (entity->type())
{
case osmium::item_type::node:
result_node.clear();
++number_of_nodes;
luabind::call_function<void>(
local_state, "node_function",
boost::cref(static_cast<const osmium::Node &>(*entity)),
boost::ref(result_node));
resulting_nodes.push_back(std::make_pair(x, result_node));
break;
case osmium::item_type::way:
result_way.clear();
++number_of_ways;
luabind::call_function<void>(
local_state, "way_function",
boost::cref(static_cast<const osmium::Way &>(*entity)),
boost::ref(result_way));
resulting_ways.push_back(std::make_pair(x, result_way));
break;
case osmium::item_type::relation:
++number_of_relations;
resulting_restrictions.push_back(restriction_parser.TryParse(
static_cast<const osmium::Relation &>(*entity)));
break;
default:
++number_of_others;
break;
}
}
});
// put parsed objects thru extractor callbacks
for (const auto &result : resulting_nodes)
{
extractor_callbacks->ProcessNode(
static_cast<const osmium::Node &>(*(osm_elements[result.first])),
result.second);
}
for (const auto &result : resulting_ways)
{
extractor_callbacks->ProcessWay(
static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
}
for (const auto &result : resulting_restrictions)
{
extractor_callbacks->ProcessRestriction(result);
}
}
TIMER_STOP(parsing);
SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
SimpleLogger().Write() << "Raw input contains " << number_of_nodes.load() << " nodes, "
<< number_of_ways.load() << " ways, and "
<< number_of_relations.load() << " relations, and "
<< number_of_others.load() << " unknown entities";
extractor_callbacks.reset();
if (extraction_containers.all_edges_list.empty())
{
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return 1;
}
extraction_containers.PrepareData(config.output_file_name, config.restriction_file_name,
config.names_file_name, segment_state);
TIMER_STOP(extracting);
SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << e.what();
return 1;
}
try
{
// Transform the node-based graph that OSM is based on into an edge-based graph
// that is better for routing. Every edge becomes a node, and every valid
// movement (e.g. turn from A->B, and B->A) becomes an edge
//
//
// // Create a new lua state
SimpleLogger().Write() << "Generating edge-expanded graph representation";
TIMER_START(expansion);
std::vector<EdgeBasedNode> node_based_edge_list;
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
std::vector<bool> node_is_startpoint;
std::vector<QueryNode> internal_to_external_node_map;
auto graph_size =
BuildEdgeExpandedGraph(internal_to_external_node_map, node_based_edge_list,
node_is_startpoint, edge_based_edge_list);
auto number_of_node_based_nodes = graph_size.first;
auto max_edge_id = graph_size.second;
TIMER_STOP(expansion);
SimpleLogger().Write() << "building r-tree ...";
TIMER_START(rtree);
FindComponents(max_edge_id, edge_based_edge_list, node_based_edge_list);
BuildRTree(std::move(node_based_edge_list), std::move(node_is_startpoint),
internal_to_external_node_map);
TIMER_STOP(rtree);
SimpleLogger().Write() << "writing node map ...";
WriteNodeMapping(internal_to_external_node_map);
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
SimpleLogger().Write() << "Expansion : "
<< (number_of_node_based_nodes / TIMER_SEC(expansion))
<< " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion))
<< " edges/sec";
SimpleLogger().Write() << "To prepare the data for routing, run: "
<< "./osrm-prepare " << config.output_file_name << std::endl;
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << e.what();
return 1;
}
return 0;
}
/**
\brief Setups scripting environment (lua-scripting)
Also initializes speed profile.
*/
void extractor::SetupScriptingEnvironment(lua_State *lua_state,
SpeedProfileProperties &speed_profile)
{
// open utility libraries string library;
luaL_openlibs(lua_state);
// adjust lua load path
luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
// Now call our function in a lua script
if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occurred in scripting block";
throw osrm::exception(msg.str());
}
if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occurred in scripting block";
throw osrm::exception(msg.str());
}
speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
SimpleLogger().Write(logDEBUG) << "traffic_signal_penalty: "
<< speed_profile.traffic_signal_penalty;
if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occurred in scripting block";
throw osrm::exception(msg.str());
}
speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
}
void extractor::FindComponents(unsigned max_edge_id,
const DeallocatingVector<EdgeBasedEdge> &input_edge_list,
std::vector<EdgeBasedNode> &input_nodes) const
{
struct UncontractedEdgeData
{
};
struct InputEdge
{
unsigned source;
unsigned target;
UncontractedEdgeData data;
bool operator<(const InputEdge &rhs) const
{
return source < rhs.source || (source == rhs.source && target < rhs.target);
}
bool operator==(const InputEdge &rhs) const
{
return source == rhs.source && target == rhs.target;
}
};
using UncontractedGraph = StaticGraph<UncontractedEdgeData>;
std::vector<InputEdge> edges;
edges.reserve(input_edge_list.size() * 2);
for (const auto &edge : input_edge_list)
{
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.weight, 1)) > 0,
"edge distance < 1");
if (edge.forward)
{
edges.push_back({edge.source, edge.target, {}});
}
if (edge.backward)
{
edges.push_back({edge.target, edge.source, {}});
}
}
// connect forward and backward nodes of each edge
for (const auto &node : input_nodes)
{
if (node.reverse_edge_based_node_id != SPECIAL_NODEID)
{
edges.push_back({node.forward_edge_based_node_id, node.reverse_edge_based_node_id, {}});
edges.push_back({node.reverse_edge_based_node_id, node.forward_edge_based_node_id, {}});
}
}
tbb::parallel_sort(edges.begin(), edges.end());
auto new_end = std::unique(edges.begin(), edges.end());
edges.resize(new_end - edges.begin());
auto uncontractor_graph = std::make_shared<UncontractedGraph>(max_edge_id + 1, edges);
TarjanSCC<UncontractedGraph> component_search(
std::const_pointer_cast<const UncontractedGraph>(uncontractor_graph));
component_search.run();
for (auto &node : input_nodes)
{
auto forward_component = component_search.get_component_id(node.forward_edge_based_node_id);
BOOST_ASSERT(node.reverse_edge_based_node_id == SPECIAL_EDGEID ||
forward_component ==
component_search.get_component_id(node.reverse_edge_based_node_id));
const unsigned component_size = component_search.get_component_size(forward_component);
node.component.is_tiny = component_size < config.small_component_size;
node.component.id = 1 + forward_component;
}
}
/**
\brief Build load restrictions from .restriction file
*/
std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
{
boost::filesystem::ifstream input_stream(config.restriction_file_name,
std::ios::in | std::ios::binary);
std::vector<TurnRestriction> restriction_list;
loadRestrictionsFromFile(input_stream, restriction_list);
SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
return std::make_shared<RestrictionMap>(restriction_list);
}
/**
\brief Load node based graph from .osrm file
*/
std::shared_ptr<NodeBasedDynamicGraph>
extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
std::unordered_set<NodeID> &traffic_lights,
std::vector<QueryNode> &internal_to_external_node_map)
{
std::vector<NodeBasedEdge> edge_list;
boost::filesystem::ifstream input_stream(config.output_file_name,
std::ios::in | std::ios::binary);
std::vector<NodeID> barrier_list;
std::vector<NodeID> traffic_light_list;
NodeID number_of_node_based_nodes = loadNodesFromFile(
input_stream, barrier_list, traffic_light_list, internal_to_external_node_map);
SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
<< traffic_light_list.size() << " traffic lights";
// insert into unordered sets for fast lookup
barrier_nodes.insert(barrier_list.begin(), barrier_list.end());
traffic_lights.insert(traffic_light_list.begin(), traffic_light_list.end());
barrier_list.clear();
barrier_list.shrink_to_fit();
traffic_light_list.clear();
traffic_light_list.shrink_to_fit();
loadEdgesFromFile(input_stream, edge_list);
if (edge_list.empty())
{
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return std::shared_ptr<NodeBasedDynamicGraph>();
}
return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
}
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::pair<std::size_t, std::size_t>
extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
std::vector<EdgeBasedNode> &node_based_edge_list,
std::vector<bool> &node_is_startpoint,
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
{
lua_State *lua_state = luaL_newstate();
luabind::open(lua_state);
SpeedProfileProperties speed_profile;
SetupScriptingEnvironment(lua_state, speed_profile);
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
auto restriction_map = LoadRestrictionMap();
auto node_based_graph =
LoadNodeBasedGraph(barrier_nodes, traffic_lights, internal_to_external_node_map);
CompressedEdgeContainer compressed_edge_container;
GraphCompressor graph_compressor(speed_profile);
graph_compressor.Compress(barrier_nodes, traffic_lights, *restriction_map, *node_based_graph,
compressed_edge_container);
EdgeBasedGraphFactory edge_based_graph_factory(
node_based_graph, compressed_edge_container, barrier_nodes, traffic_lights,
std::const_pointer_cast<RestrictionMap const>(restriction_map),
internal_to_external_node_map, speed_profile);
compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
edge_based_graph_factory.Run(config.edge_output_path, lua_state,
config.edge_segment_lookup_path, config.edge_penalty_path,
config.generate_edge_lookup
#ifdef DEBUG_GEOMETRY
,
config.debug_turns_path
#endif
);
lua_close(lua_state);
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
return std::make_pair(number_of_node_based_nodes, max_edge_id);
}
/**
\brief Writing info on original (node-based) nodes
*/
void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
{
boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
const unsigned size_of_mapping = internal_to_external_node_map.size();
node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
if (size_of_mapping > 0)
{
node_stream.write((char *)internal_to_external_node_map.data(),
size_of_mapping * sizeof(QueryNode));
}
node_stream.close();
}
/**
\brief Building rtree-based nearest-neighbor data structure
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
*/
void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
std::vector<bool> node_is_startpoint,
const std::vector<QueryNode> &internal_to_external_node_map)
{
SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
<< " edge elements build on-top of "
<< internal_to_external_node_map.size() << " coordinates";
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
// Filter node based edges based on startpoint
auto out_iter = node_based_edge_list.begin();
auto in_iter = node_based_edge_list.begin();
for (auto index : osrm::irange<std::size_t>(0, node_is_startpoint.size()))
{
BOOST_ASSERT(in_iter != node_based_edge_list.end());
if (node_is_startpoint[index])
{
*out_iter = *in_iter;
out_iter++;
}
in_iter++;
}
auto new_size = out_iter - node_based_edge_list.begin();
node_based_edge_list.resize(new_size);
TIMER_START(construction);
StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path,
config.rtree_leafs_output_path, internal_to_external_node_map);
TIMER_STOP(construction);
SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
<< " seconds";
}
void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename,
size_t const max_edge_id,
DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
{
std::ofstream file_out_stream;
file_out_stream.open(output_file_filename.c_str(), std::ios::binary);
const FingerPrint fingerprint = FingerPrint::GetValid();
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
std::cout << "[extractor] Writing edge-based-graph egdes ... " << std::flush;
TIMER_START(write_edges);
size_t number_of_used_edges = edge_based_edge_list.size();
file_out_stream.write((char *)&number_of_used_edges, sizeof(size_t));
file_out_stream.write((char *)&max_edge_id, sizeof(size_t));
for (const auto &edge : edge_based_edge_list)
{
file_out_stream.write((char *)&edge, sizeof(EdgeBasedEdge));
}
TIMER_STOP(write_edges);
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
file_out_stream.close();
}
+241
View File
@@ -0,0 +1,241 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "extractor_callbacks.hpp"
#include "extraction_containers.hpp"
#include "extraction_node.hpp"
#include "extraction_way.hpp"
#include "../data_structures/external_memory_node.hpp"
#include "../data_structures/restriction.hpp"
#include "../util/container.hpp"
#include "../util/simple_logger.hpp"
#include <boost/optional/optional.hpp>
#include <osmium/osm.hpp>
#include <osrm/coordinate.hpp>
#include <limits>
#include <string>
#include <vector>
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers)
: external_memory(extraction_containers)
{
string_map[""] = 0;
}
/**
* Takes the node position from osmium and the filtered properties from the lua
* profile and saves them to external memory.
*
* warning: caller needs to take care of synchronization!
*/
void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
const ExtractionNode &result_node)
{
external_memory.all_nodes_list.push_back(
{static_cast<int>(input_node.location().lat() * COORDINATE_PRECISION),
static_cast<int>(input_node.location().lon() * COORDINATE_PRECISION),
OSMNodeID(input_node.id()),
result_node.barrier,
result_node.traffic_lights});
}
void ExtractorCallbacks::ProcessRestriction(
const boost::optional<InputRestrictionContainer> &restriction)
{
if (restriction)
{
external_memory.restrictions_list.push_back(restriction.get());
// SimpleLogger().Write() << "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");
}
}
/**
* Takes the geometry contained in the ```input_way``` and the tags computed
* by the lua profile inside ```parsed_way``` and computes all edge segments.
*
* Depending on the forward/backwards weights the edges are split into forward
* and backward edges.
*
* warning: caller needs to take care of synchronization!
*/
void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way)
{
if (((0 >= parsed_way.forward_speed) ||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) &&
((0 >= parsed_way.backward_speed) ||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) &&
(0 >= parsed_way.duration))
{ // Only true if the way is specified by the speed profile
return;
}
if (input_way.nodes().size() <= 1)
{ // safe-guard against broken data
return;
}
if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
{
SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
<< " of size " << input_way.nodes().size();
return;
}
InternalExtractorEdge::WeightData forward_weight_data;
InternalExtractorEdge::WeightData backward_weight_data;
if (0 < parsed_way.duration)
{
const unsigned num_edges = (input_way.nodes().size() - 1);
// FIXME We devide by the numer of nodes here, but should rather consider
// the length of each segment. We would eigther have to compute the length
// of the whole way here (we can't: no node coordinates) or push that back
// to the container and keep a reference to the way.
forward_weight_data.duration = parsed_way.duration / num_edges;
forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
backward_weight_data.duration = parsed_way.duration / num_edges;
backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
}
else
{
if (parsed_way.forward_speed > 0 &&
parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
{
forward_weight_data.speed = parsed_way.forward_speed;
forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
}
if (parsed_way.backward_speed > 0 &&
parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
{
backward_weight_data.speed = parsed_way.backward_speed;
backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
}
}
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
{
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
return;
}
// Get the unique identifier for the street name
const auto &string_map_iterator = string_map.find(parsed_way.name);
unsigned name_id = external_memory.name_lengths.size();
if (string_map.end() == string_map_iterator)
{
auto name_length = std::min<unsigned>(255u, parsed_way.name.size());
std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length, std::back_inserter(external_memory.name_char_data));
external_memory.name_lengths.push_back(name_length);
string_map.insert(std::make_pair(parsed_way.name, name_id));
}
else
{
name_id = string_map_iterator->second;
}
const bool split_edge = (parsed_way.forward_speed > 0) &&
(TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) &&
(parsed_way.backward_speed > 0) &&
(TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) &&
((parsed_way.forward_speed != parsed_way.backward_speed) ||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
std::transform(input_way.nodes().begin(), input_way.nodes().end(),
std::back_inserter(external_memory.used_node_id_list),
[](const osmium::NodeRef &ref)
{
return OSMNodeID(ref.ref());
});
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
// traverse way in reverse in this case
if (is_opposite_way)
{
BOOST_ASSERT(split_edge == false);
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
backward_weight_data, true, false, parsed_way.roundabout,
parsed_way.is_access_restricted, parsed_way.is_startpoint,
parsed_way.backward_travel_mode, false));
});
external_memory.way_start_end_id_list.push_back(
{OSMWayID(input_way.id()),
OSMNodeID(input_way.nodes().back().ref()),
OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
OSMNodeID(input_way.nodes()[1].ref()),
OSMNodeID(input_way.nodes()[0].ref())});
}
else
{
const bool forward_only =
split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, forward_weight_data,
true, !forward_only, parsed_way.roundabout,
parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.forward_travel_mode,
split_edge));
});
if (split_edge)
{
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
osrm::for_each_pair(
input_way.nodes().cbegin(), input_way.nodes().cend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, backward_weight_data, false,
true, parsed_way.roundabout, parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.backward_travel_mode, true));
});
}
external_memory.way_start_end_id_list.push_back(
{OSMWayID(input_way.id()),
OSMNodeID(input_way.nodes().back().ref()),
OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
OSMNodeID(input_way.nodes()[1].ref()),
OSMNodeID(input_way.nodes()[0].ref())});
}
}
+230
View File
@@ -0,0 +1,230 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "extractor_options.hpp"
#include "util/version.hpp"
#include "../util/ini_file.hpp"
#include "../util/simple_logger.hpp"
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <tbb/task_scheduler_init.h>
return_code
ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config)
{
// declare a group of options that will be allowed only on command line
boost::program_options::options_description generic_options("Options");
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
/*
* TODO: re-enable this
"restrictions,r",
boost::program_options::value<boost::filesystem::path>(&extractor_config.restrictions_path),
"Restrictions file in .osrm.restrictions format")(
*/
"config,c", boost::program_options::value<boost::filesystem::path>(
&extractor_config.config_file_path)->default_value("extractor.ini"),
"Path to a configuration file.");
// declare a group of options that will be allowed both on command line and in config file
boost::program_options::options_description config_options("Configuration");
config_options.add_options()("profile,p",
boost::program_options::value<boost::filesystem::path>(
&extractor_config.profile_path)->default_value("profile.lua"),
"Path to LUA routing profile")(
"threads,t",
boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
->default_value(tbb::task_scheduler_init::default_num_threads()),
"Number of threads to use")(
"generate-edge-lookup",boost::program_options::value<bool>(
&extractor_config.generate_edge_lookup)->implicit_value(true)->default_value(false),
"Generate a lookup table for internal edge-expanded-edge IDs to OSM node pairs")(
"small-component-size",
boost::program_options::value<unsigned int>(&extractor_config.small_component_size)
->default_value(1000),
"Number of nodes required before a strongly-connected-componennt is considered big (affects nearest neighbor snapping)");
#ifdef DEBUG_GEOMETRY
config_options.add_options()("debug-turns",
boost::program_options::value<std::string>(&extractor_config.debug_turns_path),
"Write out GeoJSON with turn penalty data");
#endif // DEBUG_GEOMETRY
// hidden options, will be allowed both on command line and in config file, but will not be
// shown to the user
boost::program_options::options_description hidden_options("Hidden options");
hidden_options.add_options()("input,i", boost::program_options::value<boost::filesystem::path>(
&extractor_config.input_path),
"Input file in .osm, .osm.bz2 or .osm.pbf format");
// positional option
boost::program_options::positional_options_description positional_options;
positional_options.add("input", 1);
// combine above options for parsing
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
boost::program_options::options_description config_file_options;
config_file_options.add(config_options).add(hidden_options);
boost::program_options::options_description visible_options(
boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
visible_options.add(generic_options).add(config_options);
// parse command line options
try
{
boost::program_options::variables_map option_variables;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
.options(cmdline_options)
.positional(positional_options)
.run(),
option_variables);
if (option_variables.count("version"))
{
SimpleLogger().Write() << OSRM_VERSION;
return return_code::exit;
}
if (option_variables.count("help"))
{
SimpleLogger().Write() << visible_options;
return return_code::exit;
}
boost::program_options::notify(option_variables);
// parse config file
if (boost::filesystem::is_regular_file(extractor_config.config_file_path))
{
SimpleLogger().Write()
<< "Reading options from: " << extractor_config.config_file_path.string();
std::string ini_file_contents =
read_file_lower_content(extractor_config.config_file_path);
std::stringstream config_stream(ini_file_contents);
boost::program_options::store(parse_config_file(config_stream, config_file_options),
option_variables);
boost::program_options::notify(option_variables);
}
if (!option_variables.count("input"))
{
SimpleLogger().Write() << visible_options;
return return_code::exit;
}
}
catch (std::exception &e)
{
SimpleLogger().Write(logWARNING) << e.what();
return return_code::fail;
}
return return_code::ok;
}
void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_config)
{
boost::filesystem::path &input_path = extractor_config.input_path;
extractor_config.output_file_name = input_path.string();
extractor_config.restriction_file_name = input_path.string();
extractor_config.names_file_name = input_path.string();
extractor_config.timestamp_file_name = input_path.string();
extractor_config.geometry_output_path = input_path.string();
extractor_config.edge_output_path = input_path.string();
extractor_config.edge_graph_output_path = input_path.string();
extractor_config.node_output_path = input_path.string();
extractor_config.rtree_nodes_output_path = input_path.string();
extractor_config.rtree_leafs_output_path = input_path.string();
extractor_config.edge_segment_lookup_path = input_path.string();
extractor_config.edge_penalty_path = input_path.string();
std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
if (pos == std::string::npos)
{
pos = extractor_config.output_file_name.find(".osm.pbf");
if (pos == std::string::npos)
{
pos = extractor_config.output_file_name.find(".osm.xml");
}
}
if (pos == std::string::npos)
{
pos = extractor_config.output_file_name.find(".pbf");
}
if (pos == std::string::npos)
{
pos = extractor_config.output_file_name.find(".osm");
if (pos == std::string::npos)
{
extractor_config.output_file_name.append(".osrm");
extractor_config.restriction_file_name.append(".osrm.restrictions");
extractor_config.names_file_name.append(".osrm.names");
extractor_config.timestamp_file_name.append(".osrm.timestamp");
extractor_config.geometry_output_path.append(".osrm.geometry");
extractor_config.node_output_path.append(".osrm.nodes");
extractor_config.edge_output_path.append(".osrm.edges");
extractor_config.edge_graph_output_path.append(".osrm.ebg");
extractor_config.rtree_nodes_output_path.append(".osrm.ramIndex");
extractor_config.rtree_leafs_output_path.append(".osrm.fileIndex");
extractor_config.edge_segment_lookup_path.append(".osrm.edge_segment_lookup");
extractor_config.edge_penalty_path.append(".osrm.edge_penalties");
}
else
{
extractor_config.output_file_name.replace(pos, 5, ".osrm");
extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
extractor_config.names_file_name.replace(pos, 5, ".osrm.names");
extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
extractor_config.geometry_output_path.replace(pos, 5, ".osrm.geometry");
extractor_config.node_output_path.replace(pos, 5, ".osrm.nodes");
extractor_config.edge_output_path.replace(pos, 5, ".osrm.edges");
extractor_config.edge_graph_output_path.replace(pos, 5, ".osrm.ebg");
extractor_config.rtree_nodes_output_path.replace(pos, 5, ".osrm.ramIndex");
extractor_config.rtree_leafs_output_path.replace(pos, 5, ".osrm.fileIndex");
extractor_config.edge_segment_lookup_path.replace(pos,5, ".osrm.edge_segment_lookup");
extractor_config.edge_penalty_path.replace(pos,5, ".osrm.edge_penalties");
}
}
else
{
extractor_config.output_file_name.replace(pos, 8, ".osrm");
extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
extractor_config.names_file_name.replace(pos, 8, ".osrm.names");
extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
extractor_config.geometry_output_path.replace(pos, 8, ".osrm.geometry");
extractor_config.node_output_path.replace(pos, 8, ".osrm.nodes");
extractor_config.edge_output_path.replace(pos, 8, ".osrm.edges");
extractor_config.edge_graph_output_path.replace(pos, 8, ".osrm.ebg");
extractor_config.rtree_nodes_output_path.replace(pos, 8, ".osrm.ramIndex");
extractor_config.rtree_leafs_output_path.replace(pos, 8, ".osrm.fileIndex");
extractor_config.edge_segment_lookup_path.replace(pos,8, ".osrm.edge_segment_lookup");
extractor_config.edge_penalty_path.replace(pos,8, ".osrm.edge_penalties");
}
}
+188
View File
@@ -0,0 +1,188 @@
#include "graph_compressor.hpp"
#include "../data_structures/compressed_edge_container.hpp"
#include "../data_structures/dynamic_graph.hpp"
#include "../data_structures/node_based_graph.hpp"
#include "../data_structures/restriction_map.hpp"
#include "../data_structures/percent.hpp"
#include "../util/simple_logger.hpp"
GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
: speed_profile(std::move(speed_profile))
{
}
void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
const std::unordered_set<NodeID>& traffic_lights,
RestrictionMap& restriction_map,
NodeBasedDynamicGraph& graph,
CompressedEdgeContainer& geometry_compressor)
{
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
Percent progress(original_number_of_nodes);
for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
{
progress.printStatus(node_v);
// only contract degree 2 vertices
if (2 != graph.GetOutDegree(node_v))
{
continue;
}
// don't contract barrier node
if (barrier_nodes.end() != barrier_nodes.find(node_v))
{
continue;
}
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
if (restriction_map.IsViaNode(node_v))
{
continue;
}
// reverse_e2 forward_e2
// u <---------- v -----------> w
// ----------> <-----------
// forward_e1 reverse_e1
//
// Will be compressed to:
//
// reverse_e1
// u <---------- w
// ---------->
// forward_e1
//
// If the edges are compatible.
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
forward_e2 < graph.EndEdges(node_v));
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
reverse_e2 < graph.EndEdges(node_v));
const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
const NodeID node_w = graph.GetTarget(forward_e2);
BOOST_ASSERT(SPECIAL_NODEID != node_w);
BOOST_ASSERT(node_v != node_w);
const NodeID node_u = graph.GetTarget(reverse_e2);
BOOST_ASSERT(SPECIAL_NODEID != node_u);
BOOST_ASSERT(node_u != node_v);
const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));
const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
{
continue;
}
// this case can happen if two ways with different names overlap
if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
fwd_edge_data2.name_id != rev_edge_data2.name_id)
{
continue;
}
if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
{
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
graph.GetEdgeData(reverse_e1).name_id);
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
graph.GetEdgeData(reverse_e2).name_id);
// Get distances before graph is modified
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
BOOST_ASSERT(0 != forward_weight1);
BOOST_ASSERT(0 != forward_weight2);
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != reverse_weight2);
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
// add weight of e2's to e1
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
if (has_node_penalty)
{
graph.GetEdgeData(forward_e1).distance +=
speed_profile.traffic_signal_penalty;
graph.GetEdgeData(reverse_e1).distance +=
speed_profile.traffic_signal_penalty;
}
// extend e1's to targets of e2's
graph.SetTarget(forward_e1, node_w);
graph.SetTarget(reverse_e1, node_u);
// remove e2's (if bidir, otherwise only one)
graph.DeleteEdge(node_v, forward_e2);
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);
// store compressed geometry in container
geometry_compressor.CompressEdge(
forward_e1, forward_e2, node_v, node_w,
forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
forward_weight2);
geometry_compressor.CompressEdge(
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
}
}
PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
}
void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
unsigned original_number_of_edges,
const NodeBasedDynamicGraph& graph) const
{
unsigned new_node_count = 0;
unsigned new_edge_count = 0;
for (const auto i : osrm::irange(0u, graph.GetNumberOfNodes()))
{
if (graph.GetOutDegree(i) > 0)
{
++new_node_count;
new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
}
}
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;
}
+113
View File
@@ -0,0 +1,113 @@
/*
Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "import_edge.hpp"
#include "travel_mode.hpp"
#include "../typedefs.h"
bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
{
if (source == other.source)
{
if (target == other.target)
{
if (weight == other.weight)
{
return forward && backward && ((!other.forward) || (!other.backward));
}
return weight < other.weight;
}
return target < other.target;
}
return source < other.source;
}
NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
backward(false), roundabout(false),
access_restricted(false), startpoint(true), is_split(false), travel_mode(false)
{
}
NodeBasedEdge::NodeBasedEdge(NodeID source,
NodeID target,
NodeID name_id,
EdgeWeight weight,
bool forward,
bool backward,
bool roundabout,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split)
: source(source), target(target), name_id(name_id), weight(weight), forward(forward),
backward(backward), roundabout(roundabout),
access_restricted(access_restricted), startpoint(startpoint), is_split(is_split), travel_mode(travel_mode)
{
}
bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
{
if (source == other.source)
{
if (target == other.target)
{
if (weight == other.weight)
{
return forward && backward && ((!other.forward) || (!other.backward));
}
return weight < other.weight;
}
return target < other.target;
}
return source < other.source;
}
template <class EdgeT>
EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
: source(other.source), target(other.target), edge_id(other.data.via),
weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
{
}
/** Default constructor. target and weight are set to 0.*/
EdgeBasedEdge::EdgeBasedEdge()
: source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
{
}
EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
const NodeID target,
const NodeID edge_id,
const EdgeWeight weight,
const bool forward,
const bool backward)
: source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
backward(backward)
{
}
+178
View File
@@ -0,0 +1,178 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "raster_source.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include <osrm/coordinate.hpp>
#include <cmath>
RasterSource::RasterSource(RasterGrid _raster_data,
std::size_t _width,
std::size_t _height,
int _xmin,
int _xmax,
int _ymin,
int _ymax)
: xstep(calcSize(_xmin, _xmax, _width)), ystep(calcSize(_ymin, _ymax, _height)),
raster_data(std::move(_raster_data)), width(_width), height(_height), xmin(_xmin),
xmax(_xmax), ymin(_ymin), ymax(_ymax)
{
BOOST_ASSERT(xstep != 0);
BOOST_ASSERT(ystep != 0);
}
float RasterSource::calcSize(int min, int max, std::size_t count) const
{
BOOST_ASSERT(count > 0);
return (max - min) / (static_cast<float>(count) - 1);
}
// Query raster source for nearest data point
RasterDatum RasterSource::getRasterData(const int lon, const int lat) const
{
if (lon < xmin || lon > xmax || lat < ymin || lat > ymax)
{
return {};
}
const std::size_t xth = static_cast<std::size_t>(round((lon - xmin) / xstep));
const std::size_t yth = static_cast<std::size_t>(round((ymax - lat) / ystep));
return {raster_data(xth, yth)};
}
// Query raster source using bilinear interpolation
RasterDatum RasterSource::getRasterInterpolate(const int lon, const int lat) const
{
if (lon < xmin || lon > xmax || lat < ymin || lat > ymax)
{
return {};
}
const auto xthP = (lon - xmin) / xstep;
const auto ythP = (ymax - lat) / ystep;
const std::size_t top = static_cast<std::size_t>(fmax(floor(ythP), 0));
const std::size_t bottom = static_cast<std::size_t>(fmin(ceil(ythP), height - 1));
const std::size_t left = static_cast<std::size_t>(fmax(floor(xthP), 0));
const std::size_t right = static_cast<std::size_t>(fmin(ceil(xthP), width - 1));
// Calculate distances from corners for bilinear interpolation
const float fromLeft = (lon - left * xstep + xmin) / xstep;
const float fromTop = (ymax - top * ystep - lat) / ystep;
const float fromRight = 1 - fromLeft;
const float fromBottom = 1 - fromTop;
return {static_cast<std::int32_t>(raster_data(left, top) * (fromRight * fromBottom) +
raster_data(right, top) * (fromLeft * fromBottom) +
raster_data(left, bottom) * (fromRight * fromTop) +
raster_data(right, bottom) * (fromLeft * fromTop))};
}
// Load raster source into memory
int SourceContainer::loadRasterSource(const std::string &path_string,
double xmin,
double xmax,
double ymin,
double ymax,
std::size_t nrows,
std::size_t ncols)
{
const auto _xmin = static_cast<int>(xmin * COORDINATE_PRECISION);
const auto _xmax = static_cast<int>(xmax * COORDINATE_PRECISION);
const auto _ymin = static_cast<int>(ymin * COORDINATE_PRECISION);
const auto _ymax = static_cast<int>(ymax * COORDINATE_PRECISION);
const auto itr = LoadedSourcePaths.find(path_string);
if (itr != LoadedSourcePaths.end())
{
SimpleLogger().Write() << "[source loader] Already loaded source '" << path_string
<< "' at source_id " << itr->second;
return itr->second;
}
int source_id = static_cast<int>(LoadedSources.size());
SimpleLogger().Write() << "[source loader] Loading from " << path_string << " ... ";
TIMER_START(loading_source);
boost::filesystem::path filepath(path_string);
if (!boost::filesystem::exists(filepath))
{
throw osrm::exception("error reading: no such path");
}
RasterGrid rasterData{filepath, ncols, nrows};
RasterSource source{std::move(rasterData), ncols, nrows, _xmin, _xmax, _ymin, _ymax};
TIMER_STOP(loading_source);
LoadedSourcePaths.emplace(path_string, source_id);
LoadedSources.push_back(std::move(source));
SimpleLogger().Write() << "[source loader] ok, after " << TIMER_SEC(loading_source) << "s";
return source_id;
}
// External function for looking up nearest data point from a specified source
RasterDatum SourceContainer::getRasterDataFromSource(unsigned int source_id, int lon, int lat)
{
if (LoadedSources.size() < source_id + 1)
{
throw osrm::exception("error reading: no such loaded source");
}
BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
const auto &found = LoadedSources[source_id];
return found.getRasterData(lon, lat);
}
// External function for looking up interpolated data from a specified source
RasterDatum
SourceContainer::getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat)
{
if (LoadedSources.size() < source_id + 1)
{
throw osrm::exception("error reading: no such loaded source");
}
BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
const auto &found = LoadedSources[source_id];
return found.getRasterInterpolate(lon, lat);
}
+184
View File
@@ -0,0 +1,184 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "restriction_map.hpp"
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
{
// decompose restriction consisting of a start, via and end node into a
// a pair of starting edge and a list of all end nodes
for (auto &restriction : restriction_list)
{
// 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);
// 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)};
std::size_t index;
auto restriction_iter = m_restriction_map.find(restriction_source);
if (restriction_iter == m_restriction_map.end())
{
index = m_restriction_bucket_list.size();
m_restriction_bucket_list.resize(index + 1);
m_restriction_map.emplace(restriction_source, index);
}
else
{
index = restriction_iter->second;
// Map already contains an is_only_*-restriction
if (m_restriction_bucket_list.at(index).begin()->is_only)
{
continue;
}
else if (restriction.flags.is_only)
{
// We are going to insert an is_only_*-restriction. There can be only one.
m_count -= m_restriction_bucket_list.at(index).size();
m_restriction_bucket_list.at(index).clear();
}
}
++m_count;
BOOST_ASSERT(restriction.to.node < std::numeric_limits<NodeID>::max());
m_restriction_bucket_list.at(index)
.emplace_back(restriction.to.node, restriction.flags.is_only);
}
}
bool RestrictionMap::IsViaNode(const NodeID node) const
{
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
}
// Replaces start edge (v, w) with (u, w). Only start node changes.
void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
const NodeID node_v,
const NodeID node_w)
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
if (!IsSourceNode(node_v))
{
return;
}
const auto restriction_iterator = m_restriction_map.find({node_v, node_w});
if (restriction_iterator != m_restriction_map.end())
{
const unsigned index = restriction_iterator->second;
// remove old restriction start (v,w)
m_restriction_map.erase(restriction_iterator);
m_restriction_start_nodes.emplace(node_u);
// insert new restriction start (u,w) (pointing to index)
RestrictionSource new_source = {node_u, node_w};
m_restriction_map.emplace(new_source, index);
}
}
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return SPECIAL_NODEID;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter != m_restriction_map.end())
{
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (restriction_target.is_only)
{
return restriction_target.target_node;
}
}
}
return SPECIAL_NODEID;
}
// Checks if turn <u,v,w> is actually a turn restriction.
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
const NodeID node_v,
const NodeID node_w) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return false;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter == m_restriction_map.end())
{
return false;
}
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (node_w == restriction_target.target_node && // target found
!restriction_target.is_only) // and not an only_-restr.
{
return true;
}
if (node_w != restriction_target.target_node && // target not found
restriction_target.is_only) // and is an only restriction
{
return true;
}
}
return false;
}
// check of node is the start of any restriction
bool RestrictionMap::IsSourceNode(const NodeID node) const
{
if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
{
return false;
}
return true;
}
+256
View File
@@ -0,0 +1,256 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "restriction_parser.hpp"
#include "extraction_way.hpp"
#include "../data_structures/external_memory_node.hpp"
#include "../util/lua_util.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/ref.hpp>
#include <boost/regex.hpp>
#include <boost/optional/optional.hpp>
#include <osmium/osm.hpp>
#include <osmium/tags/regex_filter.hpp>
#include <algorithm>
#include <iterator>
namespace
{
int lua_error_callback(lua_State *lua_state)
{
std::string error_msg = lua_tostring(lua_state, -1);
throw osrm::exception("ERROR occurred in profile script:\n" + error_msg);
}
}
RestrictionParser::RestrictionParser(lua_State *lua_state) : use_turn_restrictions(true)
{
ReadUseRestrictionsSetting(lua_state);
if (use_turn_restrictions)
{
ReadRestrictionExceptions(lua_state);
}
}
void RestrictionParser::ReadUseRestrictionsSetting(lua_State *lua_state)
{
if (0 == luaL_dostring(lua_state, "return use_turn_restrictions\n") &&
lua_isboolean(lua_state, -1))
{
use_turn_restrictions = lua_toboolean(lua_state, -1);
}
if (use_turn_restrictions)
{
SimpleLogger().Write() << "Using turn restrictions";
}
else
{
SimpleLogger().Write() << "Ignoring turn restrictions";
}
}
void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
{
if (lua_function_exists(lua_state, "get_exceptions"))
{
luabind::set_pcall_callback(&lua_error_callback);
// get list of turn restriction exceptions
luabind::call_function<void>(lua_state, "get_exceptions",
boost::ref(restriction_exceptions));
const unsigned exception_count = restriction_exceptions.size();
SimpleLogger().Write() << "Found " << exception_count
<< " exceptions to turn restrictions:";
for (const std::string &str : restriction_exceptions)
{
SimpleLogger().Write() << " " << str;
}
}
else
{
SimpleLogger().Write() << "Found no exceptions to turn restrictions";
}
}
/**
* Tries to parse an relation as turn restriction. This can fail for a number of
* reasons, this the return type is a boost::optional<T>.
*
* Some restrictions can also be ignored: See the ```get_exceptions``` function
* in the corresponding profile.
*/
boost::optional<InputRestrictionContainer>
RestrictionParser::TryParse(const osmium::Relation &relation) const
{
// return if turn restrictions should be ignored
if (!use_turn_restrictions)
{
return {};
}
osmium::tags::KeyPrefixFilter filter(false);
filter.add(true, "restriction");
const osmium::TagList &tag_list = relation.tags();
osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
// if it's a restriction, continue;
if (std::distance(fi_begin, fi_end) == 0)
{
return {};
}
// check if the restriction should be ignored
const char *except = relation.get_value_by_key("except");
if (except != nullptr && ShouldIgnoreRestriction(except))
{
return {};
}
bool is_only_restriction = false;
for (; fi_begin != fi_end; ++fi_begin)
{
const std::string key(fi_begin->key());
const std::string value(fi_begin->value());
if (value.find("only_") == 0)
{
is_only_restriction = true;
}
// if the "restriction*" key is longer than 11 chars, it is a conditional exception (i.e.
// "restriction:<transportation_type>")
if (key.size() > 11)
{
const auto ex_suffix = [&](const std::string &exception)
{
return boost::algorithm::ends_with(key, exception);
};
bool is_actually_restricted =
std::any_of(begin(restriction_exceptions), end(restriction_exceptions), ex_suffix);
if (!is_actually_restricted)
{
return {};
}
}
}
InputRestrictionContainer restriction_container(is_only_restriction);
for (const auto &member : relation.members())
{
const char *role = member.role();
if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
{
continue;
}
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));
// 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();
}
else if (0 == strcmp("to", role))
{
restriction_container.restriction.to.way = member.ref();
}
// 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...
break;
default:
// shouldn't ever happen
break;
}
}
return boost::make_optional(std::move(restriction_container));
}
bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
{
// should this restriction be ignored? yes if there's an overlap between:
// a) the list of modes in the except tag of the restriction
// (except_tag_string), eg: except=bus;bicycle
// b) the lua profile defines a hierachy of modes,
// eg: [access, vehicle, bicycle]
if (except_tag_string.empty())
{
return false;
}
// Be warned, this is quadratic work here, but we assume that
// only a few exceptions are actually defined.
std::vector<std::string> exceptions;
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
return std::any_of(std::begin(exceptions), std::end(exceptions),
[&](const std::string &current_string)
{
if (std::end(restriction_exceptions) !=
std::find(std::begin(restriction_exceptions),
std::end(restriction_exceptions), current_string))
{
return true;
}
return false;
});
}
+175
View File
@@ -0,0 +1,175 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
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.
*/
#include "scripting_environment.hpp"
#include "extraction_helper_functions.hpp"
#include "extraction_node.hpp"
#include "extraction_way.hpp"
#include "internal_extractor_edge.hpp"
#include "../data_structures/external_memory_node.hpp"
#include "../data_structures/raster_source.hpp"
#include "../util/lua_util.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../typedefs.h"
#include <luabind/tag_function.hpp>
#include <luabind/operator.hpp>
#include <osmium/osm.hpp>
#include <sstream>
namespace
{
// wrapper method as luabind doesn't automatically overload funcs w/ default parameters
template <class T>
auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_value_by_key(key))
{
return object.get_value_by_key(key, "");
}
int lua_error_callback(lua_State *L) // This is so I can use my own function as an
// exception handler, pcall_log()
{
std::string error_msg = lua_tostring(L, -1);
std::ostringstream error_stream;
error_stream << error_msg;
throw osrm::exception("ERROR occurred in profile script:\n" + error_stream.str());
}
}
ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name) : file_name(file_name)
{
SimpleLogger().Write() << "Using script " << file_name;
}
void ScriptingEnvironment::init_lua_state(lua_State *lua_state)
{
typedef double (osmium::Location::*location_member_ptr_type)() const;
luabind::open(lua_state);
// open utility libraries string library;
luaL_openlibs(lua_state);
luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
// Add our function to the state's global scope
luabind::module(lua_state)[
luabind::def("print", LUA_print<std::string>),
luabind::def("durationIsValid", durationIsValid),
luabind::def("parseDuration", parseDuration),
luabind::class_<SourceContainer>("sources")
.def(luabind::constructor<>())
.def("load", &SourceContainer::loadRasterSource)
.def("query", &SourceContainer::getRasterDataFromSource)
.def("interpolate", &SourceContainer::getRasterInterpolateFromSource),
luabind::class_<const float>("constants")
.enum_("enums")[luabind::value("precision", COORDINATE_PRECISION)],
luabind::class_<std::vector<std::string>>("vector")
.def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(
&std::vector<std::string>::push_back)),
luabind::class_<osmium::Location>("Location")
.def<location_member_ptr_type>("lat", &osmium::Location::lat)
.def<location_member_ptr_type>("lon", &osmium::Location::lon),
luabind::class_<osmium::Node>("Node")
// .def<node_member_ptr_type>("tags", &osmium::Node::tags)
.def("location", &osmium::Node::location)
.def("get_value_by_key", &osmium::Node::get_value_by_key)
.def("get_value_by_key", &get_value_by_key<osmium::Node>)
.def("id", &osmium::Node::id),
luabind::class_<ExtractionNode>("ResultNode")
.def_readwrite("traffic_lights", &ExtractionNode::traffic_lights)
.def_readwrite("barrier", &ExtractionNode::barrier),
luabind::class_<ExtractionWay>("ResultWay")
// .def(luabind::constructor<>())
.def_readwrite("forward_speed", &ExtractionWay::forward_speed)
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
.def_readwrite("name", &ExtractionWay::name)
.def_readwrite("roundabout", &ExtractionWay::roundabout)
.def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
.def_readwrite("is_startpoint", &ExtractionWay::is_startpoint)
.def_readwrite("duration", &ExtractionWay::duration)
.property("forward_mode", &ExtractionWay::get_forward_mode,
&ExtractionWay::set_forward_mode)
.property("backward_mode", &ExtractionWay::get_backward_mode,
&ExtractionWay::set_backward_mode)
.enum_("constants")[
luabind::value("notSure", 0),
luabind::value("oneway", 1),
luabind::value("bidirectional", 2),
luabind::value("opposite", 3)
],
luabind::class_<osmium::Way>("Way")
.def("get_value_by_key", &osmium::Way::get_value_by_key)
.def("get_value_by_key", &get_value_by_key<osmium::Way>)
.def("id", &osmium::Way::id),
luabind::class_<InternalExtractorEdge>("EdgeSource")
.property("source_coordinate", &InternalExtractorEdge::source_coordinate)
.property("weight_data", &InternalExtractorEdge::weight_data),
luabind::class_<InternalExtractorEdge::WeightData>("WeightData")
.def_readwrite("speed", &InternalExtractorEdge::WeightData::speed),
luabind::class_<ExternalMemoryNode>("EdgeTarget")
.property("lat", &ExternalMemoryNode::lat)
.property("lon", &ExternalMemoryNode::lon),
luabind::class_<FixedPointCoordinate>("Coordinate")
.property("lat", &FixedPointCoordinate::lat)
.property("lon", &FixedPointCoordinate::lon),
luabind::class_<RasterDatum>("RasterDatum")
.property("datum", &RasterDatum::datum)
.def("invalid_data", &RasterDatum::get_invalid)
];
if (0 != luaL_dofile(lua_state, file_name.c_str()))
{
luabind::object error_msg(luabind::from_stack(lua_state, -1));
std::ostringstream error_stream;
error_stream << error_msg;
throw osrm::exception("ERROR occurred in profile script:\n" + error_stream.str());
}
}
lua_State *ScriptingEnvironment::get_lua_state()
{
std::lock_guard<std::mutex> lock(init_mutex);
bool initialized = false;
auto &ref = script_contexts.local(initialized);
if (!initialized)
{
std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
ref = state;
init_lua_state(ref.get());
}
luabind::set_pcall_callback(&lua_error_callback);
return ref.get();
}