forked from organicmaps/organicmaps
[routing] Add turn instructions
This commit is contained in:
parent
ecb30436ae
commit
abe72ce0f1
6 changed files with 174 additions and 5 deletions
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue