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" |   COMMENT "Configuring revision fingerprint" | ||||||
|   VERBATIM) |   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) | add_custom_target(benchmarks DEPENDS rtree-bench) | ||||||
| 
 | 
 | ||||||
| set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework) | 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 ExtractorTestsGlob unit_tests/extractor/*.cpp) | ||||||
| file(GLOB EngineTestsGlob unit_tests/engine/*.cpp) | file(GLOB EngineTestsGlob unit_tests/engine/*.cpp) | ||||||
| file(GLOB UtilTestsGlob unit_tests/util/*.cpp) | file(GLOB UtilTestsGlob unit_tests/util/*.cpp) | ||||||
|  | file(GLOB IOTestsGlob unit_tests/io/*.cpp) | ||||||
| 
 | 
 | ||||||
| add_library(UTIL OBJECT ${UtilGlob}) | add_library(UTIL OBJECT ${UtilGlob}) | ||||||
| add_library(EXTRACTOR OBJECT ${ExtractorGlob}) | 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(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(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(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 | # Benchmarks | ||||||
| add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:PHANTOM>) | 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(extractor-tests ${Boost_LIBRARIES}) | ||||||
| target_link_libraries(util-tests ${Boost_LIBRARIES}) | target_link_libraries(util-tests ${Boost_LIBRARIES}) | ||||||
| target_link_libraries(rtree-bench ${Boost_LIBRARIES}) | target_link_libraries(rtree-bench ${Boost_LIBRARIES}) | ||||||
|  | target_link_libraries(io-tests ${Boost_LIBRARIES}) | ||||||
| 
 | 
 | ||||||
| find_package(Threads REQUIRED) | find_package(Threads REQUIRED) | ||||||
| target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT}) | 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}." |       raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}." | ||||||
|     end |     end | ||||||
|     begin |     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 |         log "Renaming #{osm_file}.#{file} to #{extracted_file}.#{file}", :preprocess | ||||||
|         File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}" |         File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}" | ||||||
|       end |       end | ||||||
|  | |||||||
| @ -136,7 +136,7 @@ Feature: Basic Distance Matrix | |||||||
|             | a | 100 | 200 | 300 | |             | a | 100 | 200 | 300 | | ||||||
|             | b | 0   | 100 | 200 | |             | 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 a grid size of 300 meters | ||||||
|         Given the extract extra arguments "--small-component-size 4" |         Given the extract extra arguments "--small-component-size 4" | ||||||
|         Given the node map |         Given the node map | ||||||
| @ -156,7 +156,7 @@ Feature: Basic Distance Matrix | |||||||
|             | f | 0   | 300 | |             | f | 0   | 300 | | ||||||
|             | g | 300 |  0  | |             | 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 a grid size of 300 meters | ||||||
|         Given the extract extra arguments "--small-component-size 4" |         Given the extract extra arguments "--small-component-size 4" | ||||||
|         Given the node map |         Given the node map | ||||||
| @ -179,3 +179,21 @@ Feature: Basic Distance Matrix | |||||||
|             | h | 0   | 300 | 0   | 300 | |             | h | 0   | 300 | 0   | 300 | | ||||||
|             | i | 300 |  0  | 300 | 0   | |             | 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 | |             | 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 | |             | 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 |     Scenario: Via points on ring on the same oneway | ||||||
|     # xa it to avoid only having a single ring, which cna trigger edge cases |     # xa it to avoid only having a single ring, which cna trigger edge cases | ||||||
|         Given the node map |         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                     | |             | 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 | |             | 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 |     # See issue #1896 | ||||||
|     Scenario: Via point at a dead end with oneway |     Scenario: Via point at a dead end with oneway | ||||||
|         Given the node map |         Given the node map | ||||||
| @ -162,3 +159,45 @@ Feature: Via points | |||||||
|             | waypoints | route            | |             | waypoints | route            | | ||||||
|             | a,1,c     | abc,bd,bd,bd,abc | |             | a,1,c     | abc,bd,bd,bd,abc | | ||||||
|             | c,1,a     | 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> |     template <class ContainerT> | ||||||
|     Contractor(int nodes, ContainerT &input_edge_list, std::vector<float> &&node_levels_) |     Contractor(int nodes, | ||||||
|         : node_levels(std::move(node_levels_)) |                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; |         std::vector<ContractorEdge> edges; | ||||||
|         edges.reserve(input_edge_list.size() * 2); |         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.shortcut = reverse_edge.data.shortcut = false; | ||||||
|             forward_edge.data.id = reverse_edge.data.id = id; |             forward_edge.data.id = reverse_edge.data.id = id; | ||||||
|             forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1; |             forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1; | ||||||
|             forward_edge.data.distance = reverse_edge.data.distance = |             forward_edge.data.distance = reverse_edge.data.distance = INVALID_EDGE_WEIGHT; | ||||||
|                 std::numeric_limits<int>::max(); |  | ||||||
|             // remove parallel edges
 |             // remove parallel edges
 | ||||||
|             while (i < edges.size() && edges[i].source == source && edges[i].target == target) |             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
 |             // merge edges (s,t) and (t,s) into bidirectional edge
 | ||||||
|             if (forward_edge.data.distance == reverse_edge.data.distance) |             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; |                     forward_edge.data.backward = true; | ||||||
|                     edges[edge++] = forward_edge; |                     edges[edge++] = forward_edge; | ||||||
| @ -231,11 +233,11 @@ class Contractor | |||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { // insert seperate edges
 |             { // 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; |                     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; |                     edges[edge++] = reverse_edge; | ||||||
|                 } |                 } | ||||||
| @ -360,18 +362,21 @@ class Contractor | |||||||
| 
 | 
 | ||||||
|                 // Create new priority array
 |                 // Create new priority array
 | ||||||
|                 std::vector<float> new_node_priority(remaining_nodes.size()); |                 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
 |                 // this map gives the old IDs from the new ones, necessary to get a consistent graph
 | ||||||
|                 // at the end of contraction
 |                 // at the end of contraction
 | ||||||
|                 orig_node_id_from_new_node_id_map.resize(remaining_nodes.size()); |                 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
 |                 // this map gives the new IDs from the old ones, necessary to remap targets from the
 | ||||||
|                 // remaining graph
 |                 // 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())) |                 for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size())) | ||||||
|                 { |                 { | ||||||
|                     auto &node = remaining_nodes[new_node_id]; |                     auto &node = remaining_nodes[new_node_id]; | ||||||
|                     BOOST_ASSERT(node_priorities.size() > node.id); |                     BOOST_ASSERT(node_priorities.size() > node.id); | ||||||
|                     new_node_priority[new_node_id] = node_priorities[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
 |                 // 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_node_id_from_orig_id_map[target], data}; | ||||||
| 
 | 
 | ||||||
|                             new_edge.data.is_original_via_node_ID = true; |                             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"); |                                              "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 target id not resolveable"); | ||||||
|                             new_edge_set.push_back(new_edge); |                             new_edge_set.push_back(new_edge); | ||||||
|                         } |                         } | ||||||
| @ -420,8 +425,12 @@ class Contractor | |||||||
|                 // Replace old priorities array by new one
 |                 // Replace old priorities array by new one
 | ||||||
|                 node_priorities.swap(new_node_priority); |                 node_priorities.swap(new_node_priority); | ||||||
|                 // Delete old node_priorities vector
 |                 // 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.clear(); | ||||||
|                 new_node_priority.shrink_to_fit(); |                 new_node_priority.shrink_to_fit(); | ||||||
|  | 
 | ||||||
|  |                 node_weights.swap(new_node_weights); | ||||||
|                 // old Graph is removed
 |                 // old Graph is removed
 | ||||||
|                 contractor_graph.reset(); |                 contractor_graph.reset(); | ||||||
| 
 | 
 | ||||||
| @ -581,7 +590,7 @@ class Contractor | |||||||
|             remaining_nodes.resize(begin_independent_nodes_idx); |             remaining_nodes.resize(begin_independent_nodes_idx); | ||||||
|             //            unsigned maxdegree = 0;
 |             //            unsigned maxdegree = 0;
 | ||||||
|             //            unsigned avgdegree = 0;
 |             //            unsigned avgdegree = 0;
 | ||||||
|             //            unsigned mindegree = UINT_MAX;
 |             //            unsigned mindegree = SPECIAL_NODEID;
 | ||||||
|             //            unsigned quaddegree = 0;
 |             //            unsigned quaddegree = 0;
 | ||||||
|             //
 |             //
 | ||||||
|             //            for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
 |             //            for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
 | ||||||
| @ -686,8 +695,8 @@ class Contractor | |||||||
|                         new_edge.source = node; |                         new_edge.source = node; | ||||||
|                         new_edge.target = target; |                         new_edge.target = target; | ||||||
|                     } |                     } | ||||||
|                     BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid"); |                     BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.source, "Source id invalid"); | ||||||
|                     BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid"); |                     BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid"); | ||||||
|                     new_edge.data.distance = data.distance; |                     new_edge.data.distance = data.distance; | ||||||
|                     new_edge.data.shortcut = data.shortcut; |                     new_edge.data.shortcut = data.shortcut; | ||||||
|                     if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty()) |                     if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty()) | ||||||
| @ -718,23 +727,55 @@ class Contractor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   private: |   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, |     inline void Dijkstra(const int max_distance, | ||||||
|                          const unsigned number_of_targets, |                          const unsigned number_of_targets, | ||||||
|                          const int maxNodes, |                          const int maxNodes, | ||||||
|                          ContractorThreadData *const data, |                          ContractorThreadData &data, | ||||||
|                          const NodeID middleNode) |                          const NodeID middleNode) | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         ContractorHeap &heap = data->heap; |         ContractorHeap &heap = data.heap; | ||||||
| 
 | 
 | ||||||
|         int nodes = 0; |         int nodes = 0; | ||||||
|         unsigned number_of_targets_found = 0; |         unsigned number_of_targets_found = 0; | ||||||
|         while (!heap.Empty()) |         while (!heap.Empty()) | ||||||
|         { |         { | ||||||
|             const NodeID node = heap.DeleteMin(); |             const NodeID node = heap.DeleteMin(); | ||||||
|             const int distance = heap.GetKey(node); |             const auto distance = heap.GetKey(node); | ||||||
|             const short current_hop = heap.GetData(node).hop + 1; |  | ||||||
| 
 |  | ||||||
|             if (++nodes > maxNodes) |             if (++nodes > maxNodes) | ||||||
|             { |             { | ||||||
|                 return; |                 return; | ||||||
| @ -754,33 +795,7 @@ class Contractor | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // iterate over all edges of node
 |             RelaxNode(node, middleNode, distance, heap); | ||||||
|             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; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -815,13 +830,21 @@ class Contractor | |||||||
|     ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr) |     ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr) | ||||||
|     { |     { | ||||||
|         ContractorHeap &heap = data->heap; |         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; |         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)) |         for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node)) | ||||||
|         { |         { | ||||||
|             const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge); |             const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge); | ||||||
|             const NodeID source = contractor_graph->GetTarget(in_edge); |             const NodeID source = contractor_graph->GetTarget(in_edge); | ||||||
|  |             if (source == node) | ||||||
|  |                 continue; | ||||||
|  | 
 | ||||||
|             if (RUNSIMULATION) |             if (RUNSIMULATION) | ||||||
|             { |             { | ||||||
|                 BOOST_ASSERT(stats != nullptr); |                 BOOST_ASSERT(stats != nullptr); | ||||||
| @ -846,22 +869,64 @@ class Contractor | |||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 const NodeID target = contractor_graph->GetTarget(out_edge); |                 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); |                 max_distance = std::max(max_distance, path_distance); | ||||||
|                 if (!heap.WasInserted(target)) |                 if (!heap.WasInserted(target)) | ||||||
|                 { |                 { | ||||||
|                     heap.Insert(target, INT_MAX, ContractorHeapData(0, true)); |                     heap.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData(0, true)); | ||||||
|                     ++number_of_targets; |                     ++number_of_targets; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (RUNSIMULATION) |             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 |             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)) |             for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node)) | ||||||
|             { |             { | ||||||
| @ -871,6 +936,8 @@ class Contractor | |||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 const NodeID target = contractor_graph->GetTarget(out_edge); |                 const NodeID target = contractor_graph->GetTarget(out_edge); | ||||||
|  |                 if (target == node) | ||||||
|  |                     continue; | ||||||
|                 const int path_distance = in_data.distance + out_data.distance; |                 const int path_distance = in_data.distance + out_data.distance; | ||||||
|                 const int distance = heap.GetKey(target); |                 const int distance = heap.GetKey(target); | ||||||
|                 if (path_distance < distance) |                 if (path_distance < distance) | ||||||
| @ -886,22 +953,26 @@ class Contractor | |||||||
|                     { |                     { | ||||||
|                         inserted_edges.emplace_back(source, target, path_distance, |                         inserted_edges.emplace_back(source, target, path_distance, | ||||||
|                                                     out_data.originalEdges + in_data.originalEdges, |                                                     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, |                         inserted_edges.emplace_back(target, source, path_distance, | ||||||
|                                                     out_data.originalEdges + in_data.originalEdges, |                                                     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) |         if (!RUNSIMULATION) | ||||||
|         { |         { | ||||||
|             int iend = inserted_edges.size(); |             std::size_t iend = inserted_edges.size(); | ||||||
|             for (int i = inserted_edges_size; i < iend; ++i) |             for (std::size_t i = inserted_edges_size; i < iend; ++i) | ||||||
|             { |             { | ||||||
|                 bool found = false; |                 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) |                     if (inserted_edges[other].source != inserted_edges[i].source) | ||||||
|                     { |                     { | ||||||
| @ -1071,6 +1142,13 @@ class Contractor | |||||||
|     stxxl::vector<QueryEdge> external_edge_list; |     stxxl::vector<QueryEdge> external_edge_list; | ||||||
|     std::vector<NodeID> orig_node_id_from_new_node_id_map; |     std::vector<NodeID> orig_node_id_from_new_node_id_map; | ||||||
|     std::vector<float> node_levels; |     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; |     std::vector<bool> is_core_node; | ||||||
|     util::XORFastHash fast_hash; |     util::XORFastHash fast_hash; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <boost/filesystem.hpp> | #include <boost/filesystem.hpp> | ||||||
| 
 | 
 | ||||||
|  | #include <cstddef> | ||||||
|  | 
 | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| struct lua_State; | struct lua_State; | ||||||
| @ -43,6 +45,7 @@ class Prepare | |||||||
|     void ContractGraph(const unsigned max_edge_id, |     void ContractGraph(const unsigned max_edge_id, | ||||||
|                        util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, |                        util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, | ||||||
|                        util::DeallocatingVector<QueryEdge> &contracted_edge_list, |                        util::DeallocatingVector<QueryEdge> &contracted_edge_list, | ||||||
|  |                        std::vector<EdgeWeight> &&node_weights, | ||||||
|                        std::vector<bool> &is_core_node, |                        std::vector<bool> &is_core_node, | ||||||
|                        std::vector<float> &node_levels) const; |                        std::vector<float> &node_levels) const; | ||||||
|     void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) 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_forward_path; | ||||||
|         std::vector<NodeID> packed_reverse_path; |         std::vector<NodeID> packed_reverse_path; | ||||||
| 
 | 
 | ||||||
|         super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path); |         if (upper_bound_to_shortest_path_distance != | ||||||
|         super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path); |             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
 |         // 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() + |         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; |         int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT; | ||||||
|         new_reverse_heap.Insert(via_node, 0, via_node); |         new_reverse_heap.Insert(via_node, 0, via_node); | ||||||
|         // compute path <s,..,v> by reusing forward search from s
 |         // 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()) |         while (!new_reverse_heap.Empty()) | ||||||
|         { |         { | ||||||
|             super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle, |             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
 |         // compute path <v,..,t> by reusing backward search from node t
 | ||||||
|         NodeID v_t_middle = SPECIAL_NODEID; |         NodeID v_t_middle = SPECIAL_NODEID; | ||||||
| @ -394,7 +412,8 @@ class AlternativeRouting final | |||||||
|         while (!new_forward_heap.Empty()) |         while (!new_forward_heap.Empty()) | ||||||
|         { |         { | ||||||
|             super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle, |             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; |         *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length; | ||||||
| 
 | 
 | ||||||
| @ -442,10 +461,10 @@ class AlternativeRouting final | |||||||
|                                           partially_unpacked_shortest_path.size())) - |                                           partially_unpacked_shortest_path.size())) - | ||||||
|             1; |             1; | ||||||
|         for (int64_t current_node = 0; (current_node < packed_path_length) && |         for (int64_t current_node = 0; (current_node < packed_path_length) && | ||||||
|                                            (partially_unpacked_via_path[current_node] == |                                        (partially_unpacked_via_path[current_node] == | ||||||
|                                                 partially_unpacked_shortest_path[current_node] && |                                             partially_unpacked_shortest_path[current_node] && | ||||||
|                                             partially_unpacked_via_path[current_node + 1] == |                                         partially_unpacked_via_path[current_node + 1] == | ||||||
|                                                 partially_unpacked_shortest_path[current_node + 1]); |                                             partially_unpacked_shortest_path[current_node + 1]); | ||||||
|              ++current_node) |              ++current_node) | ||||||
|         { |         { | ||||||
|             EdgeID selected_edge = |             EdgeID selected_edge = | ||||||
| @ -600,6 +619,18 @@ class AlternativeRouting final | |||||||
|                     //     << "
 |                     //     << "
 | ||||||
|                     //     at distance " << new_distance;
 |                     //     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; |         int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT; | ||||||
|         // compute path <s,..,v> by reusing forward search from s
 |         // compute path <s,..,v> by reusing forward search from s
 | ||||||
|         new_reverse_heap.Insert(candidate.node, 0, candidate.node); |         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) |         while (new_reverse_heap.Size() > 0) | ||||||
|         { |         { | ||||||
|             super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle, |             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) |         if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length) | ||||||
| @ -673,7 +707,8 @@ class AlternativeRouting final | |||||||
|         while (new_forward_heap.Size() > 0) |         while (new_forward_heap.Size() > 0) | ||||||
|         { |         { | ||||||
|             super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle, |             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) |         if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length) | ||||||
| @ -841,12 +876,14 @@ class AlternativeRouting final | |||||||
|             if (!forward_heap3.Empty()) |             if (!forward_heap3.Empty()) | ||||||
|             { |             { | ||||||
|                 super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound, |                 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()) |             if (!reverse_heap3.Empty()) | ||||||
|             { |             { | ||||||
|                 super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound, |                 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); |         return (upper_bound <= t_test_path_length); | ||||||
|  | |||||||
| @ -93,6 +93,9 @@ class DirectShortestPathRouting final | |||||||
|         int distance = INVALID_EDGE_WEIGHT; |         int distance = INVALID_EDGE_WEIGHT; | ||||||
|         std::vector<NodeID> packed_leg; |         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) |         if (super::facade->GetCoreSize() > 0) | ||||||
|         { |         { | ||||||
|             engine_working_data.InitializeOrClearSecondThreadLocalStorage( |             engine_working_data.InitializeOrClearSecondThreadLocalStorage( | ||||||
| @ -103,11 +106,12 @@ class DirectShortestPathRouting final | |||||||
|             reverse_core_heap.Clear(); |             reverse_core_heap.Clear(); | ||||||
| 
 | 
 | ||||||
|             super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap, |             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 |         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?
 |         // No path found for both target nodes?
 | ||||||
|  | |||||||
| @ -139,14 +139,21 @@ class ManyToManyRouting final | |||||||
|                 // get target id from bucket entry
 |                 // get target id from bucket entry
 | ||||||
|                 const unsigned target_id = current_bucket.target_id; |                 const unsigned target_id = current_bucket.target_id; | ||||||
|                 const int target_distance = current_bucket.distance; |                 const int target_distance = current_bucket.distance; | ||||||
|                 const EdgeWeight current_distance = |                 auto ¤t_distance = (*result_table)[source_id * number_of_targets + target_id]; | ||||||
|                     (*result_table)[source_id * number_of_targets + target_id]; |  | ||||||
|                 // check if new distance is better
 |                 // check if new distance is better
 | ||||||
|                 const EdgeWeight new_distance = source_distance + target_distance; |                 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] = |                     const EdgeWeight loop_weight = super::GetLoopWeight(node); | ||||||
|                         (source_distance + target_distance); |                     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/internal_route_result.hpp" | ||||||
| #include "engine/search_engine_data.hpp" | #include "engine/search_engine_data.hpp" | ||||||
| #include "extractor/turn_instructions.hpp" | #include "extractor/turn_instructions.hpp" | ||||||
|  | #include "util/typedefs.hpp" | ||||||
| 
 | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| 
 | 
 | ||||||
|  | #include <cstddef> | ||||||
|  | #include <cstdint> | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iterator> | ||||||
|  | #include <utility> | ||||||
|  | #include <vector> | ||||||
| #include <stack> | #include <stack> | ||||||
| 
 | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| @ -71,24 +79,54 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|     void RoutingStep(SearchEngineData::QueryHeap &forward_heap, |     void RoutingStep(SearchEngineData::QueryHeap &forward_heap, | ||||||
|                      SearchEngineData::QueryHeap &reverse_heap, |                      SearchEngineData::QueryHeap &reverse_heap, | ||||||
|                      NodeID &middle_node_id, |                      NodeID &middle_node_id, | ||||||
|                      int &upper_bound, |                      std::int32_t &upper_bound, | ||||||
|                      int min_edge_offset, |                      std::int32_t min_edge_offset, | ||||||
|                      const bool forward_direction, |                      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 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)) |         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 < 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; |                     middle_node_id = node; | ||||||
|                     upper_bound = new_distance; |                     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) |                 if (reverse_flag) | ||||||
|                 { |                 { | ||||||
|                     const NodeID to = facade->GetTarget(edge); |                     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"); |                     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 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"); |                 BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); | ||||||
|                 const int to_distance = distance + edge_weight; |                 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> |     template <typename RandomIter> | ||||||
|     void UnpackPath(RandomIter packed_path_begin, |     void UnpackPath(RandomIter packed_path_begin, | ||||||
|                     RandomIter packed_path_end, |                     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.
 |             // facade->FindEdge does not suffice here in case of shortcuts.
 | ||||||
|             // The above explanation unclear? Think!
 |             // The above explanation unclear? Think!
 | ||||||
|             EdgeID smaller_edge_id = SPECIAL_EDGEID; |             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)) |             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) && |                 if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) && | ||||||
|                     facade->GetEdgeData(edge_id).forward) |                     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)) |                 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) && |                     if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && | ||||||
|                         facade->GetEdgeData(edge_id).backward) |                         facade->GetEdgeData(edge_id).backward) | ||||||
|                     { |                     { | ||||||
| @ -345,10 +401,10 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|             recursion_stack.pop(); |             recursion_stack.pop(); | ||||||
| 
 | 
 | ||||||
|             EdgeID smaller_edge_id = SPECIAL_EDGEID; |             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)) |             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) && |                 if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) && | ||||||
|                     facade->GetEdgeData(edge_id).forward) |                     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)) |                 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) && |                     if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && | ||||||
|                         facade->GetEdgeData(edge_id).backward) |                         facade->GetEdgeData(edge_id).backward) | ||||||
|                     { |                     { | ||||||
| @ -414,10 +470,23 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // assumes that heaps are already setup correctly.
 |     // 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, |     void Search(SearchEngineData::QueryHeap &forward_heap, | ||||||
|                 SearchEngineData::QueryHeap &reverse_heap, |                 SearchEngineData::QueryHeap &reverse_heap, | ||||||
|                 int &distance, |                 std::int32_t &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; |         NodeID middle = SPECIAL_NODEID; | ||||||
| 
 | 
 | ||||||
| @ -428,15 +497,18 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|         BOOST_ASSERT(reverse_heap.MinKey() >= 0); |         BOOST_ASSERT(reverse_heap.MinKey() >= 0); | ||||||
| 
 | 
 | ||||||
|         // run two-Target Dijkstra routing step.
 |         // run two-Target Dijkstra routing step.
 | ||||||
|  |         const constexpr bool STALLING_ENABLED = true; | ||||||
|         while (0 < (forward_heap.Size() + reverse_heap.Size())) |         while (0 < (forward_heap.Size() + reverse_heap.Size())) | ||||||
|         { |         { | ||||||
|             if (!forward_heap.Empty()) |             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()) |             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), |         BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance), | ||||||
|                          "no path found"); |                          "no path found"); | ||||||
| 
 | 
 | ||||||
|         RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg); |         // 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.
 |     // 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, |     void SearchWithCore(SearchEngineData::QueryHeap &forward_heap, | ||||||
|                         SearchEngineData::QueryHeap &reverse_heap, |                         SearchEngineData::QueryHeap &reverse_heap, | ||||||
|                         SearchEngineData::QueryHeap &forward_core_heap, |                         SearchEngineData::QueryHeap &forward_core_heap, | ||||||
|                         SearchEngineData::QueryHeap &reverse_core_heap, |                         SearchEngineData::QueryHeap &reverse_core_heap, | ||||||
|                         int &distance, |                         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; |         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
 |         // we only every insert negative offsets for nodes in the forward heap
 | ||||||
|         BOOST_ASSERT(reverse_heap.MinKey() >= 0); |         BOOST_ASSERT(reverse_heap.MinKey() >= 0); | ||||||
| 
 | 
 | ||||||
|  |         const constexpr bool STALLING_ENABLED = true; | ||||||
|         // run two-Target Dijkstra routing step.
 |         // run two-Target Dijkstra routing step.
 | ||||||
|         while (0 < (forward_heap.Size() + reverse_heap.Size())) |         while (0 < (forward_heap.Size() + reverse_heap.Size())) | ||||||
|         { |         { | ||||||
| @ -484,8 +579,8 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, |                     RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true, | ||||||
|                                 true); |                                 STALLING_ENABLED, force_loop_forward, force_loop_reverse); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (!reverse_heap.Empty()) |             if (!reverse_heap.Empty()) | ||||||
| @ -499,7 +594,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, |                     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); |         BOOST_ASSERT(min_core_edge_offset <= 0); | ||||||
| 
 | 
 | ||||||
|         // run two-target Dijkstra routing step on core with termination criterion
 |         // 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()) && |         while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) && | ||||||
|                distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey())) |                distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey())) | ||||||
|         { |         { | ||||||
|             if (!forward_core_heap.Empty()) |             if (!forward_core_heap.Empty()) | ||||||
|             { |             { | ||||||
|                 RoutingStep(forward_core_heap, reverse_core_heap, middle, distance, |                 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()) |             if (!reverse_core_heap.Empty()) | ||||||
|             { |             { | ||||||
|                 RoutingStep(reverse_core_heap, forward_core_heap, middle, distance, |                 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,29 +671,45 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | |||||||
|         BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance), |         BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance), | ||||||
|                          "no path found"); |                          "no path found"); | ||||||
| 
 | 
 | ||||||
|         // we need to unpack sub path from core heaps
 |         if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle)) | ||||||
|         if (facade->IsCoreNode(middle)) |  | ||||||
|         { |         { | ||||||
|             std::vector<NodeID> packed_core_leg; |             // self loop
 | ||||||
|             RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle, |             BOOST_ASSERT(forward_heap.GetData(middle).parent == middle && | ||||||
|                                        packed_core_leg); |                          reverse_heap.GetData(middle).parent == middle); | ||||||
|             BOOST_ASSERT(packed_core_leg.size() > 0); |             packed_leg.push_back(middle); | ||||||
|             RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg); |             packed_leg.push_back(middle); | ||||||
|             std::reverse(packed_leg.begin(), packed_leg.end()); |  | ||||||
|             packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end()); |  | ||||||
|             RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg); |  | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg); |             // we need to unpack sub path from core heaps
 | ||||||
|  |             if (facade->IsCoreNode(middle)) | ||||||
|  |             { | ||||||
|  |                 std::vector<NodeID> packed_core_leg; | ||||||
|  |                 RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle, | ||||||
|  |                                            packed_core_leg); | ||||||
|  |                 BOOST_ASSERT(packed_core_leg.size() > 0); | ||||||
|  |                 RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg); | ||||||
|  |                 std::reverse(packed_leg.begin(), packed_leg.end()); | ||||||
|  |                 packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end()); | ||||||
|  |                 RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 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, |     double get_network_distance(SearchEngineData::QueryHeap &forward_heap, | ||||||
|                                 SearchEngineData::QueryHeap &reverse_heap, |                                 SearchEngineData::QueryHeap &reverse_heap, | ||||||
|                                 const PhantomNode &source_phantom, |                                 const PhantomNode &source_phantom, | ||||||
|                                 const PhantomNode &target_phantom) const |                                 const PhantomNode &target_phantom) const | ||||||
|     { |     { | ||||||
|  |         BOOST_ASSERT(forward_heap.Empty()); | ||||||
|  |         BOOST_ASSERT(reverse_heap.Empty()); | ||||||
|         EdgeWeight upper_bound = INVALID_EDGE_WEIGHT; |         EdgeWeight upper_bound = INVALID_EDGE_WEIGHT; | ||||||
|         NodeID middle_node = SPECIAL_NODEID; |         NodeID middle_node = SPECIAL_NODEID; | ||||||
|         EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset()); |         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
 |         // 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())) |         while (0 < (forward_heap.Size() + reverse_heap.Size())) | ||||||
|         { |         { | ||||||
|             if (0 < forward_heap.Size()) |             if (0 < forward_heap.Size()) | ||||||
|             { |             { | ||||||
|                 RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset, |                 RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset, true, | ||||||
|                             true); |                             STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS); | ||||||
|             } |             } | ||||||
|             if (0 < reverse_heap.Size()) |             if (0 < reverse_heap.Size()) | ||||||
|             { |             { | ||||||
|                 RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset, |                 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) |         if (upper_bound != INVALID_EDGE_WEIGHT) | ||||||
|         { |         { | ||||||
|             std::vector<NodeID> packed_leg; |             std::vector<NodeID> packed_leg; | ||||||
|             RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, 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; |             std::vector<PathData> unpacked_path; | ||||||
|             PhantomNodes nodes; |             PhantomNodes nodes; | ||||||
|             nodes.source_phantom = source_phantom; |             nodes.source_phantom = source_phantom; | ||||||
|  | |||||||
| @ -24,6 +24,9 @@ class ShortestPathRouting final | |||||||
|     using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>; |     using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>; | ||||||
|     using QueryHeap = SearchEngineData::QueryHeap; |     using QueryHeap = SearchEngineData::QueryHeap; | ||||||
|     SearchEngineData &engine_working_data; |     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: |   public: | ||||||
|     ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data) |     ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data) | ||||||
| @ -33,6 +36,19 @@ class ShortestPathRouting final | |||||||
| 
 | 
 | ||||||
|     ~ShortestPathRouting() {} |     ~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
 |     // allows a uturn at the target_phantom
 | ||||||
|     // searches source forward/reverse -> target forward/reverse
 |     // searches source forward/reverse -> target forward/reverse
 | ||||||
|     void SearchWithUTurn(QueryHeap &forward_heap, |     void SearchWithUTurn(QueryHeap &forward_heap, | ||||||
| @ -76,113 +92,12 @@ class ShortestPathRouting final | |||||||
|                                 target_phantom.GetReverseWeightPlusOffset(), |                                 target_phantom.GetReverseWeightPlusOffset(), | ||||||
|                                 target_phantom.reverse_node_id); |                                 target_phantom.reverse_node_id); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         BOOST_ASSERT(forward_heap.Size() > 0); |         BOOST_ASSERT(forward_heap.Size() > 0); | ||||||
|         BOOST_ASSERT(reverse_heap.Size() > 0); |         BOOST_ASSERT(reverse_heap.Size() > 0); | ||||||
|         super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path); |         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)); | ||||||
|     // 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()); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // searches shortest path between:
 |     // searches shortest path between:
 | ||||||
| @ -227,8 +142,9 @@ class ShortestPathRouting final | |||||||
|             } |             } | ||||||
|             BOOST_ASSERT(forward_heap.Size() > 0); |             BOOST_ASSERT(forward_heap.Size() > 0); | ||||||
|             BOOST_ASSERT(reverse_heap.Size() > 0); |             BOOST_ASSERT(reverse_heap.Size() > 0); | ||||||
|             super::Search(forward_heap, reverse_heap, new_total_distance_to_forward, |             super::Search( | ||||||
|                           leg_packed_path_forward); |                 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) |         if (search_to_reverse_node) | ||||||
| @ -255,7 +171,8 @@ class ShortestPathRouting final | |||||||
|             BOOST_ASSERT(forward_heap.Size() > 0); |             BOOST_ASSERT(forward_heap.Size() > 0); | ||||||
|             BOOST_ASSERT(reverse_heap.Size() > 0); |             BOOST_ASSERT(reverse_heap.Size() > 0); | ||||||
|             super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse, |             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 || |             BOOST_ASSERT(!search_from_reverse_node || | ||||||
|                          source_phantom.reverse_node_id != SPECIAL_NODEID); |                          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); |             BOOST_ASSERT(search_from_forward_node || search_from_reverse_node); | ||||||
| 
 | 
 | ||||||
|             if (search_to_reverse_node || search_to_forward_node) |             if (search_to_reverse_node || search_to_forward_node) | ||||||
| @ -385,18 +289,6 @@ class ShortestPathRouting final | |||||||
|                            packed_leg_to_reverse); |                            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?
 |             // No path found for both target nodes?
 | ||||||
|             if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) && |             if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) && | ||||||
|  | |||||||
| @ -62,10 +62,11 @@ class EdgeBasedGraphFactory | |||||||
|              const bool generate_edge_lookup); |              const bool generate_edge_lookup); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |     //The following get access functions destroy the content in the factory
 | ||||||
|     void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges); |     void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges); | ||||||
| 
 |  | ||||||
|     void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes); |     void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes); | ||||||
|     void GetStartPointMarkers(std::vector<bool> &node_is_startpoint); |     void GetStartPointMarkers(std::vector<bool> &node_is_startpoint); | ||||||
|  |     void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights); | ||||||
| 
 | 
 | ||||||
|     unsigned GetHighestEdgeID(); |     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
 |     //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
 | ||||||
|     //! graph
 |     //! graph
 | ||||||
|     std::vector<bool> m_edge_based_node_is_startpoint; |     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)
 |     //! list of edge based nodes (compressed segments)
 | ||||||
|     std::vector<EdgeBasedNode> m_edge_based_node_list; |     std::vector<EdgeBasedNode> m_edge_based_node_list; | ||||||
|     util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list; |     util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list; | ||||||
|  | |||||||
| @ -6,24 +6,28 @@ | |||||||
| #include "extractor/edge_based_graph_factory.hpp" | #include "extractor/edge_based_graph_factory.hpp" | ||||||
| #include "extractor/graph_compressor.hpp" | #include "extractor/graph_compressor.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "util/typedefs.hpp" | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class extractor | class Extractor | ||||||
| { | { | ||||||
|   public: |   public: | ||||||
|     extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {} |     Extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {} | ||||||
|     int run(); |     int run(); | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     ExtractorConfig config; |     ExtractorConfig config; | ||||||
|  | 
 | ||||||
|     void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile); |     void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile); | ||||||
|     std::pair<std::size_t, std::size_t> |     std::pair<std::size_t, std::size_t> | ||||||
|     BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map, |     BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map, | ||||||
|                            std::vector<EdgeBasedNode> &node_based_edge_list, |                            std::vector<EdgeBasedNode> &node_based_edge_list, | ||||||
|                            std::vector<bool> &node_is_startpoint, |                            std::vector<bool> &node_is_startpoint, | ||||||
|  |                            std::vector<EdgeWeight> &edge_based_node_weights, | ||||||
|                            util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list); |                            util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list); | ||||||
|     void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map); |     void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map); | ||||||
|     void FindComponents(unsigned max_edge_id, |     void FindComponents(unsigned max_edge_id, | ||||||
| @ -38,8 +42,8 @@ class extractor | |||||||
|                        std::unordered_set<NodeID> &traffic_lights, |                        std::unordered_set<NodeID> &traffic_lights, | ||||||
|                        std::vector<QueryNode> &internal_to_external_node_map); |                        std::vector<QueryNode> &internal_to_external_node_map); | ||||||
| 
 | 
 | ||||||
|     void WriteEdgeBasedGraph(std::string const &output_file_filename, |     void WriteEdgeBasedGraph(const std::string &output_file_filename, | ||||||
|                              size_t const max_edge_id, |                              const size_t max_edge_id, | ||||||
|                              util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list); |                              util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list); | ||||||
| }; | }; | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,6 +35,11 @@ struct ExtractorConfig | |||||||
|     std::string rtree_nodes_output_path; |     std::string rtree_nodes_output_path; | ||||||
|     std::string rtree_leafs_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 requested_num_threads; | ||||||
|     unsigned small_component_size; |     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 "contractor/crc32_processor.hpp" | ||||||
| #include "util/graph_loader.hpp" | #include "util/graph_loader.hpp" | ||||||
|  | #include "util/io.hpp" | ||||||
| #include "util/integer_range.hpp" | #include "util/integer_range.hpp" | ||||||
| #include "util/lua_util.hpp" | #include "util/lua_util.hpp" | ||||||
| #include "util/osrm_exception.hpp" | #include "util/osrm_exception.hpp" | ||||||
| @ -22,6 +23,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <tbb/parallel_sort.h> | #include <tbb/parallel_sort.h> | ||||||
| 
 | 
 | ||||||
|  | #include <cstddef> | ||||||
|  | #include <cstdint> | ||||||
|  | #include <bitset> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| @ -73,7 +77,7 @@ int Prepare::Run() | |||||||
| 
 | 
 | ||||||
|     util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list; |     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_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path, | ||||||
|         config.edge_penalty_path, config.segment_speed_lookup_path); |         config.edge_penalty_path, config.segment_speed_lookup_path); | ||||||
| 
 | 
 | ||||||
| @ -86,9 +90,18 @@ int Prepare::Run() | |||||||
|     { |     { | ||||||
|         ReadNodeLevels(node_levels); |         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; |     util::DeallocatingVector<QueryEdge> contracted_edge_list; | ||||||
|     ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node, |     ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, std::move(node_weights), | ||||||
|                   node_levels); |                   is_core_node, node_levels); | ||||||
|     TIMER_STOP(contraction); |     TIMER_STOP(contraction); | ||||||
| 
 | 
 | ||||||
|     util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec"; |     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)); |     input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint)); | ||||||
|     fingerprint_loaded.TestPrepare(fingerprint_valid); |     fingerprint_loaded.TestPrepare(fingerprint_valid); | ||||||
| 
 | 
 | ||||||
|     size_t number_of_edges = 0; |     // TODO std::size_t can vary on systems. Our files are not transferable, but we might want to
 | ||||||
|     size_t max_edge_id = SPECIAL_EDGEID; |     // consider using a fixed size type for I/O
 | ||||||
|     input_stream.read((char *)&number_of_edges, sizeof(size_t)); |     std::size_t number_of_edges = 0; | ||||||
|     input_stream.read((char *)&max_edge_id, sizeof(size_t)); |     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); |     edge_based_edge_list.resize(number_of_edges); | ||||||
|     util::SimpleLogger().Write() << "Reading " << number_of_edges |     util::SimpleLogger().Write() << "Reading " << number_of_edges | ||||||
| @ -179,7 +194,6 @@ std::size_t Prepare::LoadEdgeExpandedGraph( | |||||||
|     { |     { | ||||||
|         extractor::EdgeBasedEdge inbuffer; |         extractor::EdgeBasedEdge inbuffer; | ||||||
|         input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge)); |         input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge)); | ||||||
| 
 |  | ||||||
|         if (update_edge_weights) |         if (update_edge_weights) | ||||||
|         { |         { | ||||||
|             // Processing-time edge updates
 |             // Processing-time edge updates
 | ||||||
| @ -370,8 +384,11 @@ Prepare::WriteContractedGraph(unsigned max_node_id, | |||||||
|     util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge; |     util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge; | ||||||
|     for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size())) |     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
 |         // 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.target = contracted_edge_list[edge].target; | ||||||
|         current_edge.data = contracted_edge_list[edge].data; |         current_edge.data = contracted_edge_list[edge].data; | ||||||
| 
 | 
 | ||||||
| @ -407,17 +424,22 @@ void Prepare::ContractGraph( | |||||||
|     const unsigned max_edge_id, |     const unsigned max_edge_id, | ||||||
|     util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, |     util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, | ||||||
|     util::DeallocatingVector<QueryEdge> &contracted_edge_list, |     util::DeallocatingVector<QueryEdge> &contracted_edge_list, | ||||||
|  |     std::vector<EdgeWeight> &&node_weights, | ||||||
|     std::vector<bool> &is_core_node, |     std::vector<bool> &is_core_node, | ||||||
|     std::vector<float> &inout_node_levels) const |     std::vector<float> &inout_node_levels) const | ||||||
| { | { | ||||||
|     std::vector<float> node_levels; |     std::vector<float> node_levels; | ||||||
|     node_levels.swap(inout_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.Run(config.core_factor); | ||||||
|     contractor.GetEdges(contracted_edge_list); |     contractor.GetEdges(contracted_edge_list); | ||||||
|     contractor.GetCoreMarker(is_core_node); |     contractor.GetCoreMarker(is_core_node); | ||||||
|     contractor.GetNodeLevels(inout_node_levels); |     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); |     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; } | unsigned EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; } | ||||||
| 
 | 
 | ||||||
| void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v) | 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; |         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) == |     BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) == | ||||||
|                  m_compressed_edge_container.HasEntryForID(edge_id_2)); |                  m_compressed_edge_container.HasEntryForID(edge_id_2)); | ||||||
|     if (m_compressed_edge_container.HasEntryForID(edge_id_1)) |     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_STOP(renumber); | ||||||
| 
 | 
 | ||||||
|     TIMER_START(generate_nodes); |     TIMER_START(generate_nodes); | ||||||
|  |     m_edge_based_node_weights.reserve(m_max_edge_id + 1); | ||||||
|     GenerateEdgeExpandedNodes(); |     GenerateEdgeExpandedNodes(); | ||||||
|     TIMER_STOP(generate_nodes); |     TIMER_STOP(generate_nodes); | ||||||
| 
 | 
 | ||||||
| @ -270,6 +280,11 @@ unsigned EdgeBasedGraphFactory::RenumberEdges() | |||||||
|                 continue; |                 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()); |             BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges()); | ||||||
|             edge_data.edge_id = numbered_edges_count; |             edge_data.edge_id = numbered_edges_count; | ||||||
|             ++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_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() |     util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() | ||||||
|                                  << " nodes in edge-expanded graph"; |                                  << " nodes in edge-expanded graph"; | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include "extractor/scripting_environment.hpp" | #include "extractor/scripting_environment.hpp" | ||||||
| 
 | 
 | ||||||
| #include "extractor/raster_source.hpp" | #include "extractor/raster_source.hpp" | ||||||
|  | #include "util/io.hpp" | ||||||
| #include "util/make_unique.hpp" | #include "util/make_unique.hpp" | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
| #include "util/timing_util.hpp" | #include "util/timing_util.hpp" | ||||||
| @ -46,6 +47,7 @@ | |||||||
| #include <thread> | #include <thread> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <bitset> | ||||||
| 
 | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| @ -71,7 +73,7 @@ namespace extractor | |||||||
|  * graph |  * graph | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| int extractor::run() | int Extractor::run() | ||||||
| { | { | ||||||
|     try |     try | ||||||
|     { |     { | ||||||
| @ -265,16 +267,25 @@ int extractor::run() | |||||||
|         std::vector<EdgeBasedNode> node_based_edge_list; |         std::vector<EdgeBasedNode> node_based_edge_list; | ||||||
|         util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list; |         util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list; | ||||||
|         std::vector<bool> node_is_startpoint; |         std::vector<bool> node_is_startpoint; | ||||||
|  |         std::vector<EdgeWeight> edge_based_node_weights; | ||||||
|         std::vector<QueryNode> internal_to_external_node_map; |         std::vector<QueryNode> internal_to_external_node_map; | ||||||
|         auto graph_size = |         auto graph_size = BuildEdgeExpandedGraph(internal_to_external_node_map, | ||||||
|             BuildEdgeExpandedGraph(internal_to_external_node_map, node_based_edge_list, |                                                  node_based_edge_list, node_is_startpoint, | ||||||
|                                    node_is_startpoint, edge_based_edge_list); |                                                  edge_based_node_weights, edge_based_edge_list); | ||||||
| 
 | 
 | ||||||
|         auto number_of_node_based_nodes = graph_size.first; |         auto number_of_node_based_nodes = graph_size.first; | ||||||
|         auto max_edge_id = graph_size.second; |         auto max_edge_id = graph_size.second; | ||||||
| 
 | 
 | ||||||
|         TIMER_STOP(expansion); |         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 ..."; |         util::SimpleLogger().Write() << "building r-tree ..."; | ||||||
|         TIMER_START(rtree); |         TIMER_START(rtree); | ||||||
| 
 | 
 | ||||||
| @ -309,7 +320,7 @@ int extractor::run() | |||||||
|     \brief Setups scripting environment (lua-scripting) |     \brief Setups scripting environment (lua-scripting) | ||||||
|     Also initializes speed profile. |     Also initializes speed profile. | ||||||
| */ | */ | ||||||
| void extractor::SetupScriptingEnvironment(lua_State *lua_state, | void Extractor::SetupScriptingEnvironment(lua_State *lua_state, | ||||||
|                                           SpeedProfileProperties &speed_profile) |                                           SpeedProfileProperties &speed_profile) | ||||||
| { | { | ||||||
|     // open utility libraries string library;
 |     // 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"); |     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, |                                const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list, | ||||||
|                                std::vector<EdgeBasedNode> &input_nodes) const |                                std::vector<EdgeBasedNode> &input_nodes) const | ||||||
| { | { | ||||||
| @ -425,7 +436,7 @@ void extractor::FindComponents(unsigned max_edge_id, | |||||||
| /**
 | /**
 | ||||||
|   \brief Build load restrictions from .restriction file |   \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, |     boost::filesystem::ifstream input_stream(config.restriction_file_name, | ||||||
|                                              std::ios::in | std::ios::binary); |                                              std::ios::in | std::ios::binary); | ||||||
| @ -442,7 +453,7 @@ std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap() | |||||||
|   \brief Load node based graph from .osrm file |   \brief Load node based graph from .osrm file | ||||||
|   */ |   */ | ||||||
| std::shared_ptr<util::NodeBasedDynamicGraph> | 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::unordered_set<NodeID> &traffic_lights, | ||||||
|                               std::vector<QueryNode> &internal_to_external_node_map) |                               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 |  \brief Building an edge-expanded graph from node-based input and turn restrictions | ||||||
| */ | */ | ||||||
| std::pair<std::size_t, std::size_t> | 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<EdgeBasedNode> &node_based_edge_list, | ||||||
|                                   std::vector<bool> &node_is_startpoint, |                                   std::vector<bool> &node_is_startpoint, | ||||||
|  |                                   std::vector<EdgeWeight> &edge_based_node_weights, | ||||||
|                                   util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list) |                                   util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list) | ||||||
| { | { | ||||||
|     lua_State *lua_state = luaL_newstate(); |     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.GetEdgeBasedEdges(edge_based_edge_list); | ||||||
|     edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list); |     edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list); | ||||||
|     edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint); |     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(); |     auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID(); | ||||||
| 
 | 
 | ||||||
|     const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes(); |     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 |   \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); |     boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary); | ||||||
|     const unsigned size_of_mapping = internal_to_external_node_map.size(); |     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'. |     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, |                            std::vector<bool> node_is_startpoint, | ||||||
|                            const std::vector<QueryNode> &internal_to_external_node_map) |                            const std::vector<QueryNode> &internal_to_external_node_map) | ||||||
| { | { | ||||||
| @ -589,7 +602,7 @@ void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list, | |||||||
|                                  << " seconds"; |                                  << " seconds"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void extractor::WriteEdgeBasedGraph( | void Extractor::WriteEdgeBasedGraph( | ||||||
|     std::string const &output_file_filename, |     std::string const &output_file_filename, | ||||||
|     size_t const max_edge_id, |     size_t const max_edge_id, | ||||||
|     util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list) |     util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list) | ||||||
| @ -600,7 +613,8 @@ void extractor::WriteEdgeBasedGraph( | |||||||
|     const util::FingerPrint fingerprint = util::FingerPrint::GetValid(); |     const util::FingerPrint fingerprint = util::FingerPrint::GetValid(); | ||||||
|     file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint)); |     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); |     TIMER_START(write_edges); | ||||||
| 
 | 
 | ||||||
|     size_t number_of_used_edges = edge_based_edge_list.size(); |     size_t number_of_used_edges = edge_based_edge_list.size(); | ||||||
| @ -613,7 +627,7 @@ void extractor::WriteEdgeBasedGraph( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     TIMER_STOP(write_edges); |     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"; |     util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges"; | ||||||
|     file_out_stream.close(); |     file_out_stream.close(); | ||||||
|  | |||||||
| @ -142,6 +142,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi | |||||||
|     extractor_config.geometry_output_path = input_path.string(); |     extractor_config.geometry_output_path = input_path.string(); | ||||||
|     extractor_config.edge_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_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.node_output_path = input_path.string(); | ||||||
|     extractor_config.rtree_nodes_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.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.node_output_path.append(".osrm.nodes"); | ||||||
|             extractor_config.edge_output_path.append(".osrm.edges"); |             extractor_config.edge_output_path.append(".osrm.edges"); | ||||||
|             extractor_config.edge_graph_output_path.append(".osrm.ebg"); |             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_nodes_output_path.append(".osrm.ramIndex"); | ||||||
|             extractor_config.rtree_leafs_output_path.append(".osrm.fileIndex"); |             extractor_config.rtree_leafs_output_path.append(".osrm.fileIndex"); | ||||||
|             extractor_config.edge_segment_lookup_path.append(".osrm.edge_segment_lookup"); |             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.node_output_path.replace(pos, 5, ".osrm.nodes"); | ||||||
|             extractor_config.edge_output_path.replace(pos, 5, ".osrm.edges"); |             extractor_config.edge_output_path.replace(pos, 5, ".osrm.edges"); | ||||||
|             extractor_config.edge_graph_output_path.replace(pos, 5, ".osrm.ebg"); |             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_nodes_output_path.replace(pos, 5, ".osrm.ramIndex"); | ||||||
|             extractor_config.rtree_leafs_output_path.replace(pos, 5, ".osrm.fileIndex"); |             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_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.node_output_path.replace(pos, 8, ".osrm.nodes"); | ||||||
|         extractor_config.edge_output_path.replace(pos, 8, ".osrm.edges"); |         extractor_config.edge_output_path.replace(pos, 8, ".osrm.edges"); | ||||||
|         extractor_config.edge_graph_output_path.replace(pos, 8, ".osrm.ebg"); |         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_nodes_output_path.replace(pos, 8, ".osrm.ramIndex"); | ||||||
|         extractor_config.rtree_leafs_output_path.replace(pos, 8, ".osrm.fileIndex"); |         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_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!"; |             << "Profile " << extractor_config.profile_path.string() << " not found!"; | ||||||
|         return EXIT_FAILURE; |         return EXIT_FAILURE; | ||||||
|     } |     } | ||||||
|     return extractor::extractor(extractor_config).run(); |     return extractor::Extractor(extractor_config).run(); | ||||||
| } | } | ||||||
| catch (const std::bad_alloc &e) | 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