[routing] Add turn instructions

This commit is contained in:
Denis Koronchik 2014-10-29 17:25:11 +03:00 committed by Alex Zolotarev
parent ecb30436ae
commit abe72ce0f1
6 changed files with 174 additions and 5 deletions

View file

@ -70,6 +70,30 @@ IsStreetChecker const & IsStreetChecker::Instance()
return inst;
}
IsOneWayChecker::IsOneWayChecker()
{
Classificator const & c = classif();
m_types.push_back(c.GetTypeByPath({ "hwtag", "oneway" }));
}
IsOneWayChecker const & IsOneWayChecker::Instance()
{
static const IsOneWayChecker inst;
return inst;
}
IsRoundAboutChecker::IsRoundAboutChecker()
{
Classificator const & c = classif();
m_types.push_back(c.GetTypeByPath({ "junction", "roundabout" }));
}
IsRoundAboutChecker const & IsRoundAboutChecker::Instance()
{
static const IsRoundAboutChecker inst;
return inst;
}
IsBuildingChecker::IsBuildingChecker()
{
Classificator const & c = classif();

View file

@ -34,6 +34,22 @@ public:
static IsStreetChecker const & Instance();
};
class IsOneWayChecker : public BaseChecker
{
public:
IsOneWayChecker();
static IsOneWayChecker const & Instance();
};
class IsRoundAboutChecker : public BaseChecker
{
public:
IsRoundAboutChecker();
static IsRoundAboutChecker const & Instance();
};
class IsBuildingChecker : public BaseChecker
{
public:

View file

@ -1,14 +1,18 @@
#include "osrm_router.hpp"
#include "route.hpp"
#include "vehicle_model.hpp"
#include "../base/math.hpp"
#include "../geometry/angles.hpp"
#include "../geometry/distance.hpp"
#include "../geometry/distance_on_sphere.hpp"
#include "../indexer/ftypes_matcher.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/index.hpp"
#include "../indexer/scales.hpp"
#include "../indexer/mwm_version.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../platform/platform.hpp"
@ -537,6 +541,8 @@ OsrmRouter::ResultCode OsrmRouter::CalculateRouteImpl(m2::PointD const & startPt
ASSERT(segBegin.IsValid(), ());
ASSERT(segEnd.IsValid(), ());
Route::TurnsT turns;
vector<m2::PointD> points;
for (auto i : osrm::irange<std::size_t>(0, rawRoute.unpacked_path_segments.size()))
{
@ -544,6 +550,10 @@ OsrmRouter::ResultCode OsrmRouter::CalculateRouteImpl(m2::PointD const & startPt
return Cancelled;
// Get all the coordinates for the computed route
m2::PointD p1, p;
feature::TypesHolder fTypePrev;
string namePrev;
size_t const n = rawRoute.unpacked_path_segments[i].size();
for (size_t j = 0; j < n; ++j)
{
@ -591,6 +601,34 @@ OsrmRouter::ResultCode OsrmRouter::CalculateRouteImpl(m2::PointD const & startPt
if (j == n - 1 && k == endK - 1)
endIdx = (seg.m_pointEnd > seg.m_pointStart) ? segEnd.m_pointEnd : segEnd.m_pointStart;
if (j > 0 && k == startK)
{
ASSERT_LESS(MercatorBounds::DistanceOnEarth(p, ft.GetPoint(startIdx)), 2, ());
m2::PointD const p2 = ft.GetPoint((seg.m_pointEnd > seg.m_pointStart) ? startIdx + 1 : startIdx - 1);
string name;
ft.GetName(FeatureType::DEFAULT_LANG, name);
string n1, n2;
search::GetStreetNameAsKey(namePrev, n1);
search::GetStreetNameAsKey(name, n2);
Route::TurnInstruction const t = GetTurnInstruction(fTypePrev, ft, p1, p, p2, (!n1.empty() && (n1 == n2)));
if (t != Route::NoTurn)
turns.push_back(Route::TurnItemT(points.size(), t));
}
if (k == endK - 1)
{
fTypePrev = feature::TypesHolder(ft);
ft.GetName(FeatureType::DEFAULT_LANG, namePrev);
p1 = ft.GetPoint((seg.m_pointEnd > seg.m_pointStart) ? (endIdx - 1) : (endIdx + 1));
p = ft.GetPoint(endIdx);
}
if (seg.m_pointEnd > seg.m_pointStart)
{
for (auto idx = startIdx; idx <= endIdx; ++idx)
@ -612,11 +650,62 @@ OsrmRouter::ResultCode OsrmRouter::CalculateRouteImpl(m2::PointD const & startPt
if (points.size() < 2)
return RouteNotFound;
// osrm multiple seconds to 10, so we need to divide it back
estimateTime /= 10;
route.SetGeometry(points.begin(), points.end());
route.SetTurnInstructions(turns);
return NoError;
}
Route::TurnInstruction OsrmRouter::GetTurnInstruction(feature::TypesHolder const & ft1, feature::TypesHolder const & ft2,
m2::PointD const & p1, m2::PointD const & p, m2::PointD const & p2,
bool isStreetEqual) const
{
bool const isRound1 = ftypes::IsRoundAboutChecker::Instance()(ft1);
bool const isRound2 = ftypes::IsRoundAboutChecker::Instance()(ft2);
if (isRound1 && isRound2)
return Route::StayOnRoundAbout;
if (!isRound1 && isRound2)
return Route::EnterRoundAbout;
if (isRound1 && !isRound2)
return Route::LeaveRoundAbout;
if (isStreetEqual)
return Route::NoTurn;
double a = my::RadToDeg(ang::AngleTo(p, p2) - ang::AngleTo(p, p1));
while (a < 0)
a += 360;
if (a >= 23 && a < 67)
return Route::TurnSharpRight;
if (a >= 67 && a < 113)
return Route::TurnRight;
if (a >= 113 && a < 158)
return Route::TurnSlightRight;
if (a >= 158 && a < 202)
return Route::GoStraight;
if (a >= 202 && a < 248)
return Route::TurnSlightLeft;
if (a >= 248 && a < 292)
return Route::TurnLeft;
if (a >= 292 && a < 336)
return Route::TurnSharpLeft;
return Route::UTurn;
}
IRouter::ResultCode OsrmRouter::FindPhantomNodes(string const & fName, m2::PointD const & startPt, m2::PointD const & finalPt,
FeatureGraphNodeVecT & res, size_t maxCount, uint32_t & mwmId)
{

View file

@ -1,5 +1,6 @@
#pragma once
#include "route.hpp"
#include "router.hpp"
#include "osrm2feature_map.hpp"
#include "osrm_data_facade.hpp"
@ -11,6 +12,7 @@
#include "../3party/osrm/osrm-backend/DataStructures/QueryEdge.h"
namespace feature { class TypesHolder; }
class Index;
struct PhantomNode;
@ -49,6 +51,10 @@ protected:
void CalculateRouteAsync(ReadyCallback const & callback);
ResultCode CalculateRouteImpl(m2::PointD const & startPt, m2::PointD const & finalPt, Route & route);
Route::TurnInstruction GetTurnInstruction(feature::TypesHolder const & ft1, feature::TypesHolder const & ft2,
m2::PointD const & p1, m2::PointD const & p, m2::PointD const & p2,
bool isStreetEqual) const;
private:
Index const * m_pIndex;

View file

@ -34,6 +34,12 @@ void Route::Swap(Route & rhs)
m_segProj.swap(rhs.m_segProj);
swap(m_current, rhs.m_current);
swap(m_currentTime, rhs.m_currentTime);
swap(m_turns, rhs.m_turns);
}
void Route::SetTurnInstructions(TurnsT & v)
{
swap(m_turns, v);
}
double Route::GetDistance() const
@ -123,12 +129,10 @@ Route::IterT Route::FindProjection(m2::RectD const & posRect, double predictDist
double Route::GetDistanceOnPolyline(IterT const & it1, IterT const & it2) const
{
size_t const n = m_poly.GetSize();
ASSERT(it1.IsValid() && it2.IsValid(), ());
ASSERT_LESS_OR_EQUAL(it1.m_ind, it2.m_ind, ());
ASSERT_LESS(it1.m_ind, n, ());
ASSERT_LESS(it2.m_ind, n, ());
ASSERT_LESS(it1.m_ind, m_poly.GetSize(), ());
ASSERT_LESS(it2.m_ind, m_poly.GetSize(), ());
if (it1.m_ind == it2.m_ind)
return MercatorBounds::DistanceOnEarth(it1.m_pt, it2.m_pt);

View file

@ -14,6 +14,32 @@ namespace routing
class Route
{
public:
enum TurnInstruction
{
NoTurn = 0,
GoStraight,
TurnRight,
TurnSharpRight,
TurnSlightRight,
TurnLeft,
TurnSharpLeft,
TurnSlightLeft,
UTurn,
HeadOn,
EnterRoundAbout,
LeaveRoundAbout,
StayOnRoundAbout,
StartAtEndOfStreet,
ReachedYourDestination,
EnterAgainstAllowedDirection,
LeaveAgainstAllowedDirection
};
// first value of piar is an number of point in polyline (number of segment + 1)
typedef pair<uint32_t, TurnInstruction> TurnItemT;
typedef vector<TurnItemT> TurnsT;
explicit Route(string const & router) : m_router(router) {}
template <class IterT>
@ -33,6 +59,8 @@ public:
Update();
}
void SetTurnInstructions(TurnsT & v);
string const & GetRouterId() const { return m_router; }
m2::PolylineD const & GetPoly() const { return m_poly; }
string const & GetName() const { return m_name; }
@ -88,6 +116,8 @@ private:
/// Precalculated info for fast projection finding.
vector<m2::ProjectionToSection<m2::PointD>> m_segProj;
TurnsT m_turns;
/// Cached result iterator for last MoveIterator query.
mutable IterT m_current;
mutable double m_currentTime;