Add viaroute suport for new API
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef ROUTE_HPP
|
||||
#define ROUTE_HPP
|
||||
|
||||
namespace osrm {
|
||||
namespace engine {
|
||||
namespace guidance {
|
||||
|
||||
struct Route
|
||||
{
|
||||
double duration;
|
||||
double distance;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user