intersection classes with variable degree of discretization

This commit is contained in:
Moritz Kobitzsch
2016-05-10 08:37:45 +02:00
committed by Patrick Niklaus
parent 0f3942558f
commit 4d9aa65e78
23 changed files with 724 additions and 702 deletions
+69 -66
View File
@@ -37,31 +37,12 @@ const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "s
// translations of TurnTypes. Not all types are exposed to the outside world.
// invalid types should never be returned as part of the API
const constexpr char *turn_type_names[] = {"invalid",
"new name",
"continue",
"turn",
"merge",
"on ramp",
"off ramp",
"fork",
"end of road",
"notification",
"roundabout",
"roundabout",
"rotary",
"rotary",
"roundabout turn",
"roundabout turn",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid"};
const constexpr char *turn_type_names[] = {
"invalid", "new name", "continue", "turn", "merge",
"on ramp", "off ramp", "fork", "end of road", "notification",
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
"roundabout turn", "invalid", "invalid", "invalid", "invalid",
"invalid", "invalid", "invalid", "invalid", "invalid"};
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
@@ -97,47 +78,80 @@ util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
return array;
}
util::json::Object getConnection(const bool entry_allowed, const double bearing)
util::json::Object
getIntersection(const guidance::Intersection &intersection, bool locate_before, bool locate_after)
{
util::json::Object result;
result.values["entry_allowed"] = entry_allowed ? "true" : "false";
result.values["bearing"] = bearing;
util::json::Array bearings;
util::json::Array entry;
const auto &available_bearings = intersection.bearing_class.getAvailableBearings();
for (std::size_t i = 0; i < available_bearings.size(); ++i)
{
bearings.values.push_back(std::to_string(available_bearings[i]));
entry.values.push_back(intersection.entry_class.allowsEntry(i) ? "true" : "false");
}
result.values["location"] = detail::coordinateToLonLat(intersection.location);
bool requires_correction = false;
if (locate_before || (!available_bearings.empty() && available_bearings.front()==0))
{
// bearings are oriented in the direction of driving. For the in-bearing, we actually need
// to
// find the bearing from the view of the intersection. This means we have to rotate the
// bearing
// by 180 degree.
const auto rotated_bearing_before = (intersection.bearing_before >= 180.0)
? (intersection.bearing_before - 180.0)
: (intersection.bearing_before + 180.0);
result.values["bearing_before"] =
intersection.bearing_class.findMatchingBearing(rotated_bearing_before);
}
else
{
result.values["bearing_before"] = available_bearings.size();
requires_correction = true;
}
if (locate_after || (!available_bearings.empty() && available_bearings.front()==0))
{
result.values["bearing_after"] =
intersection.bearing_class.findMatchingBearing(intersection.bearing_after);
}
else
{
result.values["bearing_after"] = available_bearings.size();
requires_correction = true;
}
if (requires_correction)
{
bearings.values.push_back("0");
entry.values.push_back("false");
}
result.values["bearings"] = bearings;
result.values["entry"] = entry;
return result;
}
util::json::Array getConnections(const util::guidance::EntryClass entry_class,
const util::guidance::BearingClass bearing_class)
util::json::Array getIntersection(const guidance::RouteStep &step)
{
util::json::Array result;
const auto bearings = bearing_class.getAvailableBearings();
for (size_t connection = 0; connection < bearings.size(); ++connection)
bool first = true;
for (const auto &intersection : step.intersections)
{
result.values.push_back(
getConnection(entry_class.allowsEntry(connection), bearings[connection]));
// on waypoints, the first/second bearing is invalid. In these cases, we cannot locate the
// bearing as part of the available bearings at the intersection.
result.values.push_back(getIntersection(
intersection, !first || step.maneuver.waypoint_type != guidance::WaypointType::Depart,
!first || step.maneuver.waypoint_type != guidance::WaypointType::Arrive));
first = false;
}
return result;
}
util::json::Object getIntersection(const guidance::StepManeuver maneuver)
{
util::json::Object result;
// bearings are oriented in the direction of driving. For the in-bearing, we actually need to
// find the bearing from the view of the intersection. This means we have to rotate the bearing
// by 180 degree.
const auto rotated_bearing_before = (maneuver.bearing_before >= 180.0)
? (maneuver.bearing_before - 180.0)
: (maneuver.bearing_before + 180.0);
result.values["from_bearing"] =
getMatchingDiscreteBearing(false, rotated_bearing_before, maneuver.entry_class,
maneuver.bearing_class.getAvailableBearings());
result.values["to_bearing"] =
getMatchingDiscreteBearing(true, maneuver.bearing_after, maneuver.entry_class,
maneuver.bearing_class.getAvailableBearings());
result.values["connections"] = getConnections(maneuver.entry_class, maneuver.bearing_class);
return result;
}
// FIXME this actually needs to be configurable from the profiles
std::string modeToString(const extractor::TravelMode mode)
{
@@ -193,10 +207,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
{
util::json::Object step_maneuver;
if (maneuver.waypoint_type == guidance::WaypointType::None)
{
step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type);
step_maneuver.values["intersection"] = detail::getIntersection(maneuver);
}
else
step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type);
@@ -204,18 +215,9 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
step_maneuver.values["modifier"] =
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
if (maneuver.exit != 0)
step_maneuver.values["exit"] = maneuver.exit;
// TODO currently we need this to comply with the api.
// We should move this to an additional entry, the moment we
// actually compute the correct locations of the intersections
if (!maneuver.intersections.empty() && maneuver.exit == 0)
step_maneuver.values["exit"] = maneuver.intersections.size();
return step_maneuver;
}
@@ -231,6 +233,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
route_step.values["mode"] = detail::modeToString(std::move(step.mode));
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
route_step.values["geometry"] = std::move(geometry);
route_step.values["intersections"] = detail::getIntersection(step);
return route_step;
}
+56 -47
View File
@@ -2,6 +2,7 @@
#include <boost/assert.hpp>
#include <cmath>
#include <cstddef>
namespace osrm
@@ -12,48 +13,11 @@ namespace guidance
{
namespace detail
{
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const WaypointType waypoint_type,
const LegGeometry &leg_geometry)
namespace
{
BOOST_ASSERT(waypoint_type != WaypointType::None);
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
double pre_turn_bearing = 0, post_turn_bearing = 0;
Coordinate turn_coordinate;
if (waypoint_type == WaypointType::Depart)
{
turn_coordinate = leg_geometry.locations.front();
const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
post_turn_bearing =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
}
else
{
BOOST_ASSERT(waypoint_type == WaypointType::Arrive);
turn_coordinate = leg_geometry.locations.back();
const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
pre_turn_bearing =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
}
return StepManeuver{std::move(turn_coordinate),
pre_turn_bearing,
post_turn_bearing,
std::move(instruction),
waypoint_type,
INVALID_EXIT_NR,
// BearingClass,EntryClass, and Intermediate intersections are unknown yet
{},
{},
{}};
}
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const LegGeometry &leg_geometry,
const std::size_t segment_index,
util::guidance::EntryClass entry_class,
util::guidance::BearingClass bearing_class)
void fillInIntermediate(Intersection &intersection,
const LegGeometry &leg_geometry,
const std::size_t segment_index)
{
auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0);
@@ -64,15 +28,60 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr
const auto turn_coordinate = leg_geometry.locations[turn_index];
const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
const double pre_turn_bearing =
intersection.bearing_before =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
const double post_turn_bearing =
intersection.bearing_after =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
// add a step without intermediate intersections
return StepManeuver{std::move(turn_coordinate), pre_turn_bearing, post_turn_bearing,
std::move(instruction), WaypointType::None, INVALID_EXIT_NR,
std::move(entry_class), std::move(bearing_class), {}};
intersection.location = turn_coordinate;
}
void fillInDepart(Intersection &intersection, const LegGeometry &leg_geometry)
{
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
const auto turn_coordinate = leg_geometry.locations.front();
const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
intersection.location = turn_coordinate;
intersection.bearing_before = 0;
intersection.bearing_after =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
std::cout << "Depart: " << intersection.bearing_before << " " << intersection.bearing_after << std::endl;
}
void fillInArrive(Intersection &intersection, const LegGeometry &leg_geometry)
{
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
const auto turn_coordinate = leg_geometry.locations.back();
const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
intersection.location = turn_coordinate;
intersection.bearing_before =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
intersection.bearing_after = 0;
std::cout << "Arrive: " << intersection.bearing_before << " " << intersection.bearing_after << std::endl;
}
} // namespace
Intersection intersectionFromGeometry(const WaypointType waypoint_type,
const double segment_duration,
const LegGeometry &leg_geometry,
const std::size_t segment_index)
{
Intersection intersection;
intersection.duration = segment_duration;
intersection.distance = leg_geometry.segment_distances[segment_index];
switch (waypoint_type)
{
case WaypointType::None:
fillInIntermediate(intersection, leg_geometry, segment_index);
break;
case WaypointType::Depart:
fillInDepart(intersection, leg_geometry);
break;
case WaypointType::Arrive:
fillInArrive(intersection, leg_geometry);
break;
}
return intersection;
}
} // ns detail
} // ns engine
+54 -42
View File
@@ -50,14 +50,16 @@ void print(const std::vector<RouteStep> &steps)
<< " Duration: " << step.duration << " Distance: " << step.distance
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
<< " exit: " << step.maneuver.exit
<< " Intersections: " << step.maneuver.intersections.size() << " [";
<< " Intersections: " << step.intersections.size() << " [";
for (const auto &intersection : step.maneuver.intersections)
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
for (const auto &intersection : step.intersections)
{
std::cout << "(" << intersection.duration << " " << intersection.distance << " "
<< " Bearings: " << intersection.bearing_before << " "
<< intersection.bearing_after << ")";
}
std::cout << "] name[" << step.name_id << "]: " << step.name
<< " Bearings: " << step.maneuver.bearing_before << " "
<< step.maneuver.bearing_after << std::endl;
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
}
}
@@ -67,8 +69,21 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
// Overwrites turn instruction and increases exit NR
destination.duration += source.duration;
destination.distance += source.distance;
if (destination.geometry_begin < source.geometry_begin)
{
destination.intersections.insert(destination.intersections.end(),
source.intersections.begin(), source.intersections.end());
}
else
{
destination.intersections.insert(destination.intersections.begin(),
source.intersections.begin(), source.intersections.end());
}
destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin);
destination.geometry_end = std::max(destination.geometry_end, source.geometry_end);
return destination;
}
@@ -185,7 +200,8 @@ void closeOffRoundabout(const bool on_roundabout,
// Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
// index back to the entering location and prepare the current silent set of instructions for
// removal.
const auto exit_bearing = steps[step_index].maneuver.bearing_after;
std::vector<std::size_t> intermediate_steps;
const auto exit_bearing = steps[step_index].intersections.back().bearing_after;
if (step_index > 1)
{
// The very first route-step is head, so we cannot iterate past that one
@@ -198,6 +214,7 @@ void closeOffRoundabout(const bool on_roundabout,
{
propagation_step.maneuver.exit = step.maneuver.exit;
propagation_step.geometry_end = step.geometry_end;
// remember rotary name
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
@@ -237,7 +254,7 @@ void closeOffRoundabout(const bool on_roundabout,
const auto angle = 540 - rotated_exit;
return angle > 360 ? angle - 360 : angle;
}(propagation_step.maneuver.bearing_before, exit_bearing);
}(propagation_step.intersections.back().bearing_before, exit_bearing);
propagation_step.maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle);
@@ -274,9 +291,8 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
// if we elongate in the back, we only need to copy the intersections to the beginning.
// the bearings remain the same, as the location of the turn doesn't change
step.maneuver.intersections.insert(step.maneuver.intersections.end(),
by_step.maneuver.intersections.begin(),
by_step.maneuver.intersections.end());
step.intersections.insert(step.intersections.end(), by_step.intersections.begin(),
by_step.intersections.end());
}
else
{
@@ -286,14 +302,10 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
step.geometry_begin = by_step.geometry_begin;
// elongating in the front changes the location of the maneuver
step.maneuver.location = by_step.maneuver.location;
step.maneuver.bearing_before = by_step.maneuver.bearing_before;
step.maneuver.bearing_after = by_step.maneuver.bearing_after;
step.maneuver.instruction = by_step.maneuver.instruction;
step.maneuver = by_step.maneuver;
step.maneuver.intersections.insert(step.maneuver.intersections.begin(),
by_step.maneuver.intersections.begin(),
by_step.maneuver.intersections.end());
step.intersections.insert(step.intersections.begin(), by_step.intersections.begin(),
by_step.intersections.end());
}
return step;
}
@@ -359,8 +371,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
}
}
// Potential U-Turn
else if (bearingsAreReversed(one_back_step.maneuver.bearing_before,
current_step.maneuver.bearing_after))
else if (bearingsAreReversed(one_back_step.intersections.front().bearing_before,
current_step.intersections.front().bearing_after))
{
BOOST_ASSERT(two_back_index < steps.size());
@@ -438,18 +450,6 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
bool on_roundabout = false;
bool has_entered_roundabout = false;
// adds an intersection to the initial route step
// It includes the length of the last step, until the intersection
// Also updates the length of the respective segment
auto addIntersection = [](RouteStep into, const RouteStep &last_step,
const RouteStep &intersection) {
into.maneuver.intersections.push_back(
{last_step.duration, last_step.distance, intersection.maneuver.location,
intersection.maneuver.entry_class, intersection.maneuver.bearing_class});
return forwardInto(std::move(into), intersection);
};
// count the exits forward. if enter/exit roundabout happen both, no further treatment is
// required. We might end up with only one of them (e.g. starting within a roundabout)
// or having a via-point in the roundabout.
@@ -492,8 +492,9 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
{
// count intersections. We cannot use exit, since intersections can follow directly
// after a roundabout
steps[last_valid_instruction] = addIntersection(
std::move(steps[last_valid_instruction]), steps[step_index - 1], step);
steps[last_valid_instruction].intersections.insert(
steps[last_valid_instruction].intersections.end(), step.intersections.begin(),
step.intersections.end());
step.maneuver.instruction = TurnInstruction::NO_TURN();
}
else if (!isSilent(instruction))
@@ -664,8 +665,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// update initial turn direction/bearings. Due to the duplicated first coordinate,
// the initial bearing is invalid
designated_depart.maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
designated_depart.maneuver = {TurnInstruction::NO_TURN(), WaypointType::Depart, 0};
// finally remove the initial (now duplicated move)
steps.erase(steps.begin());
@@ -678,8 +678,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
geometry.segment_offsets.begin(),
[](const std::size_t val) { return val - 1; });
steps.front().maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
steps.front().maneuver = {TurnInstruction::NO_TURN(), WaypointType::Depart, 0};
std::cout << "Removed coordinate: " << std::endl;
}
// and update the leg geometry indices for the removed entry
@@ -705,8 +705,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
BOOST_ASSERT(geometry.segment_distances.back() < 1);
geometry.segment_distances.pop_back();
next_to_last_step.maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Arrive, geometry);
next_to_last_step.maneuver = {TurnInstruction::NO_TURN(), WaypointType::Arrive, 0};
next_to_last_step.intersections.front().bearing_after = 0;
steps.pop_back();
// Because we eliminated a really short segment, it was probably
@@ -736,8 +736,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
next_to_last_step.geometry_end--;
steps.back().geometry_begin--;
steps.back().geometry_end--;
steps.back().maneuver = detail::stepManeuverFromGeometry(TurnInstruction::NO_TURN(),
WaypointType::Arrive, geometry);
steps.back().maneuver = {TurnInstruction::NO_TURN(), WaypointType::Arrive, 0};
}
}
@@ -762,6 +761,11 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
: extractor::guidance::DirectionModifier::UTurn;
steps.front().maneuver.instruction.direction_modifier = initial_modifier;
steps.front().intersections.front().bearing_before = 0;
steps.front().intersections.front().bearing_after =
util::coordinate_calculation::bearing(leg_geometry.locations[0], leg_geometry.locations[1]);
steps.front().intersections.front() = util::guidance::setIntersectionClasses(
std::move(steps.front().intersections.front()), source_node);
const auto distance_from_end = util::coordinate_calculation::haversineDistance(
target_node.input_location, leg_geometry.locations.back());
@@ -775,6 +779,14 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
: extractor::guidance::DirectionModifier::UTurn;
steps.back().maneuver.instruction.direction_modifier = final_modifier;
BOOST_ASSERT(steps.back().intersections.size() == 1);
steps.back().intersections.front().bearing_before = util::coordinate_calculation::bearing(
leg_geometry.locations[leg_geometry.locations.size() - 2],
leg_geometry.locations[leg_geometry.locations.size() - 1]);
steps.back().intersections.front().bearing_after = 0;
steps.back().intersections.front() = util::guidance::setIntersectionClasses(
std::move(steps.back().intersections.front()), target_node);
return steps;
}