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;
}
+18 -3
View File
@@ -14,6 +14,7 @@
#include "util/lua_util.hpp"
#include "util/make_unique.hpp"
#include "util/name_table.hpp"
#include "util/range_table.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
@@ -624,10 +625,24 @@ void Extractor::WriteIntersectionClassificationData(
util::writeFingerprint(file_out_stream);
util::serializeVector(file_out_stream, node_based_intersection_classes);
static_assert(std::is_trivially_copyable<util::guidance::BearingClass>::value,
"BearingClass Serialization requires trivial copyable bearing classes");
// create range table for vectors:
std::vector<unsigned> bearing_counts;
bearing_counts.reserve(bearing_classes.size());
std::uint64_t total_bearings = 0;
for (const auto &bearing_class : bearing_classes){
bearing_counts.push_back(static_cast<unsigned>(bearing_class.getAvailableBearings().size()));
total_bearings += bearing_class.getAvailableBearings().size();
}
util::serializeVector(file_out_stream, bearing_classes);
util::RangeTable<> bearing_class_range_table(bearing_counts);
file_out_stream << bearing_class_range_table;
file_out_stream << total_bearings;
for( const auto &bearing_class : bearing_classes)
{
const auto &bearings = bearing_class.getAvailableBearings();
file_out_stream.write( reinterpret_cast<const char*>(&bearings[0]), sizeof(bearings[0]) * bearings.size() );
}
static_assert(std::is_trivially_copyable<util::guidance::EntryClass>::value,
"EntryClass Serialization requires trivial copyable entry classes");
+45 -262
View File
@@ -15,234 +15,17 @@ namespace guidance
struct TurnPossibility
{
TurnPossibility(bool entry_allowed, double bearing, std::uint8_t discrete_id)
: entry_allowed(entry_allowed), bearing(std::move(bearing)),
discrete_id(std::move(discrete_id))
TurnPossibility(bool entry_allowed, double bearing)
: entry_allowed(entry_allowed), bearing(std::move(bearing))
{
}
TurnPossibility() : entry_allowed(false), bearing(0), discrete_id(0) {}
TurnPossibility() : entry_allowed(false), bearing(0) {}
bool entry_allowed;
double bearing;
std::uint8_t discrete_id;
};
namespace
{
bool hasConflicts(const std::vector<TurnPossibility> &turns)
{
if (turns.size() <= 1)
return false;
for (std::size_t pos = 0; pos < turns.size(); ++pos)
{
if (turns[pos].discrete_id == turns[(pos + 1) % turns.size()].discrete_id)
return true;
}
return false;
}
// Fix cases with nearly identical turns. If the difference between turns is just to small to be
// visible, we will not report the angle twice
std::vector<TurnPossibility> fixIdenticalTurns(std::vector<TurnPossibility> intersection)
{
BOOST_ASSERT(intersection.size() > 1);
for (auto itr = intersection.begin(); itr != intersection.end(); ++itr)
{
const auto next = [&]() {
auto next_itr = std::next(itr);
if (next_itr != intersection.end())
return next_itr;
return intersection.begin();
}();
// conflict here?
if (itr->discrete_id == next->discrete_id)
{
if (angularDeviation(itr->bearing, next->bearing) < 0.5) // very small angular difference
{
if (!itr->entry_allowed || next->entry_allowed)
{
itr = intersection.erase(itr);
}
else
{
intersection.erase(next);
}
if (itr == intersection.end())
break;
}
}
}
return intersection;
}
std::vector<TurnPossibility> fixAroundBorder(std::vector<TurnPossibility> intersection)
{
BOOST_ASSERT(intersection.size() > 1);
// We can solve a conflict by reporting different bearing availabilities, as long as
// both conflicting turns are on different sides of the bearing separator.
//
// Consider this example:
// ID(0)
// . b
// a .... (ID 1)
// . c
// ID(2)
//
// Both b and c map to the ID 1. Due to the split, we can set ID 0 and 2. In
// deducing the best available bearing for a turn, we can now find 0 to be closest
// to b and 2 to be closest to c. This only works when there are no other bearings
// close to the conflicting assignment, though.
for (std::size_t current_index = 0; current_index < intersection.size(); ++current_index)
{
const auto next_index = (current_index + 1) % intersection.size();
if (intersection[current_index].discrete_id == intersection[next_index].discrete_id)
{
const double border = util::guidance::BearingClass::discreteIDToAngle(
util::guidance::BearingClass::angleToDiscreteID(
intersection[current_index].bearing));
// if both are on different sides of the separation, we can check for possible
// resolution
if (intersection[current_index].bearing < border &&
intersection[next_index].bearing > border)
{
const auto shift_angle = [](const double bearing, const double delta) {
auto shifted_angle = bearing + delta;
if (shifted_angle < 0)
return shifted_angle + 360.;
if (shifted_angle > 360)
return shifted_angle - 360.;
return shifted_angle;
};
// conflict resolution is possible, if both bearings are available
const auto left_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(intersection[current_index].bearing,
-util::guidance::BearingClass::discrete_angle_step_size));
const auto right_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(intersection[next_index].bearing,
util::guidance::BearingClass::discrete_angle_step_size));
const bool resolvable = [&]() {
if (intersection.size() == 2)
return true;
// cannot shift to the left without generating another conflict
if (intersection[current_index + intersection.size() - 1].discrete_id ==
left_id)
return false;
// cannot shift to the right without generating another conflict
if (intersection[(next_index + 1) % intersection.size()].discrete_id ==
right_id)
return false;
return true;
}();
if (resolvable)
{
intersection[current_index].discrete_id = left_id;
intersection[next_index].discrete_id = right_id;
}
}
}
}
return intersection;
}
// return an empty set of turns, if the conflict is not possible to be handled
std::vector<TurnPossibility> handleConflicts(std::vector<TurnPossibility> intersection)
{
intersection = fixIdenticalTurns(std::move(intersection));
if (!hasConflicts(intersection))
return intersection;
intersection = fixAroundBorder(intersection);
// if the intersection still has conflicts, we cannot handle it correctly
if (hasConflicts(intersection))
intersection.clear();
return intersection;
#if 0
const auto border = util::guidance::BearingClass::discreteIDToAngle(
util::guidance::BearingClass::angleToDiscreteID(intersection[0].bearing));
// at least two turns
auto previous_id = util::guidance::BearingClass::angleToDiscreteID(turns.back().bearing);
for (std::size_t i = 0; i < turns.size(); ++i)
{
if (turns[i].entry_allowed)
entry_class.activate(turn_index);
const auto discrete_id =
util::guidance::BearingClass::angleToDiscreteID(turns[i].bearing);
const auto prev_index = (i + turns.size() - 1) % turns.size();
if (discrete_id != previous_id)
{
// if we go back in IDs, conflict resolution has to deal with multiple conflicts
if (previous_id > discrete_id &&
previous_id != (util::guidance::BearingClass::angleToDiscreteID(
turns[prev_index].bearing)))
{
std::cout << "Previous ID conflict " << (int)previous_id << " "
<< (int)discrete_id << std::endl;
break;
}
++turn_index;
bearing_class.addDiscreteID(discrete_id);
previous_id = discrete_id;
}
else
{
// the previous turn was handled into a conflict. Such a conflict cannot be
// correctly expressed.
// We have to report a unclassified setting.
if (util::guidance::BearingClass::angleToDiscreteID(turns[prev_index].bearing) !=
previous_id)
break;
if (turns[i].bearing >= border && turns[prev_index].bearing < border)
{
const auto shift_angle = [](const double bearing, const double delta) {
auto shifted_angle = bearing + delta;
if (shifted_angle < 0)
return shifted_angle + 360.;
if (shifted_angle > 360)
return shifted_angle - 360.;
return shifted_angle;
};
// conflict resolution is possible, if both bearings are available
const auto left_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(turns[prev_index].bearing,
-util::guidance::BearingClass::discrete_angle_step_size));
const auto right_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(turns[i].bearing,
util::guidance::BearingClass::discrete_angle_step_size));
if (!bearing_class.hasDiscrete(left_id) && !bearing_class.hasDiscrete(right_id))
{
bearing_class.resetDiscreteID(discrete_id);
bearing_class.addDiscreteID(left_id);
bearing_class.addDiscreteID(right_id);
++turn_index;
previous_id = right_id;
}
}
}
}
#endif
return intersection;
};
} // namespace
std::pair<util::guidance::EntryClass, util::guidance::BearingClass>
classifyIntersection(NodeID nid,
const Intersection &intersection,
@@ -266,63 +49,63 @@ classifyIntersection(NodeID nid,
const double bearing =
util::coordinate_calculation::bearing(node_coordinate, edge_coordinate);
turns.push_back({road.entry_allowed, bearing,
util::guidance::BearingClass::angleToDiscreteID(bearing)});
turns.push_back({road.entry_allowed, bearing});
}
std::sort(turns.begin(), turns.end(),
[](const TurnPossibility left, const TurnPossibility right) {
return left.bearing < right.bearing;
return util::guidance::BearingClass::getDiscreteBearing(left.bearing) <
util::guidance::BearingClass::getDiscreteBearing(right.bearing) ||
(util::guidance::BearingClass::getDiscreteBearing(left.bearing) ==
util::guidance::BearingClass::getDiscreteBearing(right.bearing) &&
left.bearing < right.bearing);
});
// check for conflicts
const bool has_conflicts = hasConflicts(turns);
if (has_conflicts)
{ // try to handle conflicts, if possible
turns = handleConflicts(std::move(turns));
}
util::guidance::EntryClass entry_class;
util::guidance::BearingClass bearing_class;
const bool canBeDiscretized = [&]() {
if (turns.size() <= 1)
return true;
DiscreteBearing last_discrete_bearing =
util::guidance::BearingClass::getDiscreteBearing(std::round(turns.back().bearing));
for (const auto turn : turns)
{
const DiscreteBearing discrete_bearing =
util::guidance::BearingClass::getDiscreteBearing(std::round(turn.bearing));
if (discrete_bearing == last_discrete_bearing)
return false;
last_discrete_bearing = discrete_bearing;
}
return true;
}();
// finally transfer data to the entry/bearing classes
std::size_t number = 0;
for (const auto turn : turns)
if (canBeDiscretized)
{
if (turn.entry_allowed)
entry_class.activate(number);
bearing_class.addDiscreteID(turn.discrete_id);
++number;
}
static std::size_t mapping_failure_count = 0;
if (turns.empty())
{
++mapping_failure_count;
util::SimpleLogger().Write(logDEBUG)
<< "Failed to provide full turn list for intersection ( " << mapping_failure_count
<< " ) for " << intersection.size() << " roads";
std::cout << std::endl;
for (const auto &road : intersection)
for (const auto turn : turns)
{
const auto eid = road.turn.eid;
const auto edge_coordinate =
getRepresentativeCoordinate(nid, node_based_graph.GetTarget(eid), eid, false,
compressed_geometries, query_nodes);
const double bearing =
util::coordinate_calculation::bearing(node_coordinate, edge_coordinate);
std::cout << " " << bearing << "("
<< (int)util::guidance::BearingClass::angleToDiscreteID(bearing) << ")";
if (turn.entry_allowed)
entry_class.activate(number);
auto discrete_bearing_class =
util::guidance::BearingClass::getDiscreteBearing(std::round(turn.bearing));
bearing_class.add(std::round(discrete_bearing_class *
util::guidance::BearingClass::discrete_step_size));
++number;
}
}
else
{
for (const auto turn : turns)
{
if (turn.entry_allowed)
entry_class.activate(number);
bearing_class.add(std::round(turn.bearing));
++number;
}
std::cout << std::endl;
std::cout << "Location of intersection: " << std::setprecision(12) << " "
<< util::toFloating(query_nodes[nid].lat) << " "
<< util::toFloating(query_nodes[nid].lon) << std::endl;
return {};
}
return std::make_pair(entry_class, bearing_class);
}
+58 -18
View File
@@ -31,6 +31,7 @@
#include <cstdint>
#include <fstream>
#include <iostream>
#include <iterator>
#include <new>
#include <string>
@@ -574,36 +575,75 @@ int Storage::Run()
{
boost::filesystem::ifstream intersection_stream(config.intersection_class_path,
std::ios::binary);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Could not open " + config.intersection_class_path.string() +
" for reading.");
if (!util::readAndCheckFingerprint(intersection_stream))
{
util::SimpleLogger().Write(logWARNING)
<< "Fingerprint does not match or reading failed";
}
throw util::exception("Fingerprint of " + config.intersection_class_path.string() +
" does not match or could not read from file");
std::vector<BearingClassID> bearing_class_id_table;
util::deserializeVector(intersection_stream, bearing_class_id_table);
if (!util::deserializeVector(intersection_stream, bearing_class_id_table))
throw util::exception("Failed to read from " + config.names_data_path.string());
shared_layout_ptr->SetBlockSize<BearingClassID>(SharedDataLayout::BEARING_CLASSID,
bearing_class_id_table.size());
auto bearing_id_ptr = shared_layout_ptr->GetBlockPtr<BearingClassID, true>(
shared_memory_ptr, SharedDataLayout::BEARING_CLASSID);
std::copy(bearing_class_id_table.begin(), bearing_class_id_table.end(), bearing_id_ptr);
auto bearing_class_ptr =
shared_layout_ptr->GetBlockPtr<util::guidance::BearingClass, true>(
shared_memory_ptr, SharedDataLayout::BEARING_CLASS);
std::vector<util::guidance::BearingClass> bearing_class_table;
util::deserializeVector(intersection_stream, bearing_class_table);
shared_layout_ptr->SetBlockSize<util::guidance::BearingClass>(
SharedDataLayout::BEARING_CLASS, bearing_class_table.size());
unsigned bearing_blocks = 0;
intersection_stream.read((char *)&bearing_blocks, sizeof(unsigned));
unsigned sum_lengths = 0;
intersection_stream.read((char *)&sum_lengths, sizeof(unsigned));
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::BEARING_OFFSETS,
bearing_blocks);
shared_layout_ptr->SetBlockSize<typename util::RangeTable<16, true>::BlockT>(
SharedDataLayout::BEARING_BLOCKS, bearing_blocks);
unsigned *bearing_offsets_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
shared_memory_ptr, SharedDataLayout::BEARING_OFFSETS);
if (shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_OFFSETS) > 0)
{
intersection_stream.read(
reinterpret_cast<char *>(bearing_offsets_ptr),
shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_OFFSETS));
}
unsigned *bearing_blocks_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
shared_memory_ptr, SharedDataLayout::BEARING_BLOCKS);
if (shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_BLOCKS) > 0)
{
intersection_stream.read(
reinterpret_cast<char *>(bearing_blocks_ptr),
shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_BLOCKS));
}
std::uint64_t num_bearings;
intersection_stream >> num_bearings;
std::vector<DiscreteBearing> bearing_class_table(num_bearings);
intersection_stream.read(reinterpret_cast<char *>(&bearing_class_table[0]),
sizeof(bearing_class_table[0]) * num_bearings);
shared_layout_ptr->SetBlockSize<DiscreteBearing>(SharedDataLayout::BEARING_VALUES,
num_bearings);
auto bearing_class_ptr = shared_layout_ptr->GetBlockPtr<DiscreteBearing, true>(
shared_memory_ptr, SharedDataLayout::BEARING_VALUES);
std::copy(bearing_class_table.begin(), bearing_class_table.end(), bearing_class_ptr);
auto entry_class_ptr =
shared_layout_ptr->GetBlockPtr<util::guidance::EntryClass, true>(
shared_memory_ptr, SharedDataLayout::ENTRY_CLASS);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Failed to read from " + config.names_data_path.string());
std::vector<util::guidance::EntryClass> entry_class_table;
util::deserializeVector(intersection_stream, entry_class_table);
shared_layout_ptr->SetBlockSize<util::guidance::EntryClass>(
SharedDataLayout::ENTRY_CLASS, entry_class_table.size());
if(!util::deserializeVector(intersection_stream, entry_class_table))
throw util::exception("Failed to read from " + config.names_data_path.string());
shared_layout_ptr->SetBlockSize<util::guidance::EntryClass>(SharedDataLayout::ENTRY_CLASS,
entry_class_table.size());
auto entry_class_ptr = shared_layout_ptr->GetBlockPtr<util::guidance::EntryClass, true>(
shared_memory_ptr, SharedDataLayout::ENTRY_CLASS);
std::copy(entry_class_table.begin(), entry_class_table.end(), entry_class_ptr);
}
+56 -68
View File
@@ -1,6 +1,8 @@
#include "extractor/guidance/discrete_angle.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/toolkit.hpp"
#include <algorithm>
#include <boost/assert.hpp>
namespace osrm
@@ -10,83 +12,69 @@ namespace util
namespace guidance
{
static_assert(
360 / BearingClass::discrete_angle_step_size <= 8 * sizeof(BearingClass::FlagBaseType),
"The number of expressable bearings does not fit into the datatype used for storage.");
std::uint8_t BearingClass::angleToDiscreteID(double angle)
{
BOOST_ASSERT(angle >= 0. && angle <= 360.);
// shift angle by half the step size to have the class be located around the center
angle = (angle + 0.5 * BearingClass::discrete_angle_step_size);
if (angle > 360)
angle -= 360;
return std::uint8_t(angle / BearingClass::discrete_angle_step_size);
}
double BearingClass::discreteIDToAngle(std::uint8_t id)
{
BOOST_ASSERT(0 <= id && id <= 360. / discrete_angle_step_size);
return discrete_angle_step_size * id;
}
void BearingClass::resetContinuous(const double bearing) {
const auto id = angleToDiscreteID(bearing);
resetDiscreteID(id);
}
void BearingClass::resetDiscreteID(const std::uint8_t id) {
available_bearings_mask &= ~(1<<id);
}
bool BearingClass::hasContinuous(const double bearing) const
{
const auto id = angleToDiscreteID(bearing);
return hasDiscrete(id);
}
bool BearingClass::hasDiscrete(const std::uint8_t id) const
{
return 0 != (available_bearings_mask & (1<<id));
}
BearingClass::BearingClass() : available_bearings_mask(0) {}
bool BearingClass::operator==(const BearingClass &other) const
{
return other.available_bearings_mask == available_bearings_mask;
BOOST_ASSERT(std::is_sorted(available_bearings.begin(), available_bearings.end()));
BOOST_ASSERT(std::is_sorted(other.available_bearings.begin(), other.available_bearings.end()));
if (other.available_bearings.size() != available_bearings.size())
return false;
for (std::size_t i = 0; i < available_bearings.size(); ++i)
if (available_bearings[i] != other.available_bearings[i])
return false;
return true;
}
bool BearingClass::operator<(const BearingClass &other) const
{
return available_bearings_mask < other.available_bearings_mask;
}
BOOST_ASSERT(std::is_sorted(available_bearings.begin(), available_bearings.end()));
BOOST_ASSERT(std::is_sorted(other.available_bearings.begin(), other.available_bearings.end()));
if (available_bearings.size() < other.available_bearings.size())
return true;
if (available_bearings.size() > other.available_bearings.size())
return false;
bool BearingClass::addContinuous(const double angle)
{
return addDiscreteID(angleToDiscreteID(angle));
}
bool BearingClass::addDiscreteID(const std::uint8_t discrete_id)
{
const auto mask = (1 << discrete_id);
const auto is_new = (0 == (available_bearings_mask & mask));
available_bearings_mask |= mask;
return is_new;
}
std::vector<double> BearingClass::getAvailableBearings() const
{
std::vector<double> result;
// account for some basic inaccuracries of double
for (std::size_t discrete_id = 0; discrete_id * discrete_angle_step_size <= 361; ++discrete_id)
for (std::size_t i = 0; i < available_bearings.size(); ++i)
{
// ervery set bit indicates a bearing
if (available_bearings_mask & (1 << discrete_id))
result.push_back(discrete_id * discrete_angle_step_size);
if (available_bearings[i] < other.available_bearings[i])
return true;
if (available_bearings[i] > other.available_bearings[i])
return false;
}
return result;
return false;
}
void BearingClass::add(const DiscreteBearing bearing)
{
available_bearings.push_back(bearing);
}
const std::vector<DiscreteBearing> &BearingClass::getAvailableBearings() const
{
return available_bearings;
}
DiscreteBearing BearingClass::getDiscreteBearing(const double bearing)
{
BOOST_ASSERT(0. <= bearing && bearing <= 360.);
auto shifted_bearing = (bearing + 0.5 * discrete_step_size);
if (shifted_bearing > 360.)
shifted_bearing -= 360;
return static_cast<DiscreteBearing>(shifted_bearing / discrete_step_size);
}
std::size_t BearingClass::findMatchingBearing(const double bearing) const
{
// the small size of the intersections allows a linear compare
auto discrete_bearing = static_cast<DiscreteBearing>(bearing);
auto max_element =
std::max_element(available_bearings.begin(), available_bearings.end(),
[&](const DiscreteBearing first, const DiscreteBearing second) {
return angularDeviation(first, discrete_bearing) >
angularDeviation(second, discrete_bearing);
});
return std::distance(available_bearings.begin(), max_element);
}
} // namespace guidance