inline bool StallAtNode(const DataFacadeT &facade, const NodeID node, const EdgeWeight weight, QueryHeap &query_heap) const { for (auto edge : facade.GetAdjacentEdgeRange(node)) { const auto &data = facade.GetEdgeData(edge); const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward); if (reverse_flag) { const NodeID to = facade.GetTarget(edge); const int edge_weight = data.weight; BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); if (query_heap.WasInserted(to)) { if (query_heap.GetKey(to) + edge_weight < weight) { return true; } } } } return false; }
inline void RelaxOutgoingEdges(const DataFacadeT &facade, const NodeID node, const EdgeWeight weight, QueryHeap &query_heap) const { for (auto edge : facade.GetAdjacentEdgeRange(node)) { const auto &data = facade.GetEdgeData(edge); const bool direction_flag = (forward_direction ? data.forward : data.backward); if (direction_flag) { const NodeID to = facade.GetTarget(edge); const int edge_weight = data.weight; BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); const int to_weight = weight + edge_weight; // New Node discovered -> Add to Heap + Node Info Storage if (!query_heap.WasInserted(to)) { query_heap.Insert(to, to_weight, node); } // Found a shorter Path -> Update weight else if (to_weight < query_heap.GetKey(to)) { // new parent query_heap.GetData(to).parent = node; query_heap.DecreaseKey(to, to_weight); } } } }
std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters) { const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); const auto &input_bearings = route_parameters.bearings; std::vector<PhantomNode> phantom_node_list; phantom_node_list.reserve(route_parameters.coordinates.size()); // find phantom nodes for all input coords for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size())) { // if client hints are helpful, encode hints 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_list.push_back(std::move(current_phantom_node)); continue; } } const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; const int range = input_bearings.size() > 0 ? (input_bearings[i].second ? *input_bearings[i].second : 10) : 180; auto results = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range); if (results.empty()) { break; } phantom_node_list.push_back(std::move(results.front().phantom_node)); BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes())); } return phantom_node_list; }
inline osrm::json::Object BuildHintData(const InternalRouteResult& raw_route) const { osrm::json::Object json_hint_object; json_hint_object.values["checksum"] = facade->GetCheckSum(); osrm::json::Array json_location_hint_array; std::string hint; for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size())) { ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint); json_location_hint_array.values.push_back(hint); } ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint); json_location_hint_array.values.push_back(hint); json_hint_object.values["locations"] = json_location_hint_array; return json_hint_object; }
unsigned DescribeLeg(const std::vector<PathData> &route_leg, const PhantomNodes &leg_phantoms, const bool target_traversed_in_reverse, const bool is_via_leg) { unsigned added_element_count = 0; // Get all the coordinates for the computed route FixedPointCoordinate current_coordinate; for (const PathData &path_data : route_leg) { current_coordinate = facade->GetCoordinateOfNode(path_data.node); description_factory.AppendSegment(current_coordinate, path_data); ++added_element_count; } description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse, is_via_leg); ++added_element_count; BOOST_ASSERT((route_leg.size() + 1) == added_element_count); return added_element_count; }
std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, const std::vector<PathData> &leg_data, const LegGeometry &leg_geometry, const PhantomNode &source_node, const PhantomNode &target_node, const bool source_traversed_in_reverse, const bool target_traversed_in_reverse) { const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const constexpr char *NO_ROTARY_NAME = ""; const EdgeWeight source_duration = source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight; const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode : source_node.forward_travel_mode; const EdgeWeight target_duration = target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight; const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode; const auto number_of_segments = leg_geometry.GetNumberOfSegments(); std::vector<RouteStep> steps; steps.reserve(number_of_segments); std::size_t segment_index = 0; BOOST_ASSERT(leg_geometry.locations.size() >= 2); if (leg_data.size() > 0) { StepManeuver maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry); maneuver.location = source_node.location; // PathData saves the information we need of the segment _before_ the turn, // but a RouteStep is with regard to the segment after the turn. // We need to skip the first segment because it is already covered by the // initial start of a route int segment_duration = 0; for (const auto &path_point : leg_data) { segment_duration += path_point.duration_until_turn; // all changes to this check have to be matched with assemble_geometry if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { BOOST_ASSERT(segment_duration >= 0); const auto name = facade.GetNameForID(path_point.name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{path_point.name_id, name, NO_ROTARY_NAME, segment_duration / 10.0, distance, path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, leg_geometry, segment_index); segment_index++; segment_duration = 0; } } const auto distance = leg_geometry.segment_distances[segment_index]; const int duration = segment_duration + target_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); } // In this case the source + target are on the same edge segment else { BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position); // s t // u-------------v // |---| source_duration // |---------| target_duration StepManeuver maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry); int duration = target_duration - source_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id), NO_ROTARY_NAME, duration / 10., leg_geometry.segment_distances[segment_index], source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); } BOOST_ASSERT(segment_index == number_of_segments - 1); // This step has length zero, the only reason we need it is the target location auto final_maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry); BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode, final_maneuver, leg_geometry.locations.size()-1, leg_geometry.locations.size()}); return steps; }
std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, const std::vector<PathData> &leg_data, const LegGeometry &leg_geometry, const PhantomNode &source_node, const PhantomNode &target_node, const bool source_traversed_in_reverse, const bool target_traversed_in_reverse) { const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const constexpr char *NO_ROTARY_NAME = ""; const EdgeWeight source_duration = source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight; const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode : source_node.forward_travel_mode; const EdgeWeight target_duration = target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight; const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode; const auto number_of_segments = leg_geometry.GetNumberOfSegments(); std::vector<RouteStep> steps; steps.reserve(number_of_segments); std::size_t segment_index = 0; BOOST_ASSERT(leg_geometry.locations.size() >= 2); auto bearings = detail::getDepartBearings(leg_geometry); StepManeuver maneuver{source_node.location, bearings.first, bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, 0}; Intersection intersection{source_node.location, std::vector<short>({bearings.second}), std::vector<bool>({true}), Intersection::NO_INDEX, 0}; if (leg_data.size() > 0) { // PathData saves the information we need of the segment _before_ the turn, // but a RouteStep is with regard to the segment after the turn. // We need to skip the first segment because it is already covered by the // initial start of a route int segment_duration = 0; // some name changes are not announced in our processing. For these, we have to keep the // first name on the segment auto step_name_id = source_node.name_id; for (std::size_t leg_data_index = 0; leg_data_index < leg_data.size(); ++leg_data_index) { const auto &path_point = leg_data[leg_data_index]; segment_duration += path_point.duration_until_turn; // all changes to this check have to be matched with assemble_geometry if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { BOOST_ASSERT(segment_duration >= 0); const auto name = facade.GetNameForID(step_name_id); const auto pronunciation = facade.GetPronunciationForID(step_name_id); const auto destinations = facade.GetDestinationsForID(step_name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{step_name_id, std::move(name), std::move(pronunciation), std::move(destinations), NO_ROTARY_NAME, segment_duration / 10.0, distance, path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); if (leg_data_index + 1 < leg_data.size()) { step_name_id = leg_data[leg_data_index + 1].name_id; } else { step_name_id = target_node.name_id; } bearings = detail::getIntermediateBearings(leg_geometry, segment_index); const auto entry_class = facade.GetEntryClass(path_point.entry_classid); const auto bearing_class = facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node)); intersection.in = bearing_class.findMatchingBearing( util::bearing::reverseBearing(bearings.first)); intersection.out = bearing_class.findMatchingBearing(bearings.second); intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node); intersection.bearings.clear(); intersection.bearings.reserve(bearing_class.getAvailableBearings().size()); std::copy(bearing_class.getAvailableBearings().begin(), bearing_class.getAvailableBearings().end(), std::back_inserter(intersection.bearings)); intersection.entry.clear(); for (auto idx : util::irange<std::size_t>(0, intersection.bearings.size())) { intersection.entry.push_back(entry_class.allowsEntry(idx)); } maneuver = {intersection.location, bearings.first, bearings.second, path_point.turn_instruction, WaypointType::None, 0}; segment_index++; segment_duration = 0; } } const auto distance = leg_geometry.segment_distances[segment_index]; const int duration = segment_duration + target_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{step_name_id, facade.GetNameForID(step_name_id), facade.GetPronunciationForID(step_name_id), facade.GetDestinationsForID(step_name_id), NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); } // In this case the source + target are on the same edge segment else { BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position); // s t // u-------------v // |---| source_duration // |---------| target_duration int duration = target_duration - source_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id), facade.GetPronunciationForID(source_node.name_id), facade.GetDestinationsForID(source_node.name_id), NO_ROTARY_NAME, duration / 10., leg_geometry.segment_distances[segment_index], source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); } BOOST_ASSERT(segment_index == number_of_segments - 1); bearings = detail::getArriveBearings(leg_geometry); // This step has length zero, the only reason we need it is the target location maneuver = {intersection.location, bearings.first, bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, 0}; intersection = { target_node.location, std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}), std::vector<bool>({true}), 0, Intersection::NO_INDEX}; BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), facade.GetPronunciationForID(target_node.name_id), facade.GetDestinationsForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode, std::move(maneuver), leg_geometry.locations.size() - 1, leg_geometry.locations.size(), {intersection}}); BOOST_ASSERT(steps.front().intersections.size() == 1); BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.front().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.front().maneuver.waypoint_type == WaypointType::Depart); BOOST_ASSERT(steps.back().intersections.size() == 1); BOOST_ASSERT(steps.back().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.back().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.back().maneuver.waypoint_type == WaypointType::Arrive); return steps; }
Status HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) override final { if (max_locations_viaroute > 0 && (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute)) { json_result.values["status_message"] = "Number of entries " + std::to_string(route_parameters.coordinates.size()) + " is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")"; return Status::Error; } if (!check_all_coordinates(route_parameters.coordinates)) { json_result.values["status_message"] = "Invalid coordinates"; return Status::Error; } const auto &input_bearings = route_parameters.bearings; if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size()) { json_result.values["status_message"] = "Number of bearings does not match number of coordinate"; return Status::Error; } std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size())) { if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) { ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], phantom_node_pair_list[i].first); if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) { continue; } } const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; const int range = input_bearings.size() > 0 ? (input_bearings[i].second ? *input_bearings[i].second : 10) : 180; phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent( route_parameters.coordinates[i], bearing, range); // we didn't found a fitting node, return error if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) { json_result.values["status_message"] = std::string("Could not find a matching segment for coordinate ") + std::to_string(i); return Status::NoSegment; } BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())); BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes())); } auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list); InternalRouteResult raw_route; auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node, const PhantomNode &second_node) { raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node}); }; osrm::for_each_pair(snapped_phantoms, build_phantom_pairs); if (1 == raw_route.segment_end_coordinates.size()) { if (route_parameters.alternate_route) { search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(), raw_route); } else { search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route); } } else { search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route); } bool no_route = INVALID_EDGE_WEIGHT == raw_route.shortest_path_length; std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; switch (descriptor_table.get_id(route_parameters.output_format)) { case 1: descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade); break; // case 2: // descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>(); // break; default: descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade); break; } descriptor->SetConfig(route_parameters); descriptor->Run(raw_route, json_result); // we can only know this after the fact, different SCC ids still // allow for connection in one direction. if (no_route) { auto first_component_id = snapped_phantoms.front().component.id; auto not_in_same_component = std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(), [first_component_id](const PhantomNode &node) { return node.component.id != first_component_id; }); if (not_in_same_component) { json_result.values["status_message"] = "Impossible route between points"; return Status::EmptyResult; } } else { json_result.values["status_message"] = "Found route between points"; } return Status::Ok; }
int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) override final { if (!check_all_coordinates(route_parameters.coordinates)) { return 400; } std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size())) { if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) { ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], phantom_node_pair_list[i]); if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) { continue; } } std::vector<PhantomNode> phantom_node_vector; if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], phantom_node_vector, 1)) { BOOST_ASSERT(!phantom_node_vector.empty()); phantom_node_pair_list[i].first = phantom_node_vector.front(); if (phantom_node_vector.size() > 1) { phantom_node_pair_list[i].second = phantom_node_vector.back(); } } } auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair) { return phantom_pair.first.component_id != 0; }; const bool every_phantom_is_in_tiny_cc = std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), check_component_id_is_tiny); // are all phantoms from a tiny cc? const auto component_id = phantom_node_pair_list.front().first.component_id; auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair) { return component_id == phantom_pair.first.component_id; }; const bool every_phantom_has_equal_id = std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), check_component_id_is_equal); auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair) { if (0 != phantom_pair.first.component_id) { using namespace std; swap(phantom_pair.first, phantom_pair.second); } }; // this case is true if we take phantoms from the big CC if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id) { std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), swap_phantom_from_big_cc_into_front); } InternalRouteResult raw_route; auto build_phantom_pairs = [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair) { raw_route.segment_end_coordinates.emplace_back( PhantomNodes{first_pair.first, second_pair.first}); }; osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs); if (route_parameters.alternate_route && 1 == raw_route.segment_end_coordinates.size()) { search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(), raw_route); } else { search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route); } if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) { SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found"; } std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; switch (descriptor_table.get_id(route_parameters.output_format)) { case 1: descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade); break; // case 2: // descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>(); // break; default: descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade); break; } DescriptorConfig config = route_parameters; descriptor->SetConfig(config); descriptor->Run(raw_route, json_result); return 200; }
inline void UnpackCHPath(const DataFacadeT &facade, BidirectionalIterator packed_path_begin, BidirectionalIterator packed_path_end, Callback &&callback) { // make sure we have at least something to unpack if (packed_path_begin == packed_path_end) return; using EdgeData = typename DataFacadeT::EdgeData; std::stack<std::pair<NodeID, NodeID>> recursion_stack; // We have to push the path in reverse order onto the stack because it's LIFO. for (auto current = std::prev(packed_path_end); current != packed_path_begin; current = std::prev(current)) { recursion_stack.emplace(*std::prev(current), *current); } std::pair<NodeID, NodeID> edge; while (!recursion_stack.empty()) { edge = recursion_stack.top(); recursion_stack.pop(); // Look for an edge on the forward CH graph (.forward) EdgeID smaller_edge_id = facade.FindSmallestEdge( edge.first, edge.second, [](const EdgeData &data) { return data.forward; }); // If we didn't find one there, the we might be looking at a part of the path that // was found using the backward search. Here, we flip the node order (.second, .first) // and only consider edges with the `.backward` flag. if (SPECIAL_EDGEID == smaller_edge_id) { smaller_edge_id = facade.FindSmallestEdge( edge.second, edge.first, [](const EdgeData &data) { return data.backward; }); } // If we didn't find anything *still*, then something is broken and someone has // called this function with bad values. BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID"); const auto &data = facade.GetEdgeData(smaller_edge_id); BOOST_ASSERT_MSG(data.distance != std::numeric_limits<EdgeWeight>::max(), "edge weight invalid"); // If the edge is a shortcut, we need to add the two halfs to the stack. if (data.shortcut) { // unpack const NodeID middle_node_id = data.id; // Note the order here - we're adding these to a stack, so we // want the first->middle to get visited before middle->second recursion_stack.emplace(middle_node_id, edge.second); recursion_stack.emplace(edge.first, middle_node_id); } else { // We found an original edge, call our callback. std::forward<Callback>(callback)(edge, data); } } }
void operator()(const DataFacadeT &facade, const std::vector<PhantomNodes> &phantom_nodes_vector, InternalRouteResult &raw_route_data) const { // Get weight to next pair of target nodes. BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(), "Direct Shortest Path Query only accepts a single source and target pair. " "Multiple ones have been specified."); const auto &phantom_node_pair = phantom_nodes_vector.front(); const auto &source_phantom = phantom_node_pair.source_phantom; const auto &target_phantom = phantom_node_pair.target_phantom; engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); QueryHeap &forward_heap = *(engine_working_data.forward_heap_1); QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1); forward_heap.Clear(); reverse_heap.Clear(); BOOST_ASSERT(source_phantom.IsValid()); BOOST_ASSERT(target_phantom.IsValid()); if (source_phantom.forward_segment_id.enabled) { forward_heap.Insert(source_phantom.forward_segment_id.id, -source_phantom.GetForwardWeightPlusOffset(), source_phantom.forward_segment_id.id); } if (source_phantom.reverse_segment_id.enabled) { forward_heap.Insert(source_phantom.reverse_segment_id.id, -source_phantom.GetReverseWeightPlusOffset(), source_phantom.reverse_segment_id.id); } if (target_phantom.forward_segment_id.enabled) { reverse_heap.Insert(target_phantom.forward_segment_id.id, target_phantom.GetForwardWeightPlusOffset(), target_phantom.forward_segment_id.id); } if (target_phantom.reverse_segment_id.enabled) { reverse_heap.Insert(target_phantom.reverse_segment_id.id, target_phantom.GetReverseWeightPlusOffset(), target_phantom.reverse_segment_id.id); } int weight = INVALID_EDGE_WEIGHT; std::vector<NodeID> packed_leg; const bool constexpr DO_NOT_FORCE_LOOPS = false; // prevents forcing of loops, since offsets are set correctly if (facade.GetCoreSize() > 0) { engine_working_data.InitializeOrClearSecondThreadLocalStorage( facade.GetNumberOfNodes()); QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2); QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2); forward_core_heap.Clear(); reverse_core_heap.Clear(); super::SearchWithCore(facade, forward_heap, reverse_heap, forward_core_heap, reverse_core_heap, weight, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS); } else { super::Search(facade, forward_heap, reverse_heap, weight, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS); } // No path found for both target nodes? if (INVALID_EDGE_WEIGHT == weight) { raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT; raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT; return; } BOOST_ASSERT_MSG(!packed_leg.empty(), "packed path empty"); raw_route_data.shortest_path_length = weight; raw_route_data.unpacked_path_segments.resize(1); raw_route_data.source_traversed_in_reverse.push_back( (packed_leg.front() != phantom_node_pair.source_phantom.forward_segment_id.id)); raw_route_data.target_traversed_in_reverse.push_back( (packed_leg.back() != phantom_node_pair.target_phantom.forward_segment_id.id)); super::UnpackPath(facade, packed_leg.begin(), packed_leg.end(), phantom_node_pair, raw_route_data.unpacked_path_segments.front()); }
std::vector<EdgeWeight> operator()(const DataFacadeT &facade, const std::vector<PhantomNode> &phantom_nodes, const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &target_indices) const { const auto number_of_sources = source_indices.empty() ? phantom_nodes.size() : source_indices.size(); const auto number_of_targets = target_indices.empty() ? phantom_nodes.size() : target_indices.size(); const auto number_of_entries = number_of_sources * number_of_targets; std::vector<EdgeWeight> result_table(number_of_entries, std::numeric_limits<EdgeWeight>::max()); engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); QueryHeap &query_heap = *(engine_working_data.forward_heap_1); SearchSpaceWithBuckets search_space_with_buckets; unsigned column_idx = 0; const auto search_target_phantom = [&](const PhantomNode &phantom) { query_heap.Clear(); // insert target(s) at weight 0 if (phantom.forward_segment_id.enabled) { query_heap.Insert(phantom.forward_segment_id.id, phantom.GetForwardWeightPlusOffset(), phantom.forward_segment_id.id); } if (phantom.reverse_segment_id.enabled) { query_heap.Insert(phantom.reverse_segment_id.id, phantom.GetReverseWeightPlusOffset(), phantom.reverse_segment_id.id); } // explore search space while (!query_heap.Empty()) { BackwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets); } ++column_idx; }; // for each source do forward search unsigned row_idx = 0; const auto search_source_phantom = [&](const PhantomNode &phantom) { query_heap.Clear(); // insert target(s) at weight 0 if (phantom.forward_segment_id.enabled) { query_heap.Insert(phantom.forward_segment_id.id, -phantom.GetForwardWeightPlusOffset(), phantom.forward_segment_id.id); } if (phantom.reverse_segment_id.enabled) { query_heap.Insert(phantom.reverse_segment_id.id, -phantom.GetReverseWeightPlusOffset(), phantom.reverse_segment_id.id); } // explore search space while (!query_heap.Empty()) { ForwardRoutingStep(facade, row_idx, number_of_targets, query_heap, search_space_with_buckets, result_table); } ++row_idx; }; if (target_indices.empty()) { for (const auto &phantom : phantom_nodes) { search_target_phantom(phantom); } } else { for (const auto index : target_indices) { const auto &phantom = phantom_nodes[index]; search_target_phantom(phantom); } } if (source_indices.empty()) { for (const auto &phantom : phantom_nodes) { search_source_phantom(phantom); } } else { for (const auto index : source_indices) { const auto &phantom = phantom_nodes[index]; search_source_phantom(phantom); } } return result_table; }
void AlternativeRoutingStep(QueryHeap &heap1, QueryHeap &heap2, NodeID *middle_node, int *upper_bound_to_shortest_path_distance, std::vector<NodeID> &search_space_intersection, std::vector<SearchSpaceEdge> &search_space, const EdgeWeight min_edge_offset) const { QueryHeap &forward_heap = (is_forward_directed ? heap1 : heap2); QueryHeap &reverse_heap = (is_forward_directed ? heap2 : heap1); const NodeID node = forward_heap.DeleteMin(); const int distance = forward_heap.GetKey(node); // const NodeID parentnode = forward_heap.GetData(node).parent; // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge (" // << parentnode << "," << node << "), dist: " << distance; const int scaled_distance = static_cast<int>((distance + min_edge_offset) / (1. + VIAPATH_EPSILON)); if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) && (scaled_distance > *upper_bound_to_shortest_path_distance)) { forward_heap.DeleteAll(); return; } search_space.emplace_back(forward_heap.GetData(node).parent, node); if (reverse_heap.WasInserted(node)) { search_space_intersection.emplace_back(node); const int new_distance = reverse_heap.GetKey(node) + distance; if (new_distance < *upper_bound_to_shortest_path_distance) { if (new_distance >= 0) { *middle_node = node; *upper_bound_to_shortest_path_distance = new_distance; // SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at // distance " << new_distance; // } else { // SimpleLogger().Write() << "discarded middle_node " << *middle_node << " // at distance " << new_distance; } } } for (auto edge : facade->GetAdjacentEdgeRange(node)) { const EdgeData &data = facade->GetEdgeData(edge); const bool edge_is_forward_directed = (is_forward_directed ? data.forward : data.backward); if (edge_is_forward_directed) { const NodeID to = facade->GetTarget(edge); const int edge_weight = data.distance; BOOST_ASSERT(edge_weight > 0); const int to_distance = distance + edge_weight; // New Node discovered -> Add to Heap + Node Info Storage if (!forward_heap.WasInserted(to)) { forward_heap.Insert(to, to_distance, node); } // Found a shorter Path -> Update distance else if (to_distance < forward_heap.GetKey(to)) { // new parent forward_heap.GetData(to).parent = node; // decreased distance forward_heap.DecreaseKey(to, to_distance); } } } }
// TODO: reorder parameters // compute and unpack <s,..,v> and <v,..,t> by exploring search spaces // from v and intersecting against queues. only half-searches have to be // done at this stage void ComputeLengthAndSharingOfViaPath(const NodeID via_node, int *real_length_of_via_path, int *sharing_of_via_path, const std::vector<NodeID> &packed_shortest_path, const EdgeWeight min_edge_offset) { engine_working_data.InitializeOrClearSecondThreadLocalStorage( super::facade->GetNumberOfNodes()); QueryHeap &existing_forward_heap = *engine_working_data.forward_heap_1; QueryHeap &existing_reverse_heap = *engine_working_data.reverse_heap_1; QueryHeap &new_forward_heap = *engine_working_data.forward_heap_2; QueryHeap &new_reverse_heap = *engine_working_data.reverse_heap_2; std::vector<NodeID> packed_s_v_path; std::vector<NodeID> packed_v_t_path; std::vector<NodeID> partially_unpacked_shortest_path; std::vector<NodeID> partially_unpacked_via_path; NodeID s_v_middle = SPECIAL_NODEID; int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT; new_reverse_heap.Insert(via_node, 0, via_node); // compute path <s,..,v> by reusing forward search from s while (!new_reverse_heap.Empty()) { super::RoutingStep(new_reverse_heap, existing_forward_heap, &s_v_middle, &upper_bound_s_v_path_length, min_edge_offset, false); } // compute path <v,..,t> by reusing backward search from node t NodeID v_t_middle = SPECIAL_NODEID; int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT; new_forward_heap.Insert(via_node, 0, via_node); while (!new_forward_heap.Empty()) { super::RoutingStep(new_forward_heap, existing_reverse_heap, &v_t_middle, &upper_bound_of_v_t_path_length, min_edge_offset, true); } *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length; if (SPECIAL_NODEID == s_v_middle || SPECIAL_NODEID == v_t_middle) { return; } // retrieve packed paths super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, s_v_middle, packed_s_v_path); super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, v_t_middle, packed_v_t_path); // partial unpacking, compute sharing // First partially unpack s-->v until paths deviate, note length of common path. const int64_t s_v_min_path_size = std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1; for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size)) { if (packed_s_v_path[current_node] == packed_shortest_path[current_node] && packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1]) { EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_s_v_path[current_node], packed_s_v_path[current_node + 1]); *sharing_of_via_path += facade->GetEdgeData(edgeID).distance; } else { if (packed_s_v_path[current_node] == packed_shortest_path[current_node]) { super::UnpackEdge(packed_s_v_path[current_node], packed_s_v_path[current_node + 1], partially_unpacked_via_path); super::UnpackEdge(packed_shortest_path[current_node], packed_shortest_path[current_node + 1], partially_unpacked_shortest_path); break; } } } // traverse partially unpacked edge and note common prefix const int64_t packed_path_length = std::min(partially_unpacked_via_path.size(), partially_unpacked_shortest_path.size()) - 1; for (int64_t current_node = 0; (current_node < packed_path_length) && (partially_unpacked_via_path[current_node] == partially_unpacked_shortest_path[current_node] && partially_unpacked_via_path[current_node + 1] == partially_unpacked_shortest_path[current_node + 1]); ++current_node) { EdgeID selected_edge = facade->FindEdgeInEitherDirection(partially_unpacked_via_path[current_node], partially_unpacked_via_path[current_node + 1]); *sharing_of_via_path += facade->GetEdgeData(selected_edge).distance; } // Second, partially unpack v-->t in reverse order until paths deviate and note lengths int64_t via_path_index = packed_v_t_path.size() - 1; int64_t shortest_path_index = packed_shortest_path.size() - 1; for (; via_path_index > 0 && shortest_path_index > 0; --via_path_index, --shortest_path_index) { if (packed_v_t_path[via_path_index - 1] == packed_shortest_path[shortest_path_index - 1] && packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index]) { EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_v_t_path[via_path_index - 1], packed_v_t_path[via_path_index]); *sharing_of_via_path += facade->GetEdgeData(edgeID).distance; } else { if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index]) { super::UnpackEdge(packed_v_t_path[via_path_index - 1], packed_v_t_path[via_path_index], partially_unpacked_via_path); super::UnpackEdge(packed_shortest_path[shortest_path_index - 1], packed_shortest_path[shortest_path_index], partially_unpacked_shortest_path); break; } } } via_path_index = partially_unpacked_via_path.size() - 1; shortest_path_index = partially_unpacked_shortest_path.size() - 1; for (; via_path_index > 0 && shortest_path_index > 0; --via_path_index, --shortest_path_index) { if (partially_unpacked_via_path[via_path_index - 1] == partially_unpacked_shortest_path[shortest_path_index - 1] && partially_unpacked_via_path[via_path_index] == partially_unpacked_shortest_path[shortest_path_index]) { EdgeID edgeID = facade->FindEdgeInEitherDirection( partially_unpacked_via_path[via_path_index - 1], partially_unpacked_via_path[via_path_index]); *sharing_of_via_path += facade->GetEdgeData(edgeID).distance; } else { break; } } // finished partial unpacking spree! Amount of sharing is stored to appropriate pointer // variable }
virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) override final { if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) { // We do not need to do much, if there is no route ;-) return; } // check if first segment is non-zero BOOST_ASSERT(raw_route.unpacked_path_segments.size() == raw_route.segment_end_coordinates.size()); description_factory.SetStartSegment( raw_route.segment_end_coordinates.front().source_phantom, raw_route.source_traversed_in_reverse.front()); // for each unpacked segment add the leg to the description for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size())) { #ifndef NDEBUG const int added_segments = #endif DescribeLeg(raw_route.unpacked_path_segments[i], raw_route.segment_end_coordinates[i], raw_route.target_traversed_in_reverse[i], raw_route.is_via_leg(i)); BOOST_ASSERT(0 < added_segments); } description_factory.Run(config.zoom_level); if (config.geometry) { osrm::json::Value route_geometry = description_factory.AppendGeometryString(config.encode_geometry); json_result.values["route_geometry"] = route_geometry; } if (config.instructions) { osrm::json::Array json_route_instructions = BuildTextualDescription(description_factory, shortest_path_segments); json_result.values["route_instructions"] = json_route_instructions; } description_factory.BuildRouteSummary(description_factory.get_entire_length(), raw_route.shortest_path_length); osrm::json::Object json_route_summary; json_route_summary.values["total_distance"] = description_factory.summary.distance; json_route_summary.values["total_time"] = description_factory.summary.duration; json_route_summary.values["start_point"] = facade->get_name_for_id(description_factory.summary.source_name_id); json_route_summary.values["end_point"] = facade->get_name_for_id(description_factory.summary.target_name_id); json_result.values["route_summary"] = json_route_summary; BOOST_ASSERT(!raw_route.segment_end_coordinates.empty()); osrm::json::Array json_via_points_array; osrm::json::Array json_first_coordinate; json_first_coordinate.values.push_back( raw_route.segment_end_coordinates.front().source_phantom.location.lat / COORDINATE_PRECISION); json_first_coordinate.values.push_back( raw_route.segment_end_coordinates.front().source_phantom.location.lon / COORDINATE_PRECISION); json_via_points_array.values.push_back(json_first_coordinate); for (const PhantomNodes &nodes : raw_route.segment_end_coordinates) { std::string tmp; osrm::json::Array json_coordinate; json_coordinate.values.push_back(nodes.target_phantom.location.lat / COORDINATE_PRECISION); json_coordinate.values.push_back(nodes.target_phantom.location.lon / COORDINATE_PRECISION); json_via_points_array.values.push_back(json_coordinate); } json_result.values["via_points"] = json_via_points_array; osrm::json::Array json_via_indices_array; std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices(); json_via_indices_array.values.insert(json_via_indices_array.values.end(), shortest_leg_end_indices.begin(), shortest_leg_end_indices.end()); json_result.values["via_indices"] = json_via_indices_array; // only one alternative route is computed at this time, so this is hardcoded if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) { json_result.values["found_alternative"] = osrm::json::True(); BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty()); alternate_description_factory.SetStartSegment( raw_route.segment_end_coordinates.front().source_phantom, raw_route.alt_source_traversed_in_reverse.front()); // Get all the coordinates for the computed route for (const PathData &path_data : raw_route.unpacked_alternative) { current = facade->GetCoordinateOfNode(path_data.node); alternate_description_factory.AppendSegment(current, path_data); } alternate_description_factory.SetEndSegment( raw_route.segment_end_coordinates.back().target_phantom, raw_route.alt_source_traversed_in_reverse.back()); alternate_description_factory.Run(config.zoom_level); if (config.geometry) { osrm::json::Value alternate_geometry_string = alternate_description_factory.AppendGeometryString(config.encode_geometry); osrm::json::Array json_alternate_geometries_array; json_alternate_geometries_array.values.push_back(alternate_geometry_string); json_result.values["alternative_geometries"] = json_alternate_geometries_array; } // Generate instructions for each alternative (simulated here) osrm::json::Array json_alt_instructions; osrm::json::Array json_current_alt_instructions; if (config.instructions) { json_current_alt_instructions = BuildTextualDescription(alternate_description_factory, alternative_path_segments); json_alt_instructions.values.push_back(json_current_alt_instructions); json_result.values["alternative_instructions"] = json_alt_instructions; } alternate_description_factory.BuildRouteSummary( alternate_description_factory.get_entire_length(), raw_route.alternative_path_length); osrm::json::Object json_alternate_route_summary; osrm::json::Array json_alternate_route_summary_array; json_alternate_route_summary.values["total_distance"] = alternate_description_factory.summary.distance; json_alternate_route_summary.values["total_time"] = alternate_description_factory.summary.duration; json_alternate_route_summary.values["start_point"] = facade->get_name_for_id(alternate_description_factory.summary.source_name_id); json_alternate_route_summary.values["end_point"] = facade->get_name_for_id(alternate_description_factory.summary.target_name_id); json_alternate_route_summary_array.values.push_back(json_alternate_route_summary); json_result.values["alternative_summaries"] = json_alternate_route_summary_array; std::vector<unsigned> const &alternate_leg_end_indices = alternate_description_factory.GetViaIndices(); osrm::json::Array json_altenative_indices_array; json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(), alternate_leg_end_indices.begin(), alternate_leg_end_indices.end()); json_result.values["alternative_indices"] = json_altenative_indices_array; } else { json_result.values["found_alternative"] = osrm::json::False(); } // Get Names for both routes RouteNames route_names = GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade); osrm::json::Array json_route_names; json_route_names.values.push_back(route_names.shortest_path_name_1); json_route_names.values.push_back(route_names.shortest_path_name_2); json_result.values["route_name"] = json_route_names; if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) { osrm::json::Array json_alternate_names_array; osrm::json::Array json_alternate_names; json_alternate_names.values.push_back(route_names.alternative_path_name_1); json_alternate_names.values.push_back(route_names.alternative_path_name_2); json_alternate_names_array.values.push_back(json_alternate_names); json_result.values["alternative_names"] = json_alternate_names_array; } json_result.values["hint_data"] = BuildHintData(raw_route); }
inline osrm::json::Array BuildTextualDescription(const DescriptionFactory &description_factory, std::vector<Segment> &route_segments_list) const { osrm::json::Array json_instruction_array; // Segment information has following format: //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth] unsigned necessary_segments_running_index = 0; struct RoundAbout { RoundAbout() : start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID), leave_at_exit(std::numeric_limits<int>::max()) {} int start_index; unsigned name_id; int leave_at_exit; } round_about; round_about.leave_at_exit = 0; round_about.name_id = 0; std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction; TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT; // Fetch data from Factory and generate a string from it. for (const SegmentInformation &segment : description_factory.path_description) { osrm::json::Array json_instruction_row; TurnInstruction current_instruction = segment.turn_instruction; if (TurnInstructionsClass::TurnIsNecessary(current_instruction)) { if (TurnInstruction::EnterRoundAbout == current_instruction) { round_about.name_id = segment.name_id; round_about.start_index = necessary_segments_running_index; } else { std::string current_turn_instruction; if (TurnInstruction::LeaveRoundAbout == current_instruction) { temp_instruction = std::to_string( cast::enum_to_underlying(TurnInstruction::EnterRoundAbout)); current_turn_instruction += temp_instruction; current_turn_instruction += "-"; temp_instruction = std::to_string(round_about.leave_at_exit + 1); current_turn_instruction += temp_instruction; round_about.leave_at_exit = 0; } else { temp_instruction = std::to_string(cast::enum_to_underlying(current_instruction)); current_turn_instruction += temp_instruction; } json_instruction_row.values.push_back(current_turn_instruction); json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id)); json_instruction_row.values.push_back(std::round(segment.length)); json_instruction_row.values.push_back(necessary_segments_running_index); json_instruction_row.values.push_back(std::round(segment.duration / 10.)); json_instruction_row.values.push_back( std::to_string(static_cast<unsigned>(segment.length)) + "m"); // post turn bearing const double post_turn_bearing_value = (segment.post_turn_bearing / 10.); json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value)); json_instruction_row.values.push_back( static_cast<unsigned>(round(post_turn_bearing_value))); json_instruction_row.values.push_back(segment.travel_mode); last_travel_mode = segment.travel_mode; // pre turn bearing const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.); json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value)); json_instruction_row.values.push_back( static_cast<unsigned>(round(pre_turn_bearing_value))); json_instruction_array.values.push_back(json_instruction_row); route_segments_list.emplace_back( segment.name_id, static_cast<int>(segment.length), static_cast<unsigned>(route_segments_list.size())); } } else if (TurnInstruction::StayOnRoundAbout == current_instruction) { ++round_about.leave_at_exit; } if (segment.necessary) { ++necessary_segments_running_index; } } osrm::json::Array json_last_instruction_row; temp_instruction = std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination)); json_last_instruction_row.values.push_back(temp_instruction); json_last_instruction_row.values.push_back(""); json_last_instruction_row.values.push_back(0); json_last_instruction_row.values.push_back(necessary_segments_running_index - 1); json_last_instruction_row.values.push_back(0); json_last_instruction_row.values.push_back("0m"); json_last_instruction_row.values.push_back(bearing::get(0.0)); json_last_instruction_row.values.push_back(0.); json_last_instruction_row.values.push_back(last_travel_mode); json_last_instruction_row.values.push_back(bearing::get(0.0)); json_last_instruction_row.values.push_back(0.); json_instruction_array.values.push_back(json_last_instruction_row); return json_instruction_array; }
// conduct T-Test bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap, QueryHeap &existing_reverse_heap, QueryHeap &new_forward_heap, QueryHeap &new_reverse_heap, const RankedCandidateNode &candidate, const int length_of_shortest_path, int *length_of_via_path, NodeID *s_v_middle, NodeID *v_t_middle, const EdgeWeight min_edge_offset) const { new_forward_heap.Clear(); new_reverse_heap.Clear(); std::vector<NodeID> packed_s_v_path; std::vector<NodeID> packed_v_t_path; *s_v_middle = SPECIAL_NODEID; int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT; // compute path <s,..,v> by reusing forward search from s new_reverse_heap.Insert(candidate.node, 0, candidate.node); while (new_reverse_heap.Size() > 0) { super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle, &upper_bound_s_v_path_length, min_edge_offset, false); } if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length) { return false; } // compute path <v,..,t> by reusing backward search from t *v_t_middle = SPECIAL_NODEID; int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT; new_forward_heap.Insert(candidate.node, 0, candidate.node); while (new_forward_heap.Size() > 0) { super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle, &upper_bound_of_v_t_path_length, min_edge_offset, true); } if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length) { return false; } *length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length; // retrieve packed paths super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path); super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path); NodeID s_P = *s_v_middle, t_P = *v_t_middle; if (SPECIAL_NODEID == s_P) { return false; } if (SPECIAL_NODEID == t_P) { return false; } const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path); int unpacked_until_distance = 0; std::stack<SearchSpaceEdge> unpack_stack; // Traverse path s-->v for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i) { const EdgeID current_edge_id = facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]); const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance; if ((length_of_current_edge + unpacked_until_distance) >= T_threshold) { unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]); } else { unpacked_until_distance += length_of_current_edge; s_P = packed_s_v_path[i - 1]; } } while (!unpack_stack.empty()) { const SearchSpaceEdge via_path_edge = unpack_stack.top(); unpack_stack.pop(); EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second); if (SPECIAL_EDGEID == edge_in_via_path_id) { return false; } const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id); const bool current_edge_is_shortcut = current_edge_data.shortcut; if (current_edge_is_shortcut) { const NodeID via_path_middle_node_id = current_edge_data.id; const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection( via_path_middle_node_id, via_path_edge.second); const int second_segment_length = facade->GetEdgeData(second_segment_edge_id).distance; // attention: !unpacking in reverse! // Check if second segment is the one to go over treshold? if yes add second segment // to stack, else push first segment to stack and add distance of second one. if (unpacked_until_distance + second_segment_length >= T_threshold) { unpack_stack.emplace(via_path_middle_node_id, via_path_edge.second); } else { unpacked_until_distance += second_segment_length; unpack_stack.emplace(via_path_edge.first, via_path_middle_node_id); } } else { // edge is not a shortcut, set the start node for T-Test to end of edge. unpacked_until_distance += current_edge_data.distance; s_P = via_path_edge.first; } } int t_test_path_length = unpacked_until_distance; unpacked_until_distance = 0; // Traverse path s-->v BOOST_ASSERT(!packed_v_t_path.empty()); for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1); (i < packed_path_length) && unpack_stack.empty(); ++i) { const EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]); int length_of_current_edge = facade->GetEdgeData(edgeID).distance; if (length_of_current_edge + unpacked_until_distance >= T_threshold) { unpack_stack.emplace(packed_v_t_path[i], packed_v_t_path[i + 1]); } else { unpacked_until_distance += length_of_current_edge; t_P = packed_v_t_path[i + 1]; } } while (!unpack_stack.empty()) { const SearchSpaceEdge via_path_edge = unpack_stack.top(); unpack_stack.pop(); EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second); if (SPECIAL_EDGEID == edge_in_via_path_id) { return false; } const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id); const bool IsViaEdgeShortCut = current_edge_data.shortcut; if (IsViaEdgeShortCut) { const NodeID middleOfViaPath = current_edge_data.id; EdgeID edgeIDOfFirstSegment = facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath); int lengthOfFirstSegment = facade->GetEdgeData(edgeIDOfFirstSegment).distance; // Check if first segment is the one to go over treshold? if yes first segment to // stack, else push second segment to stack and add distance of first one. if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold) { unpack_stack.emplace(via_path_edge.first, middleOfViaPath); } else { unpacked_until_distance += lengthOfFirstSegment; unpack_stack.emplace(middleOfViaPath, via_path_edge.second); } } else { // edge is not a shortcut, set the start node for T-Test to end of edge. unpacked_until_distance += current_edge_data.distance; t_P = via_path_edge.second; } } t_test_path_length += unpacked_until_distance; // Run actual T-Test query and compare if distances equal. engine_working_data.InitializeOrClearThirdThreadLocalStorage( super::facade->GetNumberOfNodes()); QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3; QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3; int upper_bound = INVALID_EDGE_WEIGHT; NodeID middle = SPECIAL_NODEID; forward_heap3.Insert(s_P, 0, s_P); reverse_heap3.Insert(t_P, 0, t_P); // exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path while ((forward_heap3.Size() + reverse_heap3.Size()) > 0) { if (!forward_heap3.Empty()) { super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound, min_edge_offset, true); } if (!reverse_heap3.Empty()) { super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound, min_edge_offset, false); } } return (upper_bound <= t_test_path_length); }