2016-01-28 10:28:44 -05:00
|
|
|
#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
|
|
|
|
#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
|
|
|
|
|
|
|
|
#include "engine/guidance/route_step.hpp"
|
|
|
|
#include "engine/guidance/step_maneuver.hpp"
|
|
|
|
#include "engine/guidance/leg_geometry.hpp"
|
2016-03-01 16:30:31 -05:00
|
|
|
#include "engine/guidance/toolkit.hpp"
|
|
|
|
#include "extractor/guidance/turn_instruction.hpp"
|
2016-01-28 10:28:44 -05:00
|
|
|
#include "engine/internal_route_result.hpp"
|
|
|
|
#include "engine/phantom_node.hpp"
|
|
|
|
#include "util/coordinate_calculation.hpp"
|
|
|
|
#include "util/coordinate.hpp"
|
2016-02-24 04:29:23 -05:00
|
|
|
#include "util/bearing.hpp"
|
2016-01-28 10:28:44 -05:00
|
|
|
#include "extractor/travel_mode.hpp"
|
|
|
|
|
|
|
|
#include <vector>
|
2016-02-25 04:01:16 -05:00
|
|
|
#include <boost/optional.hpp>
|
2016-01-28 10:28:44 -05:00
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace engine
|
|
|
|
{
|
|
|
|
namespace guidance
|
|
|
|
{
|
|
|
|
namespace detail
|
|
|
|
{
|
2016-03-03 09:34:13 -05:00
|
|
|
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
|
2016-03-10 05:22:45 -05:00
|
|
|
const WaypointType waypoint_type,
|
2016-03-03 09:34:13 -05:00
|
|
|
const LegGeometry &leg_geometry,
|
2016-03-21 13:07:28 -04:00
|
|
|
const std::size_t segment_index);
|
2016-03-03 09:34:13 -05:00
|
|
|
} // ns detail
|
2016-01-28 10:28:44 -05:00
|
|
|
|
|
|
|
template <typename DataFacadeT>
|
|
|
|
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,
|
2016-03-07 12:59:39 -05:00
|
|
|
const bool target_traversed_in_reverse)
|
2016-01-28 10:28:44 -05:00
|
|
|
{
|
2016-03-08 10:46:01 -05:00
|
|
|
const double constexpr ZERO_DURACTION = 0., ZERO_DISTANCE = 0., NO_BEARING = 0.;
|
2016-03-17 15:39:19 -04:00
|
|
|
const EdgeWeight source_duration =
|
2016-03-18 11:14:48 -04:00
|
|
|
source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight;
|
2016-01-28 10:28:44 -05:00
|
|
|
const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
|
|
|
|
: source_node.forward_travel_mode;
|
|
|
|
|
2016-03-17 15:39:19 -04:00
|
|
|
const EdgeWeight target_duration =
|
2016-03-18 11:14:48 -04:00
|
|
|
target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight;
|
2016-01-28 10:28:44 -05:00
|
|
|
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);
|
|
|
|
|
2016-02-29 10:24:42 -05:00
|
|
|
std::size_t segment_index = 0;
|
2016-03-08 10:46:01 -05:00
|
|
|
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
|
|
|
|
|
|
|
|
// We report the relative position of source/target to the road only within a range that is
|
|
|
|
// sufficiently different but not full of the path
|
|
|
|
const constexpr double MINIMAL_RELATIVE_DISTANCE = 5., MAXIMAL_RELATIVE_DISTANCE = 300.;
|
|
|
|
const auto distance_to_start = util::coordinate_calculation::haversineDistance(
|
|
|
|
source_node.input_location, leg_geometry.locations[0]);
|
2016-03-01 16:30:31 -05:00
|
|
|
const auto initial_modifier =
|
2016-03-08 10:46:01 -05:00
|
|
|
distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
|
|
|
|
distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
|
2016-03-01 16:30:31 -05:00
|
|
|
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
2016-03-08 10:46:01 -05:00
|
|
|
source_node.input_location, leg_geometry.locations[0],
|
|
|
|
leg_geometry.locations[1]))
|
2016-03-01 16:30:31 -05:00
|
|
|
: extractor::guidance::DirectionModifier::UTurn;
|
|
|
|
|
2016-01-28 10:28:44 -05:00
|
|
|
if (leg_data.size() > 0)
|
|
|
|
{
|
2016-02-25 04:01:16 -05:00
|
|
|
|
2016-02-26 11:33:18 -05:00
|
|
|
StepManeuver maneuver = detail::stepManeuverFromGeometry(
|
2016-03-10 05:22:45 -05:00
|
|
|
extractor::guidance::TurnInstruction{extractor::guidance::TurnType::NoTurn,
|
2016-03-01 16:30:31 -05:00
|
|
|
initial_modifier},
|
2016-03-21 13:07:28 -04:00
|
|
|
WaypointType::Depart, leg_geometry, segment_index);
|
2016-01-28 10:28:44 -05:00
|
|
|
|
|
|
|
// 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
|
2016-02-24 04:29:23 -05:00
|
|
|
// initial start of a route
|
2016-03-17 15:39:19 -04:00
|
|
|
int segment_duration = 0;
|
2016-01-28 10:28:44 -05:00
|
|
|
for (const auto &path_point : leg_data)
|
|
|
|
{
|
2016-03-17 15:39:19 -04:00
|
|
|
segment_duration += path_point.duration_until_turn;
|
|
|
|
|
2016-03-21 13:07:28 -04:00
|
|
|
if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn)
|
2016-01-28 10:28:44 -05:00
|
|
|
{
|
2016-03-17 15:39:19 -04:00
|
|
|
BOOST_ASSERT(segment_duration >= 0);
|
2016-03-18 14:21:13 -04:00
|
|
|
const auto name = facade.GetNameForID(path_point.name_id);
|
2016-01-28 10:28:44 -05:00
|
|
|
const auto distance = leg_geometry.segment_distances[segment_index];
|
2016-03-08 10:46:01 -05:00
|
|
|
steps.push_back(RouteStep{path_point.name_id,
|
|
|
|
name,
|
|
|
|
segment_duration / 10.0,
|
|
|
|
distance,
|
|
|
|
path_point.travel_mode,
|
|
|
|
maneuver,
|
2016-03-17 15:39:19 -04:00
|
|
|
leg_geometry.FrontIndex(segment_index),
|
|
|
|
leg_geometry.BackIndex(segment_index) + 1});
|
|
|
|
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
|
|
|
|
WaypointType::None, leg_geometry,
|
2016-03-21 13:07:28 -04:00
|
|
|
segment_index);
|
2016-01-28 10:28:44 -05:00
|
|
|
segment_index++;
|
2016-03-17 15:39:19 -04:00
|
|
|
segment_duration = 0;
|
2016-01-28 10:28:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
const auto distance = leg_geometry.segment_distances[segment_index];
|
2016-03-17 15:39:19 -04:00
|
|
|
const int duration = segment_duration + target_duration;
|
|
|
|
BOOST_ASSERT(duration >= 0);
|
2016-03-08 10:46:01 -05:00
|
|
|
steps.push_back(RouteStep{target_node.name_id,
|
2016-03-18 14:21:13 -04:00
|
|
|
facade.GetNameForID(target_node.name_id),
|
2016-03-08 10:46:01 -05:00
|
|
|
duration / 10.,
|
|
|
|
distance,
|
|
|
|
target_mode,
|
|
|
|
maneuver,
|
2016-01-28 10:28:44 -05:00
|
|
|
leg_geometry.FrontIndex(segment_index),
|
|
|
|
leg_geometry.BackIndex(segment_index) + 1});
|
|
|
|
}
|
2016-03-17 15:39:19 -04:00
|
|
|
// In this case the source + target are on the same edge segment
|
2016-01-28 10:28:44 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-17 15:39:19 -04:00
|
|
|
BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position);
|
|
|
|
// s t
|
|
|
|
// u-------------v
|
|
|
|
// |---| source_duration
|
|
|
|
// |---------| target_duration
|
|
|
|
|
2016-03-08 10:46:01 -05:00
|
|
|
StepManeuver maneuver = {source_node.location,
|
|
|
|
NO_BEARING,
|
|
|
|
NO_BEARING,
|
2016-03-01 16:30:31 -05:00
|
|
|
extractor::guidance::TurnInstruction{
|
2016-03-10 05:22:45 -05:00
|
|
|
extractor::guidance::TurnType::NoTurn, initial_modifier},
|
2016-03-08 10:46:01 -05:00
|
|
|
WaypointType::Depart,
|
2016-03-21 13:07:28 -04:00
|
|
|
INVALID_EXIT_NR,
|
2016-03-08 10:46:01 -05:00
|
|
|
INVALID_EXIT_NR};
|
2016-03-17 15:39:19 -04:00
|
|
|
int duration = target_duration - source_duration;
|
|
|
|
BOOST_ASSERT(duration >= 0);
|
2016-02-24 04:29:23 -05:00
|
|
|
|
2016-03-08 10:46:01 -05:00
|
|
|
steps.push_back(RouteStep{source_node.name_id,
|
2016-03-18 14:21:13 -04:00
|
|
|
facade.GetNameForID(source_node.name_id),
|
2016-03-08 10:46:01 -05:00
|
|
|
duration / 10.,
|
|
|
|
leg_geometry.segment_distances[segment_index],
|
|
|
|
source_mode,
|
|
|
|
std::move(maneuver),
|
|
|
|
leg_geometry.FrontIndex(segment_index),
|
2016-02-25 04:01:16 -05:00
|
|
|
leg_geometry.BackIndex(segment_index) + 1});
|
2016-01-28 10:28:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
2016-03-08 10:46:01 -05:00
|
|
|
const auto distance_from_end = util::coordinate_calculation::haversineDistance(
|
|
|
|
target_node.input_location, leg_geometry.locations.back());
|
2016-02-25 04:01:16 -05:00
|
|
|
const auto final_modifier =
|
2016-03-08 10:46:01 -05:00
|
|
|
distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
|
|
|
|
distance_from_end <= MAXIMAL_RELATIVE_DISTANCE
|
2016-03-01 16:30:31 -05:00
|
|
|
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
2016-03-07 12:59:39 -05:00
|
|
|
leg_geometry.locations[leg_geometry.locations.size() - 2],
|
2016-03-08 10:46:01 -05:00
|
|
|
leg_geometry.locations[leg_geometry.locations.size() - 1],
|
|
|
|
target_node.input_location))
|
2016-03-01 16:30:31 -05:00
|
|
|
: extractor::guidance::DirectionModifier::UTurn;
|
2016-01-28 10:28:44 -05:00
|
|
|
// This step has length zero, the only reason we need it is the target location
|
2016-03-08 10:46:01 -05:00
|
|
|
steps.push_back(
|
|
|
|
RouteStep{target_node.name_id,
|
2016-03-18 14:21:13 -04:00
|
|
|
facade.GetNameForID(target_node.name_id),
|
2016-03-08 10:46:01 -05:00
|
|
|
ZERO_DURACTION,
|
|
|
|
ZERO_DISTANCE,
|
|
|
|
target_mode,
|
|
|
|
StepManeuver{target_node.location,
|
|
|
|
NO_BEARING,
|
|
|
|
NO_BEARING,
|
|
|
|
extractor::guidance::TurnInstruction{
|
|
|
|
extractor::guidance::TurnType::NoTurn, final_modifier},
|
|
|
|
WaypointType::Arrive,
|
2016-03-21 13:07:28 -04:00
|
|
|
INVALID_EXIT_NR,
|
2016-03-08 10:46:01 -05:00
|
|
|
INVALID_EXIT_NR},
|
|
|
|
leg_geometry.locations.size(),
|
|
|
|
leg_geometry.locations.size()});
|
2016-01-28 10:28:44 -05:00
|
|
|
|
|
|
|
return steps;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace guidance
|
|
|
|
} // namespace engine
|
|
|
|
} // namespace osrm
|
|
|
|
|
|
|
|
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
|