Fix routing when start and target are on the same segment
Fixes issue #1864. Given the simple set-up: a --> b --> c ^-----------| This would translate into an edge based graph (ab) -> (bc), (bc) -> (ca), (ca) -> (ab). Starting at the end of the one-way street (ab) and going to the beginning, the query has to find a self-loop within the graph (ab) -> (bc) -> (ca) -> (ab), as both nodes map to the same segment (ab).
This commit is contained in:
parent
238e77d959
commit
1c1bfd7541
@ -44,7 +44,7 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
||||
COMMENT "Configuring revision fingerprint"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests)
|
||||
add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests io-tests)
|
||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
||||
@ -61,6 +61,7 @@ file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
|
||||
file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
|
||||
file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
|
||||
file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
|
||||
file(GLOB IOTestsGlob unit_tests/io/*.cpp)
|
||||
|
||||
add_library(UTIL OBJECT ${UtilGlob})
|
||||
add_library(EXTRACTOR OBJECT ${ExtractorGlob})
|
||||
@ -85,6 +86,7 @@ target_link_libraries(osrm-routed OSRM)
|
||||
add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:GRAPH>)
|
||||
add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:PHANTOM> $<TARGET_OBJECTS:UTIL>)
|
||||
add_executable(io-tests EXCLUDE_FROM_ALL unit_tests/io_tests.cpp ${IOTestsGlob} $<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
# Benchmarks
|
||||
add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:PHANTOM>)
|
||||
@ -248,6 +250,7 @@ target_link_libraries(engine-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(extractor-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(util-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${Boost_LIBRARIES})
|
||||
target_link_libraries(io-tests ${Boost_LIBRARIES})
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
@ -263,7 +263,7 @@ def extract_data
|
||||
raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
|
||||
end
|
||||
begin
|
||||
["osrm","osrm.names","osrm.restrictions","osrm.ebg","osrm.edges","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
|
||||
["osrm","osrm.names","osrm.restrictions","osrm.ebg","osrm.enw","osrm.edges","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
|
||||
log "Renaming #{osm_file}.#{file} to #{extracted_file}.#{file}", :preprocess
|
||||
File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}"
|
||||
end
|
||||
|
@ -136,7 +136,7 @@ Feature: Basic Distance Matrix
|
||||
| a | 100 | 200 | 300 |
|
||||
| b | 0 | 100 | 200 |
|
||||
|
||||
Scenario: Testbog - All coordinates are from same small component
|
||||
Scenario: Testbot - All coordinates are from same small component
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the node map
|
||||
@ -156,7 +156,7 @@ Feature: Basic Distance Matrix
|
||||
| f | 0 | 300 |
|
||||
| g | 300 | 0 |
|
||||
|
||||
Scenario: Testbog - Coordinates are from different small component and snap to big CC
|
||||
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the node map
|
||||
@ -179,3 +179,21 @@ Feature: Basic Distance Matrix
|
||||
| h | 0 | 300 | 0 | 300 |
|
||||
| i | 300 | 0 | 300 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix with loops
|
||||
Given the node map
|
||||
| a | 1 | 2 | b |
|
||||
| d | 4 | 3 | c |
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
| cd | yes |
|
||||
| da | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 100 +-1 | 400 +-1 | 500 +-1 |
|
||||
| 2 | 700 +-1 | 0 | 300 +-1 | 400 +-1 |
|
||||
| 3 | 400 +-1 | 500 +-1 | 0 | 100 +-1 |
|
||||
| 4 | 300 +-1 | 400 +-1 | 700 +-1 | 0 |
|
||||
|
@ -93,8 +93,6 @@ Feature: Via points
|
||||
| 1,3,2 | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
|
||||
| 3,2,1 | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
|
||||
|
||||
# TODO: Remove this ignore when https://github.com/Project-OSRM/osrm-backend/issues/1863 gets fixed
|
||||
@ignore-platform-mac
|
||||
Scenario: Via points on ring on the same oneway
|
||||
# xa it to avoid only having a single ring, which cna trigger edge cases
|
||||
Given the node map
|
||||
@ -118,7 +116,6 @@ Feature: Via points
|
||||
| 1,3,2 | ab,ab,bc,cd,da,ab | 1100m +-1 | head,via,right,right,right,right,destination |
|
||||
| 3,2,1 | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m | head,right,right,right,right,via,right,right,right,right,destination |
|
||||
|
||||
|
||||
# See issue #1896
|
||||
Scenario: Via point at a dead end with oneway
|
||||
Given the node map
|
||||
@ -162,3 +159,45 @@ Feature: Via points
|
||||
| waypoints | route |
|
||||
| a,1,c | abc,bd,bd,bd,abc |
|
||||
| c,1,a | abc,bd,bd,bd,abc |
|
||||
|
||||
Scenario: Via points on ring on the same oneway, forces one of the vertices to be top node
|
||||
Given the node map
|
||||
| a | 1 | 2 | b |
|
||||
| 8 | | | 3 |
|
||||
| 7 | | | 4 |
|
||||
| d | 6 | 5 | c |
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
| cd | yes |
|
||||
| da | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | distance | turns |
|
||||
| 2,1 | ab,bc,cd,da,ab | 1100m +-1 | head,right,right,right,right,destination |
|
||||
| 4,3 | bc,cd,da,ab,bc | 1100m +-1 | head,right,right,right,right,destination |
|
||||
| 6,5 | cd,da,ab,bc,cd | 1100m +-1 | head,right,right,right,right,destination |
|
||||
| 8,7 | da,ab,bc,cd,da | 1100m +-1 | head,right,right,right,right,destination |
|
||||
|
||||
Scenario: Multiple Via points on ring on the same oneway, forces one of the vertices to be top node
|
||||
Given the node map
|
||||
| a | 1 | 2 | 3 | b |
|
||||
| | | | | 4 |
|
||||
| | | | | 5 |
|
||||
| | | | | 6 |
|
||||
| d | 9 | 8 | 7 | c |
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
| cd | yes |
|
||||
| da | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | distance | turns |
|
||||
| 3,2,1 | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 3000m +-1 | head,right,right,right,right,via,right,right,right,right,destination |
|
||||
| 6,5,4 | bc,cd,da,ab,bc,bc,cd,da,ab,bc | 3000m +-1 | head,right,right,right,right,via,right,right,right,right,destination |
|
||||
| 9,8,7 | cd,da,ab,bc,cd,cd,da,ab,bc,cd | 3000m +-1 | head,right,right,right,right,via,right,right,right,right,destination |
|
||||
|
@ -145,8 +145,11 @@ class Contractor
|
||||
}
|
||||
|
||||
template <class ContainerT>
|
||||
Contractor(int nodes, ContainerT &input_edge_list, std::vector<float> &&node_levels_)
|
||||
: node_levels(std::move(node_levels_))
|
||||
Contractor(int nodes,
|
||||
ContainerT &input_edge_list,
|
||||
std::vector<float> &&node_levels_,
|
||||
std::vector<EdgeWeight> &&node_weights_)
|
||||
: node_levels(std::move(node_levels_)), node_weights(std::move(node_weights_))
|
||||
{
|
||||
std::vector<ContractorEdge> edges;
|
||||
edges.reserve(input_edge_list.size() * 2);
|
||||
@ -203,8 +206,7 @@ class Contractor
|
||||
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
|
||||
forward_edge.data.id = reverse_edge.data.id = id;
|
||||
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
|
||||
forward_edge.data.distance = reverse_edge.data.distance =
|
||||
std::numeric_limits<int>::max();
|
||||
forward_edge.data.distance = reverse_edge.data.distance = INVALID_EDGE_WEIGHT;
|
||||
// remove parallel edges
|
||||
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
|
||||
{
|
||||
@ -223,7 +225,7 @@ class Contractor
|
||||
// merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if (forward_edge.data.distance == reverse_edge.data.distance)
|
||||
{
|
||||
if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
|
||||
if ((int)forward_edge.data.distance != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
forward_edge.data.backward = true;
|
||||
edges[edge++] = forward_edge;
|
||||
@ -231,11 +233,11 @@ class Contractor
|
||||
}
|
||||
else
|
||||
{ // insert seperate edges
|
||||
if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
|
||||
if (((int)forward_edge.data.distance) != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
edges[edge++] = forward_edge;
|
||||
}
|
||||
if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
|
||||
if ((int)reverse_edge.data.distance != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
edges[edge++] = reverse_edge;
|
||||
}
|
||||
@ -360,18 +362,21 @@ class Contractor
|
||||
|
||||
// Create new priority array
|
||||
std::vector<float> new_node_priority(remaining_nodes.size());
|
||||
std::vector<EdgeWeight> new_node_weights(remaining_nodes.size());
|
||||
// this map gives the old IDs from the new ones, necessary to get a consistent graph
|
||||
// at the end of contraction
|
||||
orig_node_id_from_new_node_id_map.resize(remaining_nodes.size());
|
||||
// this map gives the new IDs from the old ones, necessary to remap targets from the
|
||||
// remaining graph
|
||||
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
|
||||
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, SPECIAL_NODEID);
|
||||
|
||||
for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
|
||||
{
|
||||
auto &node = remaining_nodes[new_node_id];
|
||||
BOOST_ASSERT(node_priorities.size() > node.id);
|
||||
new_node_priority[new_node_id] = node_priorities[node.id];
|
||||
BOOST_ASSERT(node_weights.size() > node.id);
|
||||
new_node_weights[new_node_id] = node_weights[node.id];
|
||||
}
|
||||
|
||||
// build forward and backward renumbering map and remap ids in remaining_nodes
|
||||
@ -404,9 +409,9 @@ class Contractor
|
||||
new_node_id_from_orig_id_map[target], data};
|
||||
|
||||
new_edge.data.is_original_via_node_ID = true;
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
|
||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[source],
|
||||
"new source id not resolveable");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
|
||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[target],
|
||||
"new target id not resolveable");
|
||||
new_edge_set.push_back(new_edge);
|
||||
}
|
||||
@ -420,8 +425,12 @@ class Contractor
|
||||
// Replace old priorities array by new one
|
||||
node_priorities.swap(new_node_priority);
|
||||
// Delete old node_priorities vector
|
||||
// Due to the scope, these should get cleared automatically? @daniel-j-h do you
|
||||
// agree?
|
||||
new_node_priority.clear();
|
||||
new_node_priority.shrink_to_fit();
|
||||
|
||||
node_weights.swap(new_node_weights);
|
||||
// old Graph is removed
|
||||
contractor_graph.reset();
|
||||
|
||||
@ -581,7 +590,7 @@ class Contractor
|
||||
remaining_nodes.resize(begin_independent_nodes_idx);
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
// unsigned mindegree = SPECIAL_NODEID;
|
||||
// unsigned quaddegree = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
|
||||
@ -686,8 +695,8 @@ class Contractor
|
||||
new_edge.source = node;
|
||||
new_edge.target = target;
|
||||
}
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
|
||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.source, "Source id invalid");
|
||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
|
||||
new_edge.data.distance = data.distance;
|
||||
new_edge.data.shortcut = data.shortcut;
|
||||
if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty())
|
||||
@ -718,23 +727,55 @@ class Contractor
|
||||
}
|
||||
|
||||
private:
|
||||
inline void RelaxNode(const NodeID node,
|
||||
const NodeID forbidden_node,
|
||||
const int distance,
|
||||
ContractorHeap &heap)
|
||||
{
|
||||
const short current_hop = heap.GetData(node).hop + 1;
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
if (!data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID to = contractor_graph->GetTarget(edge);
|
||||
if (forbidden_node == to)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int to_distance = distance + data.distance;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < heap.GetKey(to))
|
||||
{
|
||||
heap.DecreaseKey(to, to_distance);
|
||||
heap.GetData(to).hop = current_hop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Dijkstra(const int max_distance,
|
||||
const unsigned number_of_targets,
|
||||
const int maxNodes,
|
||||
ContractorThreadData *const data,
|
||||
ContractorThreadData &data,
|
||||
const NodeID middleNode)
|
||||
{
|
||||
|
||||
ContractorHeap &heap = data->heap;
|
||||
ContractorHeap &heap = data.heap;
|
||||
|
||||
int nodes = 0;
|
||||
unsigned number_of_targets_found = 0;
|
||||
while (!heap.Empty())
|
||||
{
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey(node);
|
||||
const short current_hop = heap.GetData(node).hop + 1;
|
||||
|
||||
const auto distance = heap.GetKey(node);
|
||||
if (++nodes > maxNodes)
|
||||
{
|
||||
return;
|
||||
@ -754,33 +795,7 @@ class Contractor
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over all edges of node
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
if (!data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID to = contractor_graph->GetTarget(edge);
|
||||
if (middleNode == to)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int to_distance = distance + data.distance;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < heap.GetKey(to))
|
||||
{
|
||||
heap.DecreaseKey(to, to_distance);
|
||||
heap.GetData(to).hop = current_hop;
|
||||
}
|
||||
}
|
||||
RelaxNode(node, middleNode, distance, heap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,13 +830,21 @@ class Contractor
|
||||
ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
|
||||
{
|
||||
ContractorHeap &heap = data->heap;
|
||||
int inserted_edges_size = data->inserted_edges.size();
|
||||
std::size_t inserted_edges_size = data->inserted_edges.size();
|
||||
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
|
||||
const constexpr bool SHORTCUT_ARC = true;
|
||||
const constexpr bool FORWARD_DIRECTION_ENABLED = true;
|
||||
const constexpr bool FORWARD_DIRECTION_DISABLED = false;
|
||||
const constexpr bool REVERSE_DIRECTION_ENABLED = true;
|
||||
const constexpr bool REVERSE_DIRECTION_DISABLED = false;
|
||||
|
||||
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
|
||||
const NodeID source = contractor_graph->GetTarget(in_edge);
|
||||
if (source == node)
|
||||
continue;
|
||||
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
@ -846,22 +869,64 @@ class Contractor
|
||||
continue;
|
||||
}
|
||||
const NodeID target = contractor_graph->GetTarget(out_edge);
|
||||
const int path_distance = in_data.distance + out_data.distance;
|
||||
if (node == target)
|
||||
continue;
|
||||
|
||||
const EdgeWeight path_distance = in_data.distance + out_data.distance;
|
||||
if (target == source)
|
||||
{
|
||||
if (path_distance < node_weights[node])
|
||||
{
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
// make sure to prune better, but keep inserting this loop if it should
|
||||
// still be the best
|
||||
// CAREFUL: This only works due to the independent node-setting. This
|
||||
// guarantees that source is not connected to another node that is
|
||||
// contracted
|
||||
node_weights[source] = path_distance + 1;
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
stats->edges_added_count += 2;
|
||||
stats->original_edges_added_count +=
|
||||
2 * (out_data.originalEdges + in_data.originalEdges);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CAREFUL: This only works due to the independent node-setting. This
|
||||
// guarantees that source is not connected to another node that is
|
||||
// contracted
|
||||
node_weights[source] = path_distance; // make sure to prune better
|
||||
inserted_edges.emplace_back(
|
||||
source, target, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
|
||||
FORWARD_DIRECTION_ENABLED, REVERSE_DIRECTION_DISABLED);
|
||||
|
||||
inserted_edges.emplace_back(
|
||||
target, source, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
|
||||
FORWARD_DIRECTION_DISABLED, REVERSE_DIRECTION_ENABLED);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
max_distance = std::max(max_distance, path_distance);
|
||||
if (!heap.WasInserted(target))
|
||||
{
|
||||
heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
|
||||
heap.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData(0, true));
|
||||
++number_of_targets;
|
||||
}
|
||||
}
|
||||
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
Dijkstra(max_distance, number_of_targets, 1000, data, node);
|
||||
const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
|
||||
Dijkstra(max_distance, number_of_targets, SIMULATION_SEARCH_SPACE_SIZE, *data,
|
||||
node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Dijkstra(max_distance, number_of_targets, 2000, data, node);
|
||||
const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
|
||||
Dijkstra(max_distance, number_of_targets, FULL_SEARCH_SPACE_SIZE, *data, node);
|
||||
}
|
||||
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
@ -871,6 +936,8 @@ class Contractor
|
||||
continue;
|
||||
}
|
||||
const NodeID target = contractor_graph->GetTarget(out_edge);
|
||||
if (target == node)
|
||||
continue;
|
||||
const int path_distance = in_data.distance + out_data.distance;
|
||||
const int distance = heap.GetKey(target);
|
||||
if (path_distance < distance)
|
||||
@ -886,22 +953,26 @@ class Contractor
|
||||
{
|
||||
inserted_edges.emplace_back(source, target, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges,
|
||||
node, true, true, false);
|
||||
node, SHORTCUT_ARC, FORWARD_DIRECTION_ENABLED,
|
||||
REVERSE_DIRECTION_DISABLED);
|
||||
|
||||
inserted_edges.emplace_back(target, source, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges,
|
||||
node, true, false, true);
|
||||
node, SHORTCUT_ARC, FORWARD_DIRECTION_DISABLED,
|
||||
REVERSE_DIRECTION_ENABLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check For One-Way Streets to decide on the creation of self-loops
|
||||
|
||||
if (!RUNSIMULATION)
|
||||
{
|
||||
int iend = inserted_edges.size();
|
||||
for (int i = inserted_edges_size; i < iend; ++i)
|
||||
std::size_t iend = inserted_edges.size();
|
||||
for (std::size_t i = inserted_edges_size; i < iend; ++i)
|
||||
{
|
||||
bool found = false;
|
||||
for (int other = i + 1; other < iend; ++other)
|
||||
for (std::size_t other = i + 1; other < iend; ++other)
|
||||
{
|
||||
if (inserted_edges[other].source != inserted_edges[i].source)
|
||||
{
|
||||
@ -1071,6 +1142,13 @@ class Contractor
|
||||
stxxl::vector<QueryEdge> external_edge_list;
|
||||
std::vector<NodeID> orig_node_id_from_new_node_id_map;
|
||||
std::vector<float> node_levels;
|
||||
|
||||
// A list of weights for every node in the graph.
|
||||
// The weight represents the cost for a u-turn on the segment in the base-graph in addition to
|
||||
// its traversal.
|
||||
// During contraction, self-loops are checked against this node weight to ensure that necessary
|
||||
// self-loops are added.
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::vector<bool> is_core_node;
|
||||
util::XORFastHash fast_hash;
|
||||
};
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
@ -43,6 +45,7 @@ class Prepare
|
||||
void ContractGraph(const unsigned max_edge_id,
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
util::DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||
std::vector<EdgeWeight> &&node_weights,
|
||||
std::vector<bool> &is_core_node,
|
||||
std::vector<float> &node_levels) const;
|
||||
void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
|
||||
|
@ -156,8 +156,23 @@ class AlternativeRouting final
|
||||
std::vector<NodeID> packed_forward_path;
|
||||
std::vector<NodeID> packed_reverse_path;
|
||||
|
||||
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
|
||||
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
|
||||
if (upper_bound_to_shortest_path_distance !=
|
||||
forward_heap1.GetKey(middle_node) + reverse_heap1.GetKey(middle_node))
|
||||
{
|
||||
// Self Loop
|
||||
BOOST_ASSERT(forward_heap1.GetData(middle_node).parent == middle_node &&
|
||||
reverse_heap1.GetData(middle_node).parent == middle_node);
|
||||
packed_forward_path.push_back(middle_node);
|
||||
packed_forward_path.push_back(middle_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node,
|
||||
packed_forward_path);
|
||||
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node,
|
||||
packed_reverse_path);
|
||||
}
|
||||
|
||||
// this set is is used as an indicator if a node is on the shortest path
|
||||
std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
|
||||
@ -382,10 +397,13 @@ class AlternativeRouting final
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_reverse_heap.Insert(via_node, 0, via_node);
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
const bool constexpr STALLING_ENABLED = true;
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS = false;
|
||||
while (!new_reverse_heap.Empty())
|
||||
{
|
||||
super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
|
||||
upper_bound_s_v_path_length, min_edge_offset, false);
|
||||
upper_bound_s_v_path_length, min_edge_offset, false,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
// compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
@ -394,7 +412,8 @@ class AlternativeRouting final
|
||||
while (!new_forward_heap.Empty())
|
||||
{
|
||||
super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true);
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||
|
||||
@ -600,6 +619,18 @@ class AlternativeRouting final
|
||||
// << "
|
||||
// at distance " << new_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
const auto loop_distance = super::GetLoopWeight(node);
|
||||
const int new_distance_with_loop = new_distance + loop_distance;
|
||||
if (loop_distance != INVALID_EDGE_WEIGHT &&
|
||||
new_distance_with_loop <= *upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_distance = loop_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,10 +686,13 @@ class AlternativeRouting final
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
||||
const bool constexpr STALLING_ENABLED = true;
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS = false;
|
||||
while (new_reverse_heap.Size() > 0)
|
||||
{
|
||||
super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle,
|
||||
upper_bound_s_v_path_length, min_edge_offset, false);
|
||||
upper_bound_s_v_path_length, min_edge_offset, false,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
|
||||
@ -673,7 +707,8 @@ class AlternativeRouting final
|
||||
while (new_forward_heap.Size() > 0)
|
||||
{
|
||||
super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle,
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true);
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
|
||||
@ -841,12 +876,14 @@ class AlternativeRouting final
|
||||
if (!forward_heap3.Empty())
|
||||
{
|
||||
super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound,
|
||||
min_edge_offset, true);
|
||||
min_edge_offset, true, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
if (!reverse_heap3.Empty())
|
||||
{
|
||||
super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound,
|
||||
min_edge_offset, false);
|
||||
min_edge_offset, false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
}
|
||||
return (upper_bound <= t_test_path_length);
|
||||
|
@ -93,6 +93,9 @@ class DirectShortestPathRouting final
|
||||
int distance = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_leg;
|
||||
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS =
|
||||
false; // prevents forcing of loops, since offsets are set correctly
|
||||
|
||||
if (super::facade->GetCoreSize() > 0)
|
||||
{
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
@ -103,11 +106,12 @@ class DirectShortestPathRouting final
|
||||
reverse_core_heap.Clear();
|
||||
|
||||
super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
|
||||
distance, packed_leg);
|
||||
distance, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
else
|
||||
{
|
||||
super::Search(forward_heap, reverse_heap, distance, packed_leg);
|
||||
super::Search(forward_heap, reverse_heap, distance, packed_leg, DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
|
@ -139,14 +139,21 @@ class ManyToManyRouting final
|
||||
// get target id from bucket entry
|
||||
const unsigned target_id = current_bucket.target_id;
|
||||
const int target_distance = current_bucket.distance;
|
||||
const EdgeWeight current_distance =
|
||||
(*result_table)[source_id * number_of_targets + target_id];
|
||||
auto ¤t_distance = (*result_table)[source_id * number_of_targets + target_id];
|
||||
// check if new distance is better
|
||||
const EdgeWeight new_distance = source_distance + target_distance;
|
||||
if (new_distance >= 0 && new_distance < current_distance)
|
||||
if (new_distance < 0)
|
||||
{
|
||||
(*result_table)[source_id * number_of_targets + target_id] =
|
||||
(source_distance + target_distance);
|
||||
const EdgeWeight loop_weight = super::GetLoopWeight(node);
|
||||
const int new_distance_with_loop = new_distance + loop_weight;
|
||||
if (loop_weight != INVALID_EDGE_WEIGHT && new_distance_with_loop >= 0)
|
||||
{
|
||||
current_distance = std::min(current_distance, new_distance_with_loop);
|
||||
}
|
||||
}
|
||||
else if (new_distance < current_distance)
|
||||
{
|
||||
(*result_table)[source_id * number_of_targets + target_id] = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,17 @@
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
|
||||
namespace osrm
|
||||
@ -71,24 +79,54 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node_id,
|
||||
int &upper_bound,
|
||||
int min_edge_offset,
|
||||
std::int32_t &upper_bound,
|
||||
std::int32_t min_edge_offset,
|
||||
const bool forward_direction,
|
||||
const bool stalling = true) const
|
||||
const bool stalling,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
const std::int32_t distance = forward_heap.GetKey(node);
|
||||
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
const std::int32_t new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < upper_bound)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
if (new_distance >= 0 &&
|
||||
(!force_loop_forward ||
|
||||
forward_heap.GetData(node).parent !=
|
||||
node) // if loops are forced, they are so at the source
|
||||
&& (!force_loop_reverse || reverse_heap.GetData(node).parent != node))
|
||||
{
|
||||
middle_node_id = node;
|
||||
upper_bound = new_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
for (const auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag =
|
||||
(forward_direction ? data.forward : data.backward);
|
||||
if (forward_directionFlag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
const std::int32_t loop_distance = new_distance + edge_weight;
|
||||
if (loop_distance >= 0 && loop_distance < upper_bound)
|
||||
{
|
||||
middle_node_id = node;
|
||||
upper_bound = loop_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +149,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
|
||||
@ -134,7 +172,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
@ -155,6 +193,24 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
}
|
||||
|
||||
inline EdgeWeight GetLoopWeight(NodeID node) const
|
||||
{
|
||||
EdgeWeight loop_weight = INVALID_EDGE_WEIGHT;
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
loop_weight = std::min(loop_weight, data.distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return loop_weight;
|
||||
}
|
||||
|
||||
template <typename RandomIter>
|
||||
void UnpackPath(RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
@ -188,10 +244,10 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
// facade->FindEdge does not suffice here in case of shortcuts.
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
@ -207,7 +263,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
@ -345,10 +401,10 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
@ -361,7 +417,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
@ -414,10 +470,23 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
||||
// Offsets.
|
||||
// In case additional offsets are supplied, you might have to force a loop first.
|
||||
// A forced loop might be necessary, if source and target are on the same segment.
|
||||
// If this is the case and the offsets of the respective direction are larger for the source
|
||||
// than the target
|
||||
// then a force loop is required (e.g. source_phantom.forward_node_id ==
|
||||
// target_phantom.forward_node_id
|
||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
// requires
|
||||
// a force loop, if the heaps have been initialized with positive offsets.
|
||||
void Search(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
std::int32_t &distance,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
@ -428,15 +497,18 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (!forward_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
|
||||
STALLING_ENABLED, force_loop_forward, force_loop_reverse);
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false);
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false,
|
||||
STALLING_ENABLED, force_loop_reverse, force_loop_forward);
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,16 +522,38 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
// make sure to correctly unpack loops
|
||||
if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
||||
{
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
|
||||
reverse_heap.GetData(middle).parent == middle);
|
||||
packed_leg.push_back(middle);
|
||||
packed_leg.push_back(middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// A forced loop might be necessary, if source and target are on the same segment.
|
||||
// If this is the case and the offsets of the respective direction are larger for the source
|
||||
// than the target
|
||||
// then a force loop is required (e.g. source_phantom.forward_node_id ==
|
||||
// target_phantom.forward_node_id
|
||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
// requires
|
||||
// a force loop, if the heaps have been initialized with positive offsets.
|
||||
void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
SearchEngineData::QueryHeap &forward_core_heap,
|
||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
@ -471,6 +565,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
@ -484,8 +579,8 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
else
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset,
|
||||
true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
|
||||
STALLING_ENABLED, force_loop_forward, force_loop_reverse);
|
||||
}
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
@ -499,7 +594,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
else
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
|
||||
false);
|
||||
false, STALLING_ENABLED, force_loop_reverse, force_loop_forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -548,18 +643,21 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT(min_core_edge_offset <= 0);
|
||||
|
||||
// run two-target Dijkstra routing step on core with termination criterion
|
||||
const constexpr bool STALLING_DISABLED = false;
|
||||
while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) &&
|
||||
distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
|
||||
{
|
||||
if (!forward_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
|
||||
min_core_edge_offset, true, false);
|
||||
min_core_edge_offset, true, STALLING_DISABLED, force_loop_forward,
|
||||
force_loop_reverse);
|
||||
}
|
||||
if (!reverse_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
|
||||
min_core_edge_offset, false, false);
|
||||
min_core_edge_offset, false, STALLING_DISABLED, force_loop_reverse,
|
||||
force_loop_forward);
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,6 +671,16 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
||||
{
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
|
||||
reverse_heap.GetData(middle).parent == middle);
|
||||
packed_leg.push_back(middle);
|
||||
packed_leg.push_back(middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we need to unpack sub path from core heaps
|
||||
if (facade->IsCoreNode(middle))
|
||||
{
|
||||
@ -590,12 +698,18 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Requires the heaps for be empty
|
||||
// If heaps should be adjusted to be initialized outside of this function,
|
||||
// the addition of force_loop parameters might be required
|
||||
double get_network_distance(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom) const
|
||||
{
|
||||
BOOST_ASSERT(forward_heap.Empty());
|
||||
BOOST_ASSERT(reverse_heap.Empty());
|
||||
EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset());
|
||||
@ -628,17 +742,19 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
const constexpr bool DO_NOT_FORCE_LOOPS = false;
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (0 < forward_heap.Size())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset,
|
||||
true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset, true,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
if (0 < reverse_heap.Size())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset,
|
||||
false);
|
||||
false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -646,7 +762,19 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
if (upper_bound != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
std::vector<NodeID> packed_leg;
|
||||
if (upper_bound != forward_heap.GetKey(middle_node) + reverse_heap.GetKey(middle_node))
|
||||
{
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle_node).parent == middle_node &&
|
||||
reverse_heap.GetData(middle_node).parent == middle_node);
|
||||
packed_leg.push_back(middle_node);
|
||||
packed_leg.push_back(middle_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
|
||||
}
|
||||
|
||||
std::vector<PathData> unpacked_path;
|
||||
PhantomNodes nodes;
|
||||
nodes.source_phantom = source_phantom;
|
||||
|
@ -24,6 +24,9 @@ class ShortestPathRouting final
|
||||
using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
const static constexpr bool FORWARD_DIRECTION = true;
|
||||
const static constexpr bool REVERSE_DIRECTION = false;
|
||||
const static constexpr bool DO_NOT_FORCE_LOOP = false;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
@ -33,6 +36,19 @@ class ShortestPathRouting final
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
inline bool
|
||||
forceLoop(bool forward, const PhantomNode &source_phantom, const PhantomNode &target_phantom) const
|
||||
{
|
||||
if (forward)
|
||||
return source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset();
|
||||
else
|
||||
return source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset();
|
||||
};
|
||||
|
||||
// allows a uturn at the target_phantom
|
||||
// searches source forward/reverse -> target forward/reverse
|
||||
void SearchWithUTurn(QueryHeap &forward_heap,
|
||||
@ -76,113 +92,12 @@ class ShortestPathRouting final
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
|
||||
}
|
||||
|
||||
// If source and target are reverse on a oneway we need to find a path
|
||||
// that connects the two. This is _not_ the shortest path in our model,
|
||||
// as source and target are on the same edge based node.
|
||||
// We force a detour by inserting "virtaul vias", which means we search a path
|
||||
// from all nodes that are connected by outgoing edges to all nodes that are connected by
|
||||
// incoming edges.
|
||||
// ------^
|
||||
// | ^source
|
||||
// | ^
|
||||
// | ^target
|
||||
// ------^
|
||||
void SearchLoop(QueryHeap &forward_heap,
|
||||
QueryHeap &reverse_heap,
|
||||
const bool search_forward_node,
|
||||
const bool search_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_distance_to_forward,
|
||||
const int total_distance_to_reverse,
|
||||
int &new_total_distance_to_forward,
|
||||
int &new_total_distance_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse) const
|
||||
{
|
||||
BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
|
||||
|
||||
if (search_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.forward_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_forward + data.distance -
|
||||
source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
}
|
||||
|
||||
if (search_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.reverse_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_reverse + data.distance -
|
||||
source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
}
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path,
|
||||
forceLoop(FORWARD_DIRECTION, source_phantom, target_phantom),
|
||||
forceLoop(REVERSE_DIRECTION, source_phantom, target_phantom));
|
||||
}
|
||||
|
||||
// searches shortest path between:
|
||||
@ -227,8 +142,9 @@ class ShortestPathRouting final
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
super::Search(
|
||||
forward_heap, reverse_heap, new_total_distance_to_forward, leg_packed_path_forward,
|
||||
forceLoop(FORWARD_DIRECTION, source_phantom, target_phantom), DO_NOT_FORCE_LOOP);
|
||||
}
|
||||
|
||||
if (search_to_reverse_node)
|
||||
@ -255,7 +171,8 @@ class ShortestPathRouting final
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
|
||||
forceLoop(REVERSE_DIRECTION, source_phantom, target_phantom));
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,19 +253,6 @@ class ShortestPathRouting final
|
||||
BOOST_ASSERT(!search_from_reverse_node ||
|
||||
source_phantom.reverse_node_id != SPECIAL_NODEID);
|
||||
|
||||
if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset())
|
||||
{
|
||||
search_to_forward_node = search_from_reverse_node;
|
||||
}
|
||||
if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset())
|
||||
{
|
||||
search_to_reverse_node = search_from_forward_node;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
|
||||
|
||||
if (search_to_reverse_node || search_to_forward_node)
|
||||
@ -385,18 +289,6 @@ class ShortestPathRouting final
|
||||
packed_leg_to_reverse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
||||
search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||
BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
|
||||
BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
|
||||
SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
|
||||
search_from_reverse_node, source_phantom, target_phantom,
|
||||
total_distance_to_forward, total_distance_to_reverse,
|
||||
new_total_distance_to_forward, new_total_distance_to_reverse,
|
||||
packed_leg_to_forward, packed_leg_to_reverse);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
|
||||
|
@ -62,10 +62,11 @@ class EdgeBasedGraphFactory
|
||||
const bool generate_edge_lookup);
|
||||
#endif
|
||||
|
||||
//The following get access functions destroy the content in the factory
|
||||
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
|
||||
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
|
||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
||||
|
||||
unsigned GetHighestEdgeID();
|
||||
|
||||
@ -80,6 +81,11 @@ class EdgeBasedGraphFactory
|
||||
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
|
||||
//! graph
|
||||
std::vector<bool> m_edge_based_node_is_startpoint;
|
||||
|
||||
//! node weights that indicate the length of the segment (node based) represented by the
|
||||
//! edge-based node
|
||||
std::vector<EdgeWeight> m_edge_based_node_weights;
|
||||
|
||||
//! list of edge based nodes (compressed segments)
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
|
@ -6,24 +6,28 @@
|
||||
#include "extractor/edge_based_graph_factory.hpp"
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
class extractor
|
||||
class Extractor
|
||||
{
|
||||
public:
|
||||
extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
|
||||
Extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
|
||||
int run();
|
||||
|
||||
private:
|
||||
ExtractorConfig config;
|
||||
|
||||
void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile);
|
||||
std::pair<std::size_t, std::size_t>
|
||||
BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
|
||||
void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map);
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
@ -38,8 +42,8 @@ class extractor
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<QueryNode> &internal_to_external_node_map);
|
||||
|
||||
void WriteEdgeBasedGraph(std::string const &output_file_filename,
|
||||
size_t const max_edge_id,
|
||||
void WriteEdgeBasedGraph(const std::string &output_file_filename,
|
||||
const size_t max_edge_id,
|
||||
util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
|
||||
};
|
||||
}
|
||||
|
@ -35,6 +35,11 @@ struct ExtractorConfig
|
||||
std::string rtree_nodes_output_path;
|
||||
std::string rtree_leafs_output_path;
|
||||
|
||||
// every edge based node represents a segment in the original graph. During contraciton we need
|
||||
// to know about this segment length, as we might have to add self-loops in cases of shorter
|
||||
// parts than the segment represents itself
|
||||
std::string edge_based_node_weights_output_path;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
unsigned small_component_size;
|
||||
|
||||
|
127
include/util/io.hpp
Normal file
127
include/util/io.hpp
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef OSRM_INCLUDE_UTIL_IO_HPP_
|
||||
#define OSRM_INCLUDE_UTIL_IO_HPP_
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <fstream>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
#include "util/fingerprint.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
inline bool writeFingerprint(std::ostream &stream)
|
||||
{
|
||||
const auto fingerprint = FingerPrint::GetValid();
|
||||
stream.write(reinterpret_cast<const char *>(&fingerprint), sizeof(fingerprint));
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
inline bool readAndCheckFingerprint(std::istream &stream)
|
||||
{
|
||||
FingerPrint fingerprint;
|
||||
const auto valid = FingerPrint::GetValid();
|
||||
stream.read(reinterpret_cast<char *>(&fingerprint), sizeof(fingerprint));
|
||||
// compare the compilation state stored in the fingerprint
|
||||
return static_cast<bool>(stream) && valid.IsMagicNumberOK(fingerprint) &&
|
||||
valid.TestPrepare(fingerprint) && valid.TestGraphUtil(fingerprint) &&
|
||||
valid.TestRTree(fingerprint) && valid.TestQueryObjects(fingerprint);
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool serializeVector(const std::string &filename, const std::vector<simple_type> &data)
|
||||
{
|
||||
std::ofstream stream(filename, std::ios::binary);
|
||||
|
||||
writeFingerprint(stream);
|
||||
|
||||
std::uint64_t count = data.size();
|
||||
stream.write(reinterpret_cast<const char *>(&count), sizeof(count));
|
||||
if (!data.empty())
|
||||
stream.write(reinterpret_cast<const char *>(&data[0]), sizeof(simple_type) * count);
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool deserializeVector(const std::string &filename, std::vector<simple_type> &data)
|
||||
{
|
||||
std::ifstream stream(filename, std::ios::binary);
|
||||
|
||||
if (!readAndCheckFingerprint(stream))
|
||||
return false;
|
||||
|
||||
std::uint64_t count = 0;
|
||||
stream.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
data.resize(count);
|
||||
if (count)
|
||||
stream.read(reinterpret_cast<char *>(&data[0]), sizeof(simple_type) * count);
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
|
||||
{
|
||||
// TODO this should be replaced with a FILE-based write using error checking
|
||||
std::ofstream flag_stream(path.string(), std::ios::binary);
|
||||
|
||||
writeFingerprint(flag_stream);
|
||||
|
||||
std::uint32_t number_of_bits = flags.size();
|
||||
flag_stream.write(reinterpret_cast<const char *>(&number_of_bits), sizeof(number_of_bits));
|
||||
// putting bits in ints
|
||||
std::uint32_t chunk = 0;
|
||||
std::size_t chunk_count = 0;
|
||||
for (std::size_t bit_nr = 0; bit_nr < number_of_bits;)
|
||||
{
|
||||
std::bitset<32> chunk_bitset;
|
||||
for (std::size_t chunk_bit = 0; chunk_bit < 32 && bit_nr < number_of_bits;
|
||||
++chunk_bit, ++bit_nr)
|
||||
chunk_bitset[chunk_bit] = flags[bit_nr];
|
||||
|
||||
chunk = chunk_bitset.to_ulong();
|
||||
++chunk_count;
|
||||
flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
|
||||
}
|
||||
SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count
|
||||
<< " chunks (Flags).";
|
||||
return static_cast<bool>(flag_stream);
|
||||
}
|
||||
|
||||
inline bool deserializeFlags(const boost::filesystem::path &path, std::vector<bool> &flags)
|
||||
{
|
||||
SimpleLogger().Write() << "Reading flags from " << path;
|
||||
std::ifstream flag_stream(path.string(), std::ios::binary);
|
||||
|
||||
if (!readAndCheckFingerprint(flag_stream))
|
||||
return false;
|
||||
|
||||
std::uint32_t number_of_bits;
|
||||
flag_stream.read(reinterpret_cast<char *>(&number_of_bits), sizeof(number_of_bits));
|
||||
flags.resize(number_of_bits);
|
||||
// putting bits in ints
|
||||
std::uint32_t chunks = (number_of_bits + 31) / 32;
|
||||
std::size_t bit_position = 0;
|
||||
std::uint32_t chunk;
|
||||
for (std::size_t chunk_id = 0; chunk_id < chunks; ++chunk_id)
|
||||
{
|
||||
flag_stream.read(reinterpret_cast<char *>(&chunk), sizeof(chunk));
|
||||
std::bitset<32> chunk_bits(chunk);
|
||||
for (std::size_t bit = 0; bit < 32 && bit_position < number_of_bits; ++bit, ++bit_position)
|
||||
flags[bit_position] = chunk_bits[bit];
|
||||
}
|
||||
SimpleLogger().Write() << "Read " << number_of_bits << " bits in " << chunks
|
||||
<< " Chunks from disk.";
|
||||
return static_cast<bool>(flag_stream);
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_INCLUDE_UTIL_IO_HPP_
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "contractor/crc32_processor.hpp"
|
||||
#include "util/graph_loader.hpp"
|
||||
#include "util/io.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/lua_util.hpp"
|
||||
#include "util/osrm_exception.hpp"
|
||||
@ -22,6 +23,9 @@
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -73,7 +77,7 @@ int Prepare::Run()
|
||||
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||
|
||||
size_t max_edge_id = LoadEdgeExpandedGraph(
|
||||
std::size_t max_edge_id = LoadEdgeExpandedGraph(
|
||||
config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
|
||||
config.edge_penalty_path, config.segment_speed_lookup_path);
|
||||
|
||||
@ -86,9 +90,18 @@ int Prepare::Run()
|
||||
{
|
||||
ReadNodeLevels(node_levels);
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Reading node weights.";
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::string node_file_name = config.osrm_input_path.string() + ".enw";
|
||||
if (util::deserializeVector(node_file_name, node_weights))
|
||||
util::SimpleLogger().Write() << "Done reading node weights.";
|
||||
else
|
||||
util::SimpleLogger().Write() << "Failed reading node weights.";
|
||||
|
||||
util::DeallocatingVector<QueryEdge> contracted_edge_list;
|
||||
ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node,
|
||||
node_levels);
|
||||
ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, std::move(node_weights),
|
||||
is_core_node, node_levels);
|
||||
TIMER_STOP(contraction);
|
||||
|
||||
util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
@ -143,10 +156,12 @@ std::size_t Prepare::LoadEdgeExpandedGraph(
|
||||
input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
|
||||
fingerprint_loaded.TestPrepare(fingerprint_valid);
|
||||
|
||||
size_t number_of_edges = 0;
|
||||
size_t max_edge_id = SPECIAL_EDGEID;
|
||||
input_stream.read((char *)&number_of_edges, sizeof(size_t));
|
||||
input_stream.read((char *)&max_edge_id, sizeof(size_t));
|
||||
// TODO std::size_t can vary on systems. Our files are not transferable, but we might want to
|
||||
// consider using a fixed size type for I/O
|
||||
std::size_t number_of_edges = 0;
|
||||
std::size_t max_edge_id = SPECIAL_EDGEID;
|
||||
input_stream.read((char *)&number_of_edges, sizeof(std::size_t));
|
||||
input_stream.read((char *)&max_edge_id, sizeof(std::size_t));
|
||||
|
||||
edge_based_edge_list.resize(number_of_edges);
|
||||
util::SimpleLogger().Write() << "Reading " << number_of_edges
|
||||
@ -179,7 +194,6 @@ std::size_t Prepare::LoadEdgeExpandedGraph(
|
||||
{
|
||||
extractor::EdgeBasedEdge inbuffer;
|
||||
input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge));
|
||||
|
||||
if (update_edge_weights)
|
||||
{
|
||||
// Processing-time edge updates
|
||||
@ -370,8 +384,11 @@ Prepare::WriteContractedGraph(unsigned max_node_id,
|
||||
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
|
||||
for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size()))
|
||||
{
|
||||
// some self-loops are required for oneway handling. Need to assertthat we only keep these
|
||||
// (TODO)
|
||||
// no eigen loops
|
||||
BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
|
||||
// BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target ||
|
||||
// node_represents_oneway[contracted_edge_list[edge].source]);
|
||||
current_edge.target = contracted_edge_list[edge].target;
|
||||
current_edge.data = contracted_edge_list[edge].data;
|
||||
|
||||
@ -407,17 +424,22 @@ void Prepare::ContractGraph(
|
||||
const unsigned max_edge_id,
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
util::DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||
std::vector<EdgeWeight> &&node_weights,
|
||||
std::vector<bool> &is_core_node,
|
||||
std::vector<float> &inout_node_levels) const
|
||||
{
|
||||
std::vector<float> node_levels;
|
||||
node_levels.swap(inout_node_levels);
|
||||
|
||||
Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels));
|
||||
Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels),
|
||||
std::move(node_weights));
|
||||
contractor.Run(config.core_factor);
|
||||
contractor.GetEdges(contracted_edge_list);
|
||||
contractor.GetCoreMarker(is_core_node);
|
||||
contractor.GetNodeLevels(inout_node_levels);
|
||||
|
||||
std::cout << "Levels: " << inout_node_levels.size() << " Core: " << is_core_node.size()
|
||||
<< " MEID: " << max_edge_id << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,12 @@ void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_star
|
||||
swap(m_edge_based_node_is_startpoint, node_is_startpoint);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
|
||||
{
|
||||
using std::swap; // Koenig swap
|
||||
swap(m_edge_based_node_weights, output_node_weights);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
|
||||
|
||||
void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
||||
@ -92,6 +98,9 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeI
|
||||
return;
|
||||
}
|
||||
|
||||
if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
||||
m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
|
||||
|
||||
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))
|
||||
@ -231,6 +240,7 @@ void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
|
||||
TIMER_STOP(renumber);
|
||||
|
||||
TIMER_START(generate_nodes);
|
||||
m_edge_based_node_weights.reserve(m_max_edge_id + 1);
|
||||
GenerateEdgeExpandedNodes();
|
||||
TIMER_STOP(generate_nodes);
|
||||
|
||||
@ -270,6 +280,11 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
continue;
|
||||
}
|
||||
|
||||
// oneway streets always require this self-loop. Other streets only if a u-turn plus
|
||||
// traversal
|
||||
// of the street takes longer than the loop
|
||||
m_edge_based_node_weights.push_back(edge_data.distance + speed_profile.u_turn_penalty);
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
||||
edge_data.edge_id = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
@ -321,6 +336,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
}
|
||||
|
||||
BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
|
||||
BOOST_ASSERT(m_max_edge_id+1 == m_edge_based_node_weights.size());
|
||||
|
||||
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
||||
<< " nodes in edge-expanded graph";
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
|
||||
#include "extractor/raster_source.hpp"
|
||||
#include "util/io.hpp"
|
||||
#include "util/make_unique.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
@ -46,6 +47,7 @@
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@ -71,7 +73,7 @@ namespace extractor
|
||||
* graph
|
||||
*
|
||||
*/
|
||||
int extractor::run()
|
||||
int Extractor::run()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -265,16 +267,25 @@ int extractor::run()
|
||||
std::vector<EdgeBasedNode> node_based_edge_list;
|
||||
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
std::vector<bool> node_is_startpoint;
|
||||
std::vector<EdgeWeight> edge_based_node_weights;
|
||||
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 graph_size = BuildEdgeExpandedGraph(internal_to_external_node_map,
|
||||
node_based_edge_list, node_is_startpoint,
|
||||
edge_based_node_weights, edge_based_edge_list);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
auto max_edge_id = graph_size.second;
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
util::SimpleLogger().Write() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
util::serializeVector(config.edge_based_node_weights_output_path,
|
||||
edge_based_node_weights);
|
||||
TIMER_STOP(timer_write_node_weights);
|
||||
util::SimpleLogger().Write() << "Done writing. (" << TIMER_SEC(timer_write_node_weights)
|
||||
<< ")";
|
||||
|
||||
util::SimpleLogger().Write() << "building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
|
||||
@ -309,7 +320,7 @@ int extractor::run()
|
||||
\brief Setups scripting environment (lua-scripting)
|
||||
Also initializes speed profile.
|
||||
*/
|
||||
void extractor::SetupScriptingEnvironment(lua_State *lua_state,
|
||||
void Extractor::SetupScriptingEnvironment(lua_State *lua_state,
|
||||
SpeedProfileProperties &speed_profile)
|
||||
{
|
||||
// open utility libraries string library;
|
||||
@ -347,7 +358,7 @@ void extractor::SetupScriptingEnvironment(lua_State *lua_state,
|
||||
speed_profile.has_turn_penalty_function = util::lua_function_exists(lua_state, "turn_function");
|
||||
}
|
||||
|
||||
void extractor::FindComponents(unsigned max_edge_id,
|
||||
void Extractor::FindComponents(unsigned max_edge_id,
|
||||
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
||||
std::vector<EdgeBasedNode> &input_nodes) const
|
||||
{
|
||||
@ -425,7 +436,7 @@ void extractor::FindComponents(unsigned max_edge_id,
|
||||
/**
|
||||
\brief Build load restrictions from .restriction file
|
||||
*/
|
||||
std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
|
||||
std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
|
||||
{
|
||||
boost::filesystem::ifstream input_stream(config.restriction_file_name,
|
||||
std::ios::in | std::ios::binary);
|
||||
@ -442,7 +453,7 @@ std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
|
||||
\brief Load node based graph from .osrm file
|
||||
*/
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph>
|
||||
extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<QueryNode> &internal_to_external_node_map)
|
||||
{
|
||||
@ -483,9 +494,10 @@ extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
\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,
|
||||
Extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
|
||||
{
|
||||
lua_State *lua_state = luaL_newstate();
|
||||
@ -526,6 +538,7 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
|
||||
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);
|
||||
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
|
||||
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
|
||||
|
||||
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
||||
@ -535,7 +548,7 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
|
||||
/**
|
||||
\brief Writing info on original (node-based) nodes
|
||||
*/
|
||||
void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
|
||||
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();
|
||||
@ -553,7 +566,7 @@ void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_exter
|
||||
|
||||
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
|
||||
*/
|
||||
void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
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)
|
||||
{
|
||||
@ -589,7 +602,7 @@ void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
<< " seconds";
|
||||
}
|
||||
|
||||
void extractor::WriteEdgeBasedGraph(
|
||||
void Extractor::WriteEdgeBasedGraph(
|
||||
std::string const &output_file_filename,
|
||||
size_t const max_edge_id,
|
||||
util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
|
||||
@ -600,7 +613,8 @@ void extractor::WriteEdgeBasedGraph(
|
||||
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
|
||||
file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
|
||||
|
||||
std::cout << "[extractor] Writing edge-based-graph egdes ... " << std::flush;
|
||||
util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph egdes ... "
|
||||
<< std::flush;
|
||||
TIMER_START(write_edges);
|
||||
|
||||
size_t number_of_used_edges = edge_based_edge_list.size();
|
||||
@ -613,7 +627,7 @@ void extractor::WriteEdgeBasedGraph(
|
||||
}
|
||||
|
||||
TIMER_STOP(write_edges);
|
||||
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
|
||||
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
|
||||
|
||||
util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
|
||||
file_out_stream.close();
|
||||
|
@ -142,6 +142,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
||||
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.edge_based_node_weights_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();
|
||||
@ -173,6 +174,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
||||
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.edge_based_node_weights_output_path.append(".osrm.enw");
|
||||
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");
|
||||
@ -188,6 +190,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
||||
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.edge_based_node_weights_output_path.replace(pos, 5, ".osrm.enw");
|
||||
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");
|
||||
@ -204,6 +207,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
||||
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.edge_based_node_weights_output_path.replace(pos, 8, ".osrm.enw");
|
||||
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");
|
||||
|
@ -49,7 +49,7 @@ int main(int argc, char *argv[]) try
|
||||
<< "Profile " << extractor_config.profile_path.string() << " not found!";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return extractor::extractor(extractor_config).run();
|
||||
return extractor::Extractor(extractor_config).run();
|
||||
}
|
||||
catch (const std::bad_alloc &e)
|
||||
{
|
||||
|
43
unit_tests/io/io.cpp
Normal file
43
unit_tests/io/io.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "util/io.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
const static std::string IO_TMP_FILE = "test_io.tmp";
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(osrm_io)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(io_flags)
|
||||
{
|
||||
std::vector<bool> flags_in, flags_out;
|
||||
flags_in.resize(53);
|
||||
for (std::size_t i = 0; i < flags_in.size(); ++i)
|
||||
flags_in[i] = ((i % 2) == 1);
|
||||
|
||||
osrm::util::serializeFlags(IO_TMP_FILE, flags_in);
|
||||
osrm::util::deserializeFlags(IO_TMP_FILE, flags_out);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(flags_in.size(), flags_out.size());
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(flags_out.begin(), flags_out.end(), flags_in.begin(),
|
||||
flags_in.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(io_data)
|
||||
{
|
||||
std::vector<int> data_in, data_out;
|
||||
data_in.resize(53);
|
||||
for (std::size_t i = 0; i < data_in.size(); ++i)
|
||||
data_in[i] = i;
|
||||
|
||||
osrm::util::serializeVector(IO_TMP_FILE, data_in);
|
||||
osrm::util::deserializeVector(IO_TMP_FILE, data_out);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(data_in.size(), data_out.size());
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(data_out.begin(), data_out.end(), data_in.begin(),
|
||||
data_in.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
7
unit_tests/io_tests.cpp
Normal file
7
unit_tests/io_tests.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#define BOOST_TEST_MODULE io tests
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
/*
|
||||
* This file will contain an automatically generated main function.
|
||||
*/
|
Loading…
Reference in New Issue
Block a user