Add viaroute suport for new API

This commit is contained in:
Patrick Niklaus
2016-01-28 16:28:44 +01:00
parent 54ee76bcef
commit f3e72623e9
87 changed files with 3352 additions and 2099 deletions
@@ -0,0 +1,78 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Extracts the geometry for each segment and calculates the traveled distance
// Combines the geometry form the phantom node with the PathData
// to the full route geometry.
//
// turn 0 1 2 3 4
// s...x...y...z...t
// |---|segment 0
// |---| segment 1
// |---| segment 2
// |---| segment 3
template <typename DataFacadeT>
LegGeometry assembleGeometry(const DataFacadeT &facade,
const std::vector<PathData> &leg_data,
const PhantomNode &source_node,
const PhantomNode &target_node)
{
LegGeometry geometry;
// segment 0 first and last
geometry.segment_offsets.push_back(0);
geometry.locations.push_back(source_node.location);
auto current_distance = 0.;
auto prev_coordinate = geometry.locations.front();
for (const auto &path_point : leg_data)
{
auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node);
current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate);
if (path_point.turn_instruction != extractor::TurnInstruction::NoTurn)
{
geometry.segment_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size());
current_distance = 0.;
}
prev_coordinate = coordinate;
geometry.locations.push_back(std::move(coordinate));
}
current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
// segment leading to the target node
geometry.segment_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size());
geometry.locations.push_back(target_node.location);
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
return geometry;
}
}
}
}
#endif
+165
View File
@@ -0,0 +1,165 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/internal_route_result.hpp"
#include <vector>
#include <array>
#include <algorithm>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
const constexpr std::size_t MAX_USED_SEGMENTS = 2;
struct NamedSegment
{
double duration;
std::uint32_t position;
std::uint32_t name_id;
};
template <std::size_t SegmentNumber>
std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data)
{
// merges segments with same name id
const auto collapse_segments = [](std::vector<NamedSegment> &segments)
{
auto out = segments.begin();
auto end = segments.end();
for (auto in = segments.begin(); in != end; ++in)
{
if (in->name_id == out->name_id)
{
out->duration += in->duration;
}
else
{
++out;
BOOST_ASSERT(out != end);
*out = *in;
}
}
return out;
};
std::vector<NamedSegment> segments(route_data.size());
std::uint32_t index = 0;
std::transform(
route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point)
{
return NamedSegment{point.duration_until_turn / 10.0, index++, point.name_id};
});
// this makes sure that the segment with the lowest position comes first
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.name_id < rhs.name_id ||
(lhs.name_id == rhs.name_id && lhs.position < rhs.position);
});
auto new_end = collapse_segments(segments);
segments.resize(new_end - segments.begin());
// sort descending
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.duration > rhs.duration;
});
// make sure the segments are sorted by position
segments.resize(std::min(segments.size(), SegmentNumber));
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.position < rhs.position;
});
std::array<std::uint32_t, SegmentNumber> summary;
std::fill(summary.begin(), summary.end(), 0);
std::transform(segments.begin(), segments.end(), summary.begin(),
[](const NamedSegment &segment)
{
return segment.name_id;
});
return summary;
}
}
template <typename DataFacadeT>
RouteLeg assembleLeg(const DataFacadeT &facade,
const std::vector<PathData> &route_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 auto source_duration =
(source_traversed_in_reverse ? source_node.GetReverseWeightPlusOffset()
: source_node.GetForwardWeightPlusOffset()) /
10.;
const auto target_duration =
(target_traversed_in_reverse ? target_node.GetReverseWeightPlusOffset()
: target_node.GetForwardWeightPlusOffset()) /
10.;
auto distance = std::accumulate(leg_geometry.segment_distances.begin(),
leg_geometry.segment_distances.end(), 0.);
auto duration = std::accumulate(route_data.begin(), route_data.end(), 0.,
[](const double sum, const PathData &data)
{
return sum + data.duration_until_turn;
}) /
10.;
// s
// |
// Given a route a---b---c where there is a right turn at b.
// |
// d
// |--t
// e
// (a, b, c) gets compressed to (a,c)
// (c, d, e) gets compressed to (c,e)
// The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
// of (a,b,c)).
// The phantom node of s will contain:
// `forward_weight`: duration of (a,s)
// `forward_offset`: 0 (its the first segment)
// The phantom node of t will contain:
// `forward_weight`: duration of (d,t)
// `forward_offset`: duration of (c, d)
//
// The PathData will contain entries of b, c and d. But only c will contain
// a duration value since its the only point associated with a turn.
// As such we want to slice of the duration for (a,s) and add the duration for
// (c,d,t)
duration = duration - source_duration + target_duration;
auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data);
BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
BOOST_ASSERT(summary_array.begin() != summary_array.end());
std::string summary =
std::accumulate(std::next(summary_array.begin()), summary_array.end(),
facade.get_name_for_id(summary_array.front()),
[&facade](std::string previous, const std::uint32_t name_id)
{
if (name_id != 0)
{
previous += ", " + facade.get_name_for_id(name_id);
}
return previous;
});
return RouteLeg{duration, distance, summary, {}};
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
@@ -0,0 +1,22 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#include "engine/guidance/leg_geometry.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
std::vector<util::FixedPointCoordinate>
assembleOverview(const std::vector<LegGeometry> &leg_geometries, const bool use_simplification);
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif
@@ -0,0 +1,37 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route.hpp"
#include <vector>
#include <algorithm>
namespace osrm
{
namespace engine
{
namespace guidance
{
inline Route assembleRoute(const std::vector<RouteLeg> &route_legs)
{
auto distance = std::accumulate(route_legs.begin(),
route_legs.end(), 0.,
[](const double sum, const RouteLeg &leg)
{
return sum + leg.distance;
});
auto duration = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
[](const double sum, const RouteLeg &leg)
{
return sum + leg.duration;
});
return Route{duration, distance};
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif
+135
View File
@@ -0,0 +1,135 @@
#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"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
// FIXME move implementation to cpp
inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction instruction,
const LegGeometry &leg_geometry,
std::size_t segment_index)
{
auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0);
BOOST_ASSERT(turn_index < leg_geometry.locations.size() - 1);
// TODO chose a bigger look-a-head to smooth complex geometry
const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1];
const auto turn_coordinate = leg_geometry.locations[turn_index];
const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
const double pre_turn_heading =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
const double post_turn_heading =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
return StepManeuver{turn_coordinate, pre_turn_heading, post_turn_heading, instruction};
}
}
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,
const bool target_traversed_in_reverse)
{
const auto source_duration =
(source_traversed_in_reverse ? source_node.GetReverseWeightPlusOffset()
: source_node.GetForwardWeightPlusOffset()) /
10.;
const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
: source_node.forward_travel_mode;
const auto target_duration =
(target_traversed_in_reverse ? target_node.GetReverseWeightPlusOffset()
: target_node.GetForwardWeightPlusOffset()) /
10.;
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);
auto segment_index = 0;
if (leg_data.size() > 0)
{
StepManeuver maneuver = detail::stepManeuverFromGeometry(extractor::TurnInstruction::StartAtEndOfStreet,
leg_geometry, segment_index);
// 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
for (const auto &path_point : leg_data)
{
if (path_point.turn_instruction != extractor::TurnInstruction::NoTurn)
{
auto name = facade.get_name_for_id(path_point.name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{path_point.name_id, std::move(name),
path_point.duration_until_turn / 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++;
}
}
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{target_node.name_id, facade.get_name_for_id(target_node.name_id),
target_duration, distance, target_mode, maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
}
else
{
//
// |-----s source_duration
// |-------------t target_duration
// x---*---*---*---z compressed edge
// |-------| duration
steps.push_back(RouteStep{
source_node.name_id, facade.get_name_for_id(source_node.name_id),
target_duration - source_duration, leg_geometry.segment_distances[segment_index],
source_mode,
StepManeuver{source_node.location, 0., 0., extractor::TurnInstruction::StartAtEndOfStreet},
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
steps.push_back(RouteStep{
target_node.name_id, facade.get_name_for_id(target_node.name_id), 0., 0., target_mode,
StepManeuver{target_node.location, 0., 0., extractor::TurnInstruction::ReachedYourDestination},
leg_geometry.locations.size(), leg_geometry.locations.size()});
return steps;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
+54
View File
@@ -0,0 +1,54 @@
#ifndef ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
#define ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
#include "util/coordinate.hpp"
#include "util/integer_range.hpp"
#include <boost/assert.hpp>
#include <boost/range/iterator_range.hpp>
#include <vector>
#include <cstdlib>
namespace osrm
{
namespace engine
{
namespace guidance
{
// locations 0---1---2-...-n-1---n
// turns s x y t
// segment | 0 | 1 | 2 | senitel
// offsets 0 2 n-1 n
struct LegGeometry
{
std::vector<util::FixedPointCoordinate> locations;
// segment_offset[i] .. segment_offset[i+1] (inclusive)
// contains the geometry of segment i
std::vector<std::size_t> segment_offsets;
// length of the segment in meters
std::vector<double> segment_distances;
std::size_t FrontIndex(std::size_t segment_index) const
{
return segment_offsets[segment_index];
}
std::size_t BackIndex(std::size_t segment_index) const
{
return segment_offsets[segment_index + 1];
}
std::size_t GetNumberOfSegments() const
{
BOOST_ASSERT(segment_offsets.size() > 0);
return segment_offsets.size() - 1;
}
};
}
}
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#ifndef ROUTE_HPP
#define ROUTE_HPP
namespace osrm {
namespace engine {
namespace guidance {
struct Route
{
double duration;
double distance;
};
}
}
}
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef ROUTE_LEG_HPP
#define ROUTE_LEG_HPP
#include "engine/guidance/route_step.hpp"
#include <boost/optional.hpp>
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
struct RouteLeg
{
double duration;
double distance;
std::string summary;
std::vector<RouteStep> steps;
};
}
}
}
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef ROUTE_STEP_HPP
#define ROUTE_STEP_HPP
#include "extractor/travel_mode.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Given the following turn from a,b to b,c over b:
// a --> b --> c
// this struct saves the information of the segment b,c.
// Notable exceptions are Departure and Arrival steps.
// Departue: s --> a --> b. Represents the segment s,a with location being s.
// Arrive: a --> b --> t. The segment (b,t) is already covered by the previous segment.
struct RouteStep
{
unsigned name_id;
std::string way_name;
double duration;
double distance;
extractor::TravelMode mode;
StepManeuver maneuver;
// indices into the locations array stored the LegGeometry
std::size_t geometry_begin;
std::size_t geometry_end;
};
}
}
}
#endif
-347
View File
@@ -1,347 +0,0 @@
#ifndef ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
#define ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
#include "osrm/coordinate.hpp"
#include "engine/douglas_peucker.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "engine/segment_information.hpp"
#include "util/integer_range.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/for_each_pair.hpp"
#include "extractor/turn_instructions.hpp"
#include <boost/assert.hpp>
#include <cmath>
#include <cstdint>
#include <cstddef>
#include <limits>
#include <vector>
// transfers the internal edge based data structures to a more useable format
namespace osrm
{
namespace engine
{
namespace guidance
{
template <typename DataFacadeT> class SegmentList
{
public:
using DataFacade = DataFacadeT;
SegmentList(const InternalRouteResult &raw_route,
const bool extract_alternative,
const unsigned zoom_level,
const bool allow_simplification,
const DataFacade *facade);
const std::vector<std::uint32_t> &GetViaIndices() const;
std::uint32_t GetDistance() const;
std::uint32_t GetDuration() const;
const std::vector<SegmentInformation> &Get() const;
private:
void InitRoute(const PhantomNode &phantom_node, const bool traversed_in_reverse);
void AddLeg(const std::vector<PathData> &leg_data,
const PhantomNode &target_node,
const bool traversed_in_reverse,
const bool is_via_leg,
const DataFacade *facade);
void AppendSegment(const FixedPointCoordinate coordinate, const PathData &path_point);
void Finalize(const bool extract_alternative,
const InternalRouteResult &raw_route,
const unsigned zoom_level,
const bool allow_simplification);
// journey length in tenth of a second
std::uint32_t total_distance;
// journey distance in meter (TODO: verify)
std::uint32_t total_duration;
// segments that are required to keep
std::vector<std::uint32_t> via_indices;
// a list of node based segments
std::vector<SegmentInformation> segments;
};
template <typename DataFacadeT>
SegmentList<DataFacadeT>::SegmentList(const InternalRouteResult &raw_route,
const bool extract_alternative,
const unsigned zoom_level,
const bool allow_simplification,
const DataFacade *facade)
: total_distance(0), total_duration(0)
{
if (!raw_route.is_valid())
{
return;
}
if (extract_alternative)
{
BOOST_ASSERT(raw_route.has_alternative());
InitRoute(raw_route.segment_end_coordinates.front().source_phantom,
raw_route.alt_source_traversed_in_reverse.front());
AddLeg(raw_route.unpacked_alternative,
raw_route.segment_end_coordinates.back().target_phantom,
raw_route.alt_source_traversed_in_reverse.back(), false, facade);
}
else
{
InitRoute(raw_route.segment_end_coordinates.front().source_phantom,
raw_route.source_traversed_in_reverse.front());
for (std::size_t raw_index = 0; raw_index < raw_route.segment_end_coordinates.size();
++raw_index)
{
AddLeg(raw_route.unpacked_path_segments[raw_index],
raw_route.segment_end_coordinates[raw_index].target_phantom,
raw_route.target_traversed_in_reverse[raw_index],
raw_route.is_via_leg(raw_index), facade);
if (raw_route.is_via_leg(raw_index))
{
const auto &source_phantom =
raw_route.segment_end_coordinates[raw_index].target_phantom;
if (raw_route.target_traversed_in_reverse[raw_index] !=
raw_route.source_traversed_in_reverse[raw_index + 1])
{
bool traversed_in_reverse = raw_route.target_traversed_in_reverse[raw_index];
const extractor::TravelMode travel_mode =
(traversed_in_reverse ? source_phantom.backward_travel_mode
: source_phantom.forward_travel_mode);
const bool constexpr IS_NECESSARY = true;
const bool constexpr IS_VIA_LOCATION = true;
segments.emplace_back(source_phantom.location, source_phantom.name_id, 0, 0.f,
extractor::TurnInstruction::UTurn, IS_NECESSARY,
IS_VIA_LOCATION, travel_mode);
}
}
}
}
if (!allow_simplification)
{
// to prevent any simplifications, we mark all segments as necessary
for (auto &segment : segments)
{
segment.necessary = true;
}
}
Finalize(extract_alternative, raw_route, zoom_level, allow_simplification);
}
template <typename DataFacadeT>
void SegmentList<DataFacadeT>::InitRoute(const PhantomNode &node, const bool traversed_in_reverse)
{
const auto segment_duration =
(traversed_in_reverse ? node.reverse_weight : node.forward_weight);
const auto travel_mode =
(traversed_in_reverse ? node.backward_travel_mode : node.forward_travel_mode);
AppendSegment(node.location, PathData(0, node.name_id, extractor::TurnInstruction::HeadOn,
segment_duration, travel_mode));
}
template <typename DataFacadeT>
void SegmentList<DataFacadeT>::AddLeg(const std::vector<PathData> &leg_data,
const PhantomNode &target_node,
const bool traversed_in_reverse,
const bool is_via_leg,
const DataFacade *facade)
{
for (const auto &path_data : leg_data)
{
AppendSegment(facade->GetCoordinateOfNode(path_data.node), path_data);
}
const EdgeWeight segment_duration =
(traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight);
const extractor::TravelMode travel_mode =
(traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode);
const bool constexpr IS_NECESSARY = true;
const bool constexpr IS_VIA_LOCATION = true;
segments.emplace_back(target_node.location, target_node.name_id, segment_duration, 0.f,
is_via_leg ? extractor::TurnInstruction::ReachViaLocation
: extractor::TurnInstruction::NoTurn,
IS_NECESSARY, IS_VIA_LOCATION, travel_mode);
}
template <typename DataFacadeT> std::uint32_t SegmentList<DataFacadeT>::GetDistance() const
{
return total_distance;
}
template <typename DataFacadeT> std::uint32_t SegmentList<DataFacadeT>::GetDuration() const
{
return total_duration;
}
template <typename DataFacadeT>
std::vector<std::uint32_t> const &SegmentList<DataFacadeT>::GetViaIndices() const
{
return via_indices;
}
template <typename DataFacadeT>
std::vector<SegmentInformation> const &SegmentList<DataFacadeT>::Get() const
{
return segments;
}
template <typename DataFacadeT>
void SegmentList<DataFacadeT>::AppendSegment(const FixedPointCoordinate coordinate,
const PathData &path_point)
{
const auto turn = path_point.turn_instruction;
segments.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f, turn,
path_point.travel_mode);
}
template <typename DataFacadeT>
void SegmentList<DataFacadeT>::Finalize(const bool extract_alternative,
const InternalRouteResult &raw_route,
const unsigned zoom_level,
const bool allow_simplification)
{
if (segments.empty())
return;
// check if first two segments can be merged
BOOST_ASSERT(segments.size() >= 2);
if (segments[0].location == segments[1].location &&
segments[1].turn_instruction == extractor::TurnInstruction::NoTurn)
{
segments[0].travel_mode = segments[1].travel_mode;
segments[0].name_id = segments[1].name_id;
// Other data??
segments.erase(segments.begin() + 1);
}
// announce mode changes
for (std::size_t i = 0; i + 1 < segments.size(); ++i)
{
auto &segment = segments[i];
const auto next_mode = segments[i + 1].travel_mode;
if (segment.travel_mode != next_mode &&
segment.turn_instruction == extractor::TurnInstruction::NoTurn)
{
segment.turn_instruction = extractor::TurnInstruction::GoStraight;
segment.necessary = true;
}
}
segments[0].length = 0.f;
for (const auto i : util::irange<std::size_t>(1, segments.size()))
{
// move down names by one, q&d hack
segments[i - 1].name_id = segments[i].name_id;
segments[i].length = util::coordinate_calculation::greatCircleDistance(
segments[i - 1].location, segments[i].location);
}
float segment_length = 0.;
EdgeWeight segment_duration = 0;
std::size_t segment_start_index = 0;
double path_length = 0;
for (const auto i : util::irange<std::size_t>(1, segments.size()))
{
path_length += segments[i].length;
segment_length += segments[i].length;
segment_duration += segments[i].duration;
segments[segment_start_index].length = segment_length;
segments[segment_start_index].duration = segment_duration;
if (extractor::TurnInstruction::NoTurn != segments[i].turn_instruction)
{
BOOST_ASSERT(segments[i].necessary);
segment_length = 0;
segment_duration = 0;
segment_start_index = i;
if (segments[i].turn_instruction == extractor::TurnInstruction::NameChanges)
{
segments[i].turn_instruction =
extractor::TurnInstruction::GoStraight; // to not break the api
}
}
}
total_distance = static_cast<std::uint32_t>(std::round(path_length));
total_duration = static_cast<std::uint32_t>(std::round(
(extract_alternative ? raw_route.alternative_path_length : raw_route.shortest_path_length) /
10.));
// Post-processing to remove empty or nearly empty path segments
if (segments.size() > 2 && std::numeric_limits<float>::epsilon() > segments.back().length &&
!(segments.end() - 2)->is_via_location)
{
segments.pop_back();
segments.back().necessary = true;
segments.back().turn_instruction = extractor::TurnInstruction::NoTurn;
}
if (segments.size() > 2 && std::numeric_limits<float>::epsilon() > segments.front().length &&
!(segments.begin() + 1)->is_via_location)
{
segments.erase(segments.begin());
segments.front().turn_instruction = extractor::TurnInstruction::HeadOn;
segments.front().necessary = true;
}
if (allow_simplification)
{
douglasPeucker(segments, zoom_level);
}
std::uint32_t necessary_segments = 0; // a running index that counts the necessary pieces
via_indices.push_back(0);
const auto markNecessarySegments = [this, &necessary_segments](SegmentInformation &first,
const SegmentInformation &second)
{
if (!first.necessary)
return;
// mark the end of a leg (of several segments)
if (first.is_via_location)
via_indices.push_back(necessary_segments);
const double post_turn_bearing =
util::coordinate_calculation::bearing(first.location, second.location);
const double pre_turn_bearing =
util::coordinate_calculation::bearing(second.location, first.location);
first.post_turn_bearing = static_cast<short>(post_turn_bearing * 10);
first.pre_turn_bearing = static_cast<short>(pre_turn_bearing * 10);
++necessary_segments;
};
// calculate which segments are necessary and update segments for bearings
util::for_each_pair(segments, markNecessarySegments);
via_indices.push_back(necessary_segments);
BOOST_ASSERT(via_indices.size() >= 2);
}
template <typename DataFacadeT>
SegmentList<DataFacadeT> MakeSegmentList(const InternalRouteResult &raw_route,
const bool extract_alternative,
const unsigned zoom_level,
const bool allow_simplification,
const DataFacadeT *facade)
{
return SegmentList<DataFacadeT>(raw_route, extract_alternative, zoom_level,
allow_simplification, facade);
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
+26
View File
@@ -0,0 +1,26 @@
#ifndef ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
namespace osrm
{
namespace engine
{
namespace guidance
{
struct StepManeuver
{
util::FixedPointCoordinate location;
double heading_before;
double heading_after;
extractor::TurnInstruction instruction;
};
}
}
}
#endif
@@ -1,147 +0,0 @@
#ifndef ENGINE_GUIDANCE_TEXTUAL_ROUTE_ANNOTATIONS_HPP_
#define ENGINE_GUIDANCE_TEXTUAL_ROUTE_ANNOTATIONS_HPP_
#include "engine/segment_information.hpp"
#include "engine/guidance/segment_list.hpp"
#include "extractor/turn_instructions.hpp"
#include "osrm/json_container.hpp"
#include "util/bearing.hpp"
#include "util/cast.hpp"
#include <cstdint>
#include <limits>
#include <string>
#include <utility>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
template <typename DataFacadeT>
inline util::json::Array AnnotateRoute(const std::vector<SegmentInformation> &route_segments,
DataFacadeT *facade)
{
util::json::Array json_instruction_array;
if (route_segments.empty())
return json_instruction_array;
// Segment information has following format:
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
std::int32_t necessary_segments_running_index = 0;
struct RoundAbout
{
std::int32_t start_index;
std::uint32_t name_id;
std::int32_t leave_at_exit;
} round_about;
round_about = {std::numeric_limits<std::int32_t>::max(), 0, 0};
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
extractor::TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT;
// Generate annotations for every segment
for (std::size_t i = 0; i < route_segments.size(); ++i)
{
const auto &segment = route_segments[i];
util::json::Array json_instruction_row;
extractor::TurnInstruction current_instruction = segment.turn_instruction;
if (extractor::isTurnNecessary(current_instruction))
{
if (extractor::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 (extractor::TurnInstruction::LeaveRoundAbout == current_instruction)
{
temp_instruction = std::to_string(util::cast::enum_to_underlying(
extractor::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(util::cast::enum_to_underlying(current_instruction));
current_turn_instruction += temp_instruction;
}
json_instruction_row.values.emplace_back(std::move(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<std::uint32_t>(segment.length)) + "m");
// post turn bearing
const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
json_instruction_row.values.push_back(util::bearing::get(post_turn_bearing_value));
json_instruction_row.values.push_back(
static_cast<std::uint32_t>(std::round(post_turn_bearing_value)));
if (i + 1 < route_segments.size())
{
// anounce next travel mode with turn
json_instruction_row.values.push_back(route_segments[i + 1].travel_mode);
last_travel_mode = segment.travel_mode;
}
else
{
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(util::bearing::get(pre_turn_bearing_value));
json_instruction_row.values.push_back(
static_cast<std::uint32_t>(std::round(pre_turn_bearing_value)));
json_instruction_array.values.push_back(json_instruction_row);
}
}
else if (extractor::TurnInstruction::StayOnRoundAbout == current_instruction)
{
++round_about.leave_at_exit;
}
if (segment.necessary)
{
++necessary_segments_running_index;
}
}
util::json::Array json_last_instruction_row;
temp_instruction = std::to_string(
util::cast::enum_to_underlying(extractor::TurnInstruction::ReachedYourDestination));
json_last_instruction_row.values.emplace_back(std::move(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(util::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(util::bearing::get(0.0));
json_last_instruction_row.values.push_back(0.);
json_instruction_array.values.emplace_back(std::move(json_last_instruction_row));
return json_instruction_array;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif