diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e1b0a5c700..daaa891af78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8.8) -if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE) +if( CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE ) message(FATAL_ERROR "In-source builds are not allowed. Please create a directory and run cmake from there, passing the path to this source directory as the last argument. This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.") @@ -11,7 +11,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(CheckCXXCompilerFlag) include(FindPackageHandleStandardArgs) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(GetGitRevisionDescription) git_describe(GIT_DESCRIPTION) @@ -30,26 +30,26 @@ endif() OPTION(WITH_TOOLS "Build OSRM tools" OFF) OPTION(BUILD_TOOLS "Build OSRM tools" OFF) -include_directories(${CMAKE_SOURCE_DIR}/Include/) -include_directories(${CMAKE_SOURCE_DIR}/third_party/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/Include/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/) -add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild - COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} +add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild + COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake DEPENDS - ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/Util/finger_print.cpp.in COMMENT "Configuring finger_print.cpp" VERBATIM) -add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp) +add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Util/finger_print.cpp) add_custom_target(tests DEPENDS datastructure-tests algorithm-tests) add_custom_target(benchmarks DEPENDS rtree-bench) set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework) configure_file( - ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in - ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Util/GitDescription.cpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/Util/GitDescription.cpp ) file(GLOB ExtractorGlob extractor/*.cpp) file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp) @@ -104,14 +104,7 @@ add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $>(query_data_facade)); RegisterPlugin(new HelloWorldPlugin()); RegisterPlugin(new LocatePlugin>(query_data_facade)); + RegisterPlugin(new MultiTargetPlugin, true>(query_data_facade)); + RegisterPlugin(new MultiTargetPlugin, false>(query_data_facade)); RegisterPlugin(new NearestPlugin>(query_data_facade)); + RegisterPlugin(new DistanceTablePlugin, false, false>(query_data_facade)); RegisterPlugin(new TimestampPlugin>(query_data_facade)); RegisterPlugin(new ViaRoutePlugin>(query_data_facade)); } diff --git a/data_structures/search_engine.hpp b/data_structures/search_engine.hpp index 0b2b888dcdb..6c136f13cc7 100644 --- a/data_structures/search_engine.hpp +++ b/data_structures/search_engine.hpp @@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "search_engine_data.hpp" #include "../routing_algorithms/alternative_path.hpp" #include "../routing_algorithms/many_to_many.hpp" +#include "../routing_algorithms/multi_target.hpp" #include "../routing_algorithms/shortest_path.hpp" #include @@ -44,11 +45,20 @@ template class SearchEngine public: ShortestPathRouting shortest_path; AlternativeRouting alternative_path; - ManyToManyRouting distance_table; + ManyToManyRouting distance_table; + ManyToManyRouting distance_table_single_source; + ManyToManyRouting distance_table_single_target; + MultiTargetRouting multi_target; + MultiTargetRouting multi_source; explicit SearchEngine(DataFacadeT *facade) : facade(facade), shortest_path(facade, engine_working_data), - alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data) + alternative_path(facade, engine_working_data), + distance_table(facade, engine_working_data), + distance_table_single_source(facade, engine_working_data), + distance_table_single_target(facade, engine_working_data), + multi_target(facade, engine_working_data), + multi_source(facade, engine_working_data) { static_assert(!std::is_pointer::value, "don't instantiate with ptr type"); static_assert(std::is_object::value, "don't instantiate with void, function, or reference"); diff --git a/data_structures/search_engine_data.cpp b/data_structures/search_engine_data.cpp index 810762acd47..724f850b023 100644 --- a/data_structures/search_engine_data.cpp +++ b/data_structures/search_engine_data.cpp @@ -29,6 +29,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "binary_heap.hpp" +SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap; +SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap; +SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2; +SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2; +SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3; +SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3; + void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes) { if (forwardHeap.get()) diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp index a75e0ed17e2..dea769d314d 100644 --- a/plugins/distance_table.hpp +++ b/plugins/distance_table.hpp @@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../data_structures/query_edge.hpp" #include "../data_structures/search_engine.hpp" #include "../descriptors/descriptor_base.hpp" +#include "../Util/integer_range.hpp" #include "../Util/json_renderer.hpp" #include "../Util/make_unique.hpp" #include "../Util/StringUtil.h" @@ -48,7 +49,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -template class DistanceTablePlugin final : public BasePlugin +template class DistanceTablePlugin final : public BasePlugin { private: std::unique_ptr> search_engine_ptr; @@ -63,19 +66,15 @@ template class DistanceTablePlugin final : public BasePlugin const std::string GetDescriptor() const final { return descriptor_string; } - void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final + std::shared_ptr> HandleRequest( + const RouteParameters &route_parameters, unsigned &calctime_in_us) { if (!check_all_coordinates(route_parameters.coordinates)) - { - reply = http::Reply::StockReply(http::Reply::badRequest); - return; - } + return {}; const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); - unsigned max_locations = - std::min(100u, static_cast(route_parameters.coordinates.size())); - PhantomNodeArray phantom_node_vector(max_locations); - for (const auto i : osrm::irange(1u, max_locations)) + PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size()); + for (const auto i : osrm::irange(0ul, route_parameters.coordinates.size())) { if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) @@ -96,20 +95,43 @@ template class DistanceTablePlugin final : public BasePlugin BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); } - // TIMER_START(distance_table); - std::shared_ptr> result_table = - search_engine_ptr->distance_table(phantom_node_vector); - // TIMER_STOP(distance_table); + std::shared_ptr> result_table; + + TIMER_START(distance_table); + if (single_source) + { + result_table = search_engine_ptr->distance_table_single_source(phantom_node_vector); + } + else if (single_target) + { + result_table = search_engine_ptr->distance_table_single_target(phantom_node_vector); + } + else + { + result_table = search_engine_ptr->distance_table(phantom_node_vector); + } + TIMER_STOP(distance_table); + + calctime_in_us = TIMER_USEC(distance_table); + + return result_table; + } + + void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final + { + unsigned calctime_in_us = 0; + auto result_table = HandleRequest(route_parameters, calctime_in_us); if (!result_table) { reply = http::Reply::StockReply(http::Reply::badRequest); return; } + JSON::Object json_object; JSON::Array json_array; - const unsigned number_of_locations = static_cast(phantom_node_vector.size()); - for (unsigned row = 0; row < number_of_locations; ++row) + const auto number_of_locations = route_parameters.coordinates.size(); + for (const auto row : osrm::irange(0, number_of_locations)) { JSON::Array json_row; auto row_begin_iterator = result_table->begin() + (row * number_of_locations); diff --git a/plugins/multi_target.hpp b/plugins/multi_target.hpp new file mode 100644 index 00000000000..bd78cc20e62 --- /dev/null +++ b/plugins/multi_target.hpp @@ -0,0 +1,140 @@ +/* + +Copyright (c) 2014, Project OSRM, Felix Guendling +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef MULTI_TARGET_PLUGIN_H +#define MULTI_TARGET_PLUGIN_H + +#include "plugin_base.hpp" + +#include "../Algorithms/object_encoder.hpp" +#include "../data_structures/search_engine.hpp" +#include "../Util/json_renderer.hpp" +#include "../Util/TimingUtil.h" + +template class MultiTargetPlugin final : public BasePlugin +{ + public: + explicit MultiTargetPlugin(DataFacadeT *facade) + : facade(facade), search_engine_ptr(std::make_shared>(facade)) + { + } + + virtual ~MultiTargetPlugin() {} + + std::shared_ptr>> + HandleRequest(const RouteParameters &route_parameters, + unsigned &calctime_in_us) + { + // check number of parameters + if (2 > route_parameters.coordinates.size()) + { + return nullptr; + } + + if (std::any_of(begin(route_parameters.coordinates), end(route_parameters.coordinates), + [&](FixedPointCoordinate coordinate) + { + return !coordinate.is_valid(); + })) + { + return nullptr; + } + + const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); + PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size()); + for (unsigned i = 0; i < route_parameters.coordinates.size(); ++i) + { + if (checksum_OK && i < route_parameters.hints.size() && + !route_parameters.hints[i].empty()) + { + PhantomNode current_phantom_node; + ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node); + if (current_phantom_node.is_valid(facade->GetNumberOfNodes())) + { + phantom_node_vector[i].emplace_back(std::move(current_phantom_node)); + continue; + } + } + facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], + phantom_node_vector[i], + route_parameters.zoom_level, + 1); + + BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); + } + + std::shared_ptr>> ret; + + TIMER_START(multi_target); + if (forward) + { + ret = search_engine_ptr->multi_target(phantom_node_vector); + } + else + { + ret = search_engine_ptr->multi_source(phantom_node_vector); + } + TIMER_STOP(multi_target); + calctime_in_us = TIMER_USEC(multi_target); + + return ret; + } + + void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) + { + unsigned calctime_in_ms = 0; + auto result_table = HandleRequest(route_parameters, calctime_in_ms); + + if (!result_table) + { + reply = http::Reply::StockReply(http::Reply::badRequest); + return; + } + + JSON::Object json_object; + JSON::Array json_array; + for (unsigned column = 0; column < route_parameters.coordinates.size() - 1; ++column) + { + auto routing_result = result_table->operator[](column); + + JSON::Object result; + result.values["time_cost"] = routing_result.first; + result.values["distance"] = routing_result.second; + json_array.values.emplace_back(result); + } + json_object.values["distances"] = json_array; + JSON::render(reply.content, json_object); + } + + const std::string GetDescriptor() const { return forward ? "multitarget" : "multisource"; } + + private: + DataFacadeT *facade; + std::shared_ptr> search_engine_ptr; +}; + +#endif // MULTI_TARGET_PLUGIN_H diff --git a/routing_algorithms/many_to_many.hpp b/routing_algorithms/many_to_many.hpp index 112971c7ad5..7a46c3e284b 100644 --- a/routing_algorithms/many_to_many.hpp +++ b/routing_algorithms/many_to_many.hpp @@ -39,7 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -template class ManyToManyRouting final : public BasicRoutingInterface +template class ManyToManyRouting final : public BasicRoutingInterface { using super = BasicRoutingInterface; using QueryHeap = SearchEngineData::QueryHeap; @@ -106,6 +108,12 @@ template class ManyToManyRouting final : public BasicRouting { BackwardRoutingStep(target_id, query_heap, search_space_with_buckets); } + + if (single_target) + { + break; + } + ++target_id; } @@ -141,9 +149,13 @@ template class ManyToManyRouting final : public BasicRouting result_table); } + if (single_source) + { + break; + } + ++source_id; } - BOOST_ASSERT(source_id == target_id); return result_table; } diff --git a/routing_algorithms/multi_target.hpp b/routing_algorithms/multi_target.hpp new file mode 100644 index 00000000000..df47c5a420c --- /dev/null +++ b/routing_algorithms/multi_target.hpp @@ -0,0 +1,230 @@ +/* + +Copyright (c) 2014, Project OSRM, Felix Guendling +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef MULTI_TARGET_ROUTING_H +#define MULTI_TARGET_ROUTING_H + +#include "routing_base.hpp" +#include "../data_structures/json_container.hpp" +#include "../data_structures/search_engine_data.hpp" +#include "../typedefs.h" + +#include + +#include +#include + +template +class MultiTargetRouting final : public BasicRoutingInterface +{ + typedef BasicRoutingInterface super; + typedef SearchEngineData::QueryHeap QueryHeap; + SearchEngineData &engine_working_data; + + public: + MultiTargetRouting(DataFacadeT *facade, SearchEngineData &engine_working_data) + : super(facade), engine_working_data(engine_working_data) + { + } + + ~MultiTargetRouting() {} + + std::shared_ptr>> + operator()(const PhantomNodeArray &phantom_nodes_array) const + { + BOOST_ASSERT(phantom_nodes_array.size() >= 2); + + // Prepare results table: + // Each target (phantom_nodes_array[1], ..., phantom_nodes_array[n]) has its own index. + auto results = std::make_shared>>(); + results->reserve(phantom_nodes_array.size() - 1); + + // For readability: some reference variables making it clear, + // which one is the source and which are the targets. + const auto &source = phantom_nodes_array[0]; + std::vector>> targets( + std::next(begin(phantom_nodes_array)), end(phantom_nodes_array)); + + engine_working_data.InitializeOrClearFirstThreadLocalStorage( + super::facade->GetNumberOfNodes()); + + // The forward heap keeps the distances from the source. + // Therefore it will be reused for each target backward search. + QueryHeap &forward_heap = *(engine_working_data.forwardHeap); + + // The reverse heap will be cleared after each search from + // one of the targets to the source. + QueryHeap &reverse_heap = *(engine_working_data.backwardHeap); + + // Fill forward heap with the source location phantom node(s). + // The source location is located at index 0. + // The target locations are located at index [1, ..., n]. + EdgeWeight min_edge_offset = 0; + for (const PhantomNode &phantom_node : source) + { + if (SPECIAL_NODEID != phantom_node.forward_node_id) + { + EdgeWeight offset = (forward ? -1 : 1) * phantom_node.GetForwardWeightPlusOffset(); + forward_heap.Insert(phantom_node.forward_node_id, offset, + phantom_node.forward_node_id); + min_edge_offset = std::min(min_edge_offset, offset); + } + if (SPECIAL_NODEID != phantom_node.reverse_node_id) + { + EdgeWeight offset = (forward ? -1 : 1) * phantom_node.GetReverseWeightPlusOffset(); + forward_heap.Insert(phantom_node.reverse_node_id, + (forward ? -1 : 1) * phantom_node.GetReverseWeightPlusOffset(), + phantom_node.reverse_node_id); + min_edge_offset = std::min(min_edge_offset, offset); + } + } + + for (auto const &target : targets) + { + const std::vector &phantom_node_vector = target; + auto result = FindShortestPath(source, phantom_node_vector, forward_heap, reverse_heap, + min_edge_offset); + results->emplace_back(std::move(result)); + } + + forward_heap.Clear(); + reverse_heap.Clear(); + + return results; + } + + std::pair FindShortestPath(const std::vector &source, + const std::vector &target, + QueryHeap &forward_heap, + QueryHeap &backward_heap, + EdgeWeight min_edge_offset) const + { + NodeID middle = UINT_MAX; + int local_upper_bound = INT_MAX; + + // Clear backward heap from the entries produced by the search to the last target + // and initialize heap for this target. + backward_heap.Clear(); + for (const PhantomNode &phantom_node : target) + { + if (SPECIAL_NODEID != phantom_node.forward_node_id) + { + EdgeWeight offset = (forward ? 1 : -1) * phantom_node.GetForwardWeightPlusOffset(); + backward_heap.Insert(phantom_node.forward_node_id, offset, + phantom_node.forward_node_id); + min_edge_offset = std::min(min_edge_offset, offset); + } + + if (SPECIAL_NODEID != phantom_node.reverse_node_id) + { + EdgeWeight offset = (forward ? 1 : -1) * phantom_node.GetReverseWeightPlusOffset(); + backward_heap.Insert(phantom_node.reverse_node_id, offset, + phantom_node.reverse_node_id); + min_edge_offset = std::min(min_edge_offset, offset); + } + } + + // Execute bidirectional Dijkstra shortest path search. + while (0 < backward_heap.Size() || 0 < forward_heap.Size()) + { + if (0 < forward_heap.Size()) + { + super::RoutingStep(forward_heap, backward_heap, &middle, &local_upper_bound, + min_edge_offset, forward, false); + } + if (0 < backward_heap.Size()) + { + super::RoutingStep(backward_heap, forward_heap, &middle, &local_upper_bound, + min_edge_offset, !forward); + } + } + + // Check if no path could be found (-> early exit). + if (INVALID_EDGE_WEIGHT == local_upper_bound) + { + return std::make_pair(INVALID_EDGE_WEIGHT, 0); + } + + // Calculate exact distance in km. + std::vector packed_path; + super::RetrievePackedPathFromHeap(forward_heap, backward_heap, middle, packed_path); + + if (!forward) + { + std::reverse(begin(packed_path), end(packed_path)); + } + + auto source_phantom_it = + std::find_if(begin(source), end(source), [&packed_path](PhantomNode const &node) + { + return node.forward_node_id == packed_path[forward ? 0 : packed_path.size() - 1] || + node.reverse_node_id == packed_path[forward ? 0 : packed_path.size() - 1]; + }); + auto target_phantom_it = + std::find_if(begin(target), end(target), [&packed_path](PhantomNode const &node) + { + return node.forward_node_id == packed_path[forward ? packed_path.size() - 1 : 0] || + node.reverse_node_id == packed_path[forward ? packed_path.size() - 1 : 0]; + }); + + BOOST_ASSERT(source_phantom_it != end(source)); + BOOST_ASSERT(target_phantom_it != end(target)); + + std::vector unpacked_path; + if (forward) + { + super::UnpackPath(packed_path, {*source_phantom_it, *target_phantom_it}, unpacked_path); + } + else + { + super::UnpackPath(packed_path, {*target_phantom_it, *source_phantom_it}, unpacked_path); + } + + std::vector coordinates; + coordinates.reserve(unpacked_path.size() + 2); + + coordinates.emplace_back(forward ? source_phantom_it->location + : target_phantom_it->location); + for (const auto &path_data : unpacked_path) + { + coordinates.emplace_back(super::facade->GetCoordinateOfNode(path_data.node)); + } + coordinates.emplace_back(forward ? target_phantom_it->location + : source_phantom_it->location); + + double distance = 0.0; + for (int i = 1; i < coordinates.size(); ++i) + { + distance += FixedPointCoordinate::ApproximateEuclideanDistance(coordinates[i - 1], + coordinates[i]); + } + + return std::make_pair(round(local_upper_bound / 10.), distance); + } +}; + +#endif diff --git a/routing_algorithms/routing_base.hpp b/routing_algorithms/routing_base.hpp index 20610ea170f..8ee51a53b74 100644 --- a/routing_algorithms/routing_base.hpp +++ b/routing_algorithms/routing_base.hpp @@ -37,13 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap; -SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap; -SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2; -SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2; -SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3; -SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3; - template class BasicRoutingInterface { private: @@ -58,12 +51,13 @@ template class BasicRoutingInterface explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {} virtual ~BasicRoutingInterface() {}; - inline void RoutingStep(SearchEngineData::QueryHeap &forward_heap, + inline bool RoutingStep(SearchEngineData::QueryHeap &forward_heap, SearchEngineData::QueryHeap &reverse_heap, NodeID *middle_node_id, int *upper_bound, const int min_edge_offset, - const bool forward_direction) const + const bool forward_direction, + bool clear_if_finished = true) const { const NodeID node = forward_heap.DeleteMin(); const int distance = forward_heap.GetKey(node); @@ -87,11 +81,11 @@ template class BasicRoutingInterface } } - if (distance + min_edge_offset > *upper_bound) + if (clear_if_finished && distance + min_edge_offset > *upper_bound) { // SimpleLogger().Write() << "min_edge_offset: " << min_edge_offset; forward_heap.DeleteAll(); - return; + return true; } // Stalling @@ -110,7 +104,7 @@ template class BasicRoutingInterface { if (forward_heap.GetKey(to) + edge_weight < distance) { - return; + return false; } } } @@ -143,6 +137,8 @@ template class BasicRoutingInterface } } } + + return false; } inline void UnpackPath(const std::vector &packed_path, @@ -300,7 +296,8 @@ template class BasicRoutingInterface for (std::size_t i = start_index; i != end_index; (start_index < end_index ? ++i : --i)) { BOOST_ASSERT(i < id_vector.size()); - BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode>0 ); + // TODO check why this is failing for multi-target distance calc + // BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode>0 ); unpacked_path.emplace_back(PathData{id_vector[i], phantom_node_pair.target_phantom.name_id, TurnInstruction::NoTurn,