Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/jni/com/mapswithme/maps/Framework.cpp42
-rw-r--r--android/src/com/mapswithme/maps/LocationState.java32
-rw-r--r--map/routing_session.cpp13
-rw-r--r--platform/location.hpp16
-rw-r--r--routing/route.cpp1
-rw-r--r--routing/route.hpp2
-rw-r--r--routing/routing_tests/turns_generator_test.cpp136
-rw-r--r--routing/turns.cpp85
-rw-r--r--routing/turns.hpp18
-rw-r--r--routing/turns_generator.cpp69
-rw-r--r--routing/turns_generator.hpp6
11 files changed, 323 insertions, 97 deletions
diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp
index 4d0cc6e8c6..b6d9442ad1 100644
--- a/android/jni/com/mapswithme/maps/Framework.cpp
+++ b/android/jni/com/mapswithme/maps/Framework.cpp
@@ -1315,39 +1315,45 @@ extern "C"
jclass const klass = env->FindClass("com/mapswithme/maps/LocationState$RoutingInfo");
ASSERT(klass, (jni::DescribeException()));
- static jmethodID const methodID =
- env->GetMethodID(klass, "<init>",
- "(Ljava/lang/String;Ljava/lang/String;"
- "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II[[B)V");
- ASSERT(methodID, (jni::DescribeException()));
+ static jmethodID const ctorRouteInfoID = env->GetMethodID(klass, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;"
+ "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II"
+ "[Lcom/mapswithme/maps/LocationState$SingleLaneInfo;)V");
+ ASSERT(ctorRouteInfoID, (jni::DescribeException()));
- vector<vector<int8_t>> const & lanes = info.m_lanes;
+ vector<location::FollowingInfo::SingleLaneInfoOuter> const & lanes = info.m_lanes;
jobjectArray jLanes = nullptr;
if (!lanes.empty())
{
- // A new java two-dimensional array for lane information is allocated here.
- // Then it will be saved in com.mapswithme.maps.LocationState, and then removed by java
- // GC.
- jclass const myClassArray = env->FindClass("[B");
+ // A new java array of SingleLaneInfo classes for lane information is allocated here.
+ // Then it will be saved in com.mapswithme.maps.LocationState, and then removed by java GC.
+ jclass const myClassArray = env->FindClass("com/mapswithme/maps/LocationState$SingleLaneInfo");
ASSERT(myClassArray, (jni::DescribeException()));
size_t const lanesSize = lanes.size();
jLanes = env->NewObjectArray(lanesSize, myClassArray, nullptr);
ASSERT(jLanes, (jni::DescribeException()));
- jbyteArray jOneLane = nullptr;
+ static jmethodID const ctorSingleLaneInfoID = env->GetMethodID(myClassArray, "<init>", "([BZ)V");
+ ASSERT(ctorSingleLaneInfoID, (jni::DescribeException()));
+
+ jbyteArray singleLane = nullptr;
+ jobject singleLaneInfo = nullptr;
for (size_t j = 0; j < lanesSize; ++j)
{
- size_t const laneSize = lanes[j].size();
- jOneLane = env->NewByteArray(laneSize);
- ASSERT(jOneLane, (jni::DescribeException()));
- env->SetByteArrayRegion(jOneLane, 0, laneSize, lanes[j].data());
- env->SetObjectArrayElement(jLanes, j, jOneLane);
- env->DeleteLocalRef(jOneLane);
+ size_t const laneSize = lanes[j].m_lane.size();
+ singleLane = env->NewByteArray(laneSize);
+ ASSERT(singleLane, (jni::DescribeException()));
+ env->SetByteArrayRegion(singleLane, 0, laneSize, lanes[j].m_lane.data());
+ singleLaneInfo = env->NewObject(myClassArray, ctorSingleLaneInfoID, singleLane, lanes[j].m_isActive);
+ ASSERT(singleLaneInfo, (jni::DescribeException()));
+ env->SetObjectArrayElement(jLanes, j, singleLaneInfo);
+ env->DeleteLocalRef(singleLaneInfo);
+ env->DeleteLocalRef(singleLane);
}
}
jobject const result = env->NewObject(
- klass, methodID, jni::ToJavaString(env, info.m_distToTarget),
+ klass, ctorRouteInfoID, jni::ToJavaString(env, info.m_distToTarget),
jni::ToJavaString(env, info.m_targetUnitsSuffix),
jni::ToJavaString(env, info.m_distToTurn),
jni::ToJavaString(env, info.m_turnUnitsSuffix), jni::ToJavaString(env, info.m_targetName),
diff --git a/android/src/com/mapswithme/maps/LocationState.java b/android/src/com/mapswithme/maps/LocationState.java
index 7c2a3048ed..196155861c 100644
--- a/android/src/com/mapswithme/maps/LocationState.java
+++ b/android/src/com/mapswithme/maps/LocationState.java
@@ -26,6 +26,28 @@ public enum LocationState
public native void invalidatePosition();
+ public static class SingleLaneInfo
+ {
+ byte[] mLane;
+ boolean mIsActive;
+
+ SingleLaneInfo(byte[] lane, boolean isActive)
+ {
+ mLane = lane;
+ mIsActive = isActive;
+ }
+
+ private String DumpString()
+ {
+ final int startCapacity = 32;
+ StringBuilder sb = new StringBuilder(startCapacity);
+ sb.append("Is lane active? ").append(mIsActive).append(":");
+ for (byte i : mLane)
+ sb.append(" ").append(i);
+ return sb.toString();
+ }
+ }
+
public static class RoutingInfo
{
public String mDistToTarget;
@@ -99,21 +121,19 @@ public enum LocationState
SHARP_RIGHT
};
- private void DumpLanes(byte[][] lanes)
+ private void DumpLanes(SingleLaneInfo[] lanes)
{
for (int j = 0; j < lanes.length; j++)
{
final int startCapacity = 32;
StringBuilder sb = new StringBuilder(startCapacity);
- sb.append("Lane number ").append(j).append(":");
- for (int i : lanes[j])
- sb.append(" ").append(i);
+ sb.append("Lane number ").append(j).append(":").append(lanes[j].DumpString());
Log.d("JNIARRAY", " " + sb.toString());
}
}
- public RoutingInfo(String distToTarget, String units, String distTurn, String turnSuffix, String targetName, int direction, int totalTime
- , byte[][] lanes)
+ public RoutingInfo(String distToTarget, String units, String distTurn, String turnSuffix,
+ String targetName, int direction, int totalTime, SingleLaneInfo[] lanes)
{
// lanes is not equal to null if any lane information is available and should be displayed.
// If so, lanes contains values of Lane enum for every lane.
diff --git a/map/routing_session.cpp b/map/routing_session.cpp
index 70208949b7..7167e392ca 100644
--- a/map/routing_session.cpp
+++ b/map/routing_session.cpp
@@ -173,19 +173,12 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const
if (dist < kShowLanesDistInMeters)
{
- // There are two nested for-loops below. Outer one is for lanes and inner one (transform) is
- // for each lane's directions.
- // The meaning of the code below is info.m_lanes = turn.m_lanes; (vector<vector<int>> =
- // vector<vector<LaneWay>>).
- // The size of turn.m_lanes is relatively small. Less than 10 in most cases.
+ // There are two nested loops below. Outer one is for lanes and inner one (ctor of SingleLaneInfo) is
+ // for each lane's directions. The size of turn.m_lanes is relatively small. Less than 10 in most cases.
info.m_lanes.clear();
for (size_t j = 0; j < turn.m_lanes.size(); ++j)
{
- vector<int8_t> lane;
- lane.reserve(turn.m_lanes[j].size());
- transform(turn.m_lanes[j].begin(), turn.m_lanes[j].end(), back_inserter(lane),
- [](routing::turns::LaneWay l) { return static_cast<int8_t>(l); });
- info.m_lanes.push_back(move(lane));
+ info.m_lanes.push_back(move(FollowingInfo::SingleLaneInfoOuter(turn.m_lanes[j])));
}
}
else
diff --git a/platform/location.hpp b/platform/location.hpp
index a93aada073..2bb9921230 100644
--- a/platform/location.hpp
+++ b/platform/location.hpp
@@ -93,6 +93,19 @@ namespace location
class FollowingInfo
{
public:
+ struct SingleLaneInfoOuter
+ {
+ vector<int8_t> m_lane;
+ bool m_isActive;
+ SingleLaneInfoOuter(routing::turns::SingleLaneInfo singleLaneInfo) : m_isActive(singleLaneInfo.m_isActive)
+ {
+ routing::turns::TSingleLane const & lane = singleLaneInfo.m_lane;
+ m_lane.resize(lane.size());
+ transform(lane.begin(), lane.end(), m_lane.begin(),
+ [] (routing::turns::LaneWay l) { return static_cast<int8_t>(l); });
+ }
+ };
+
/// @name Formatted covered distance with measurement units suffix.
//@{
string m_distToTarget;
@@ -108,8 +121,7 @@ namespace location
//@}
int m_time;
// m_lanes contains lane information on the edge before the turn.
- // Template parameter int is used for passing the information to Android and iOS.
- vector<vector<int8_t>> m_lanes;
+ vector<SingleLaneInfoOuter> m_lanes;
// The next street name
string m_targetName;
diff --git a/routing/route.cpp b/routing/route.cpp
index 3caca68dfe..6d01607aeb 100644
--- a/routing/route.cpp
+++ b/routing/route.cpp
@@ -26,6 +26,7 @@ string DebugPrint(TurnItem const & turnItem)
stringstream out;
out << "[ TurnItem: m_index = " << turnItem.m_index
<< ", m_turn = " << DebugPrint(turnItem.m_turn)
+ << ", m_lanes = " << ::DebugPrint(turnItem.m_lanes)
<< ", m_exitNum = " << turnItem.m_exitNum
<< ", m_sourceName = " << turnItem.m_sourceName
<< ", m_targetName = " << turnItem.m_targetName
diff --git a/routing/route.hpp b/routing/route.hpp
index 502305526e..358925da40 100644
--- a/routing/route.hpp
+++ b/routing/route.hpp
@@ -40,7 +40,7 @@ struct TurnItem
uint32_t m_index; // Index of point on polyline (number of segment + 1).
turns::TurnDirection m_turn;
- vector<turns::TSingleLane> m_lanes; // Lane information on the edge before the turn.
+ vector<turns::SingleLaneInfo> m_lanes; // Lane information on the edge before the turn.
uint32_t m_exitNum; // Number of exit on roundabout.
string m_sourceName;
string m_targetName;
diff --git a/routing/routing_tests/turns_generator_test.cpp b/routing/routing_tests/turns_generator_test.cpp
index 978c4f0a5d..7b7f888cd3 100644
--- a/routing/routing_tests/turns_generator_test.cpp
+++ b/routing/routing_tests/turns_generator_test.cpp
@@ -37,7 +37,7 @@ UNIT_TEST(TestParseSingleLane)
{
TSingleLane result;
TEST(ParseSingleLane("through;right", ';', result), ());
- vector<LaneWay> expected1 = {LaneWay::Through, LaneWay::Right};
+ TSingleLane expected1 = {LaneWay::Through, LaneWay::Right};
TEST_EQUAL(result, expected1, ());
TEST(!ParseSingleLane("through;Right", ';', result), ());
@@ -55,7 +55,7 @@ UNIT_TEST(TestParseSingleLane)
TEST_EQUAL(result.size(), 0, ());
TEST(ParseSingleLane("left;through", ';', result), ());
- vector<LaneWay> expected2 = {LaneWay::Left, LaneWay::Through};
+ TSingleLane expected2 = {LaneWay::Left, LaneWay::Through};
TEST_EQUAL(result, expected2, ());
TEST(ParseSingleLane("left", ';', result), ());
@@ -65,59 +65,59 @@ UNIT_TEST(TestParseSingleLane)
UNIT_TEST(TestParseLanes)
{
- vector<TSingleLane> result;
+ vector<SingleLaneInfo> result;
TEST(ParseLanes("through|through|through|through;right", result), ());
TEST_EQUAL(result.size(), 4, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[3].size(), 2, ());
- TEST_EQUAL(result[0][0], LaneWay::Through, ());
- TEST_EQUAL(result[3][0], LaneWay::Through, ());
- TEST_EQUAL(result[3][1], LaneWay::Right, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[3].m_lane.size(), 2, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[3].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[3].m_lane[1], LaneWay::Right, ());
TEST(ParseLanes("left|left;through|through|through", result), ());
TEST_EQUAL(result.size(), 4, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[1].size(), 2, ());
- TEST_EQUAL(result[3].size(), 1, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[1][0], LaneWay::Left, ());
- TEST_EQUAL(result[1][1], LaneWay::Through, ());
- TEST_EQUAL(result[3][0], LaneWay::Through, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[1].m_lane.size(), 2, ());
+ TEST_EQUAL(result[3].m_lane.size(), 1, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[1].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[1].m_lane[1], LaneWay::Through, ());
+ TEST_EQUAL(result[3].m_lane[0], LaneWay::Through, ());
TEST(ParseLanes("left|through|through", result), ());
TEST_EQUAL(result.size(), 3, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[1].size(), 1, ());
- TEST_EQUAL(result[2].size(), 1, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[1][0], LaneWay::Through, ());
- TEST_EQUAL(result[2][0], LaneWay::Through, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[1].m_lane.size(), 1, ());
+ TEST_EQUAL(result[2].m_lane.size(), 1, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[1].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[2].m_lane[0], LaneWay::Through, ());
TEST(ParseLanes("left|le ft| through|through | right", result), ());
TEST_EQUAL(result.size(), 5, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[4].size(), 1, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[1][0], LaneWay::Left, ());
- TEST_EQUAL(result[2][0], LaneWay::Through, ());
- TEST_EQUAL(result[3][0], LaneWay::Through, ());
- TEST_EQUAL(result[4][0], LaneWay::Right, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[4].m_lane.size(), 1, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[1].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[2].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[3].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[4].m_lane[0], LaneWay::Right, ());
TEST(ParseLanes("left|Left|through|througH|right", result), ());
TEST_EQUAL(result.size(), 5, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[4].size(), 1, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[4][0], LaneWay::Right, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[4].m_lane.size(), 1, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[4].m_lane[0], LaneWay::Right, ());
TEST(ParseLanes("left|Left|through|througH|through;right;sharp_rIght", result), ());
TEST_EQUAL(result.size(), 5, ());
- TEST_EQUAL(result[0].size(), 1, ());
- TEST_EQUAL(result[4].size(), 3, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[4][0], LaneWay::Through, ());
- TEST_EQUAL(result[4][1], LaneWay::Right, ());
- TEST_EQUAL(result[4][2], LaneWay::SharpRight, ());
+ TEST_EQUAL(result[0].m_lane.size(), 1, ());
+ TEST_EQUAL(result[4].m_lane.size(), 3, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[4].m_lane[0], LaneWay::Through, ());
+ TEST_EQUAL(result[4].m_lane[1], LaneWay::Right, ());
+ TEST_EQUAL(result[4].m_lane[2], LaneWay::SharpRight, ());
TEST(!ParseLanes("left|Leftt|through|througH|right", result), ());
TEST_EQUAL(result.size(), 0, ());
@@ -130,8 +130,8 @@ UNIT_TEST(TestParseLanes)
TEST(ParseLanes("left |Left|through|througH|right", result), ());
TEST_EQUAL(result.size(), 5, ());
- TEST_EQUAL(result[0][0], LaneWay::Left, ());
- TEST_EQUAL(result[1][0], LaneWay::Left, ());
+ TEST_EQUAL(result[0].m_lane[0], LaneWay::Left, ());
+ TEST_EQUAL(result[1].m_lane[0], LaneWay::Left, ());
}
UNIT_TEST(TestFixupTurns)
@@ -270,4 +270,60 @@ UNIT_TEST(TestCalculateTurnGeometry)
turnsGeom3[0].m_points[3]) - kSquareSideMeters),
kErrorMeters, ());
}
+
+UNIT_TEST(TestIsLaneWayConformedTurnDirection)
+{
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::Left, TurnDirection::TurnLeft), ());
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::Right, TurnDirection::TurnRight), ());
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::SlightLeft, TurnDirection::TurnSlightLeft), ());
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::SharpRight, TurnDirection::TurnSharpRight), ());
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::Reverse, TurnDirection::UTurn), ());
+ TEST(IsLaneWayConformedTurnDirection(LaneWay::Through, TurnDirection::GoStraight), ());
+
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::Left, TurnDirection::TurnSlightLeft), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::Right, TurnDirection::TurnSharpRight), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::SlightLeft, TurnDirection::GoStraight), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::SharpRight, TurnDirection::NoTurn), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::Reverse, TurnDirection::TurnLeft), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::None, TurnDirection::ReachedYourDestination), ());
+}
+
+UNIT_TEST(TestIsLaneWayConformedTurnDirectionApproximately)
+{
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Left, TurnDirection::TurnSharpLeft), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Left, TurnDirection::TurnSlightLeft), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Right, TurnDirection::TurnSharpRight), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Right, TurnDirection::TurnRight), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Reverse, TurnDirection::UTurn), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightLeft, TurnDirection::GoStraight), ());
+ TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightRight, TurnDirection::GoStraight), ());
+
+ TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpLeft, TurnDirection::UTurn), ());
+ TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpRight, TurnDirection::UTurn), ());
+ TEST(!IsLaneWayConformedTurnDirection(LaneWay::Through, TurnDirection::ReachedYourDestination), ());
+ TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::Through, TurnDirection::TurnRight), ());
+ TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightRight, TurnDirection::TurnSharpLeft), ());
+}
+
+UNIT_TEST(TestAddingActiveLaneInformation)
+{
+ Route::TurnsT turns = {{0, TurnDirection::GoStraight},
+ {1, TurnDirection::TurnLeft},
+ {2, TurnDirection::ReachedYourDestination}};
+ turns[0].m_lanes.push_back({LaneWay::Left, LaneWay::Through});
+ turns[0].m_lanes.push_back({LaneWay::Right});
+
+ turns[1].m_lanes.push_back({LaneWay::SlightLeft});
+ turns[1].m_lanes.push_back({LaneWay::Through});
+ turns[1].m_lanes.push_back({LaneWay::Through});
+
+ AddingActiveLaneInformation(turns);
+
+ TEST(turns[0].m_lanes[0].m_isActive, ());
+ TEST(!turns[0].m_lanes[1].m_isActive, ());
+
+ TEST(turns[1].m_lanes[0].m_isActive, ());
+ TEST(!turns[1].m_lanes[1].m_isActive, ());
+ TEST(!turns[1].m_lanes[1].m_isActive, ());
}
+} // namespace
diff --git a/routing/turns.cpp b/routing/turns.cpp
index 86169485e1..e9684b75e4 100644
--- a/routing/turns.cpp
+++ b/routing/turns.cpp
@@ -1,5 +1,7 @@
#include "routing/turns.hpp"
+#include "base/internal/message.hpp"
+
#include "std/array.hpp"
@@ -55,6 +57,11 @@ bool TurnGeom::operator==(TurnGeom const & other) const
&& m_points == other.m_points;
}
+bool SingleLaneInfo::operator==(SingleLaneInfo const & other) const
+{
+ return m_lane == other.m_lane && m_isActive == other.m_isActive;
+}
+
string const GetTurnString(TurnDirection turn)
{
stringstream out;
@@ -95,6 +102,70 @@ bool IsGoStraightOrSlightTurn(TurnDirection t)
return (t == TurnDirection::GoStraight || t == TurnDirection::TurnSlightLeft || t == TurnDirection::TurnSlightRight);
}
+bool IsLaneWayConformedTurnDirection(LaneWay l, TurnDirection t)
+{
+ switch(t)
+ {
+ case TurnDirection::NoTurn:
+ case TurnDirection::TakeTheExit:
+ case TurnDirection::EnterRoundAbout:
+ case TurnDirection::LeaveRoundAbout:
+ case TurnDirection::StayOnRoundAbout:
+ case TurnDirection::StartAtEndOfStreet:
+ case TurnDirection::ReachedYourDestination:
+ default:
+ return false;
+ case TurnDirection::GoStraight:
+ return l == LaneWay::Through;
+ case TurnDirection::TurnRight:
+ return l == LaneWay::Right;
+ case TurnDirection::TurnSharpRight:
+ return l == LaneWay::SharpRight;
+ case TurnDirection::TurnSlightRight:
+ return l == LaneWay::SlightRight;
+ case TurnDirection::TurnLeft:
+ return l == LaneWay::Left;
+ case TurnDirection::TurnSharpLeft:
+ return l == LaneWay::SharpLeft;
+ case TurnDirection::TurnSlightLeft:
+ return l == LaneWay::SlightLeft;
+ case TurnDirection::UTurn:
+ return l == LaneWay::Reverse;
+ }
+}
+
+bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, TurnDirection t)
+{
+ switch(t)
+ {
+ case TurnDirection::NoTurn:
+ case TurnDirection::TakeTheExit:
+ case TurnDirection::EnterRoundAbout:
+ case TurnDirection::LeaveRoundAbout:
+ case TurnDirection::StayOnRoundAbout:
+ case TurnDirection::StartAtEndOfStreet:
+ case TurnDirection::ReachedYourDestination:
+ default:
+ return false;
+ case TurnDirection::GoStraight:
+ return l == LaneWay::Through || l == LaneWay::SlightRight || l == LaneWay::SlightLeft;
+ case TurnDirection::TurnRight:
+ return l == LaneWay::Right || l == LaneWay::SharpRight || l == LaneWay::SlightRight;
+ case TurnDirection::TurnSharpRight:
+ return l == LaneWay::SharpRight || l == LaneWay::Right;
+ case TurnDirection::TurnSlightRight:
+ return l == LaneWay::SlightRight || l == LaneWay::Through || l == LaneWay::Right;
+ case TurnDirection::TurnLeft:
+ return l == LaneWay::Left || l == LaneWay::SlightLeft || l == LaneWay::SharpLeft;
+ case TurnDirection::TurnSharpLeft:
+ return l == LaneWay::SharpLeft || l == LaneWay::Left;
+ case TurnDirection::TurnSlightLeft:
+ return l == LaneWay::SlightLeft || l == LaneWay::Through || l == LaneWay::Left;
+ case TurnDirection::UTurn:
+ return l == LaneWay::Reverse;
+ }
+}
+
void SplitLanes(string const & lanesString, char delimiter, vector<string> & lanes)
{
lanes.clear();
@@ -125,7 +196,7 @@ bool ParseSingleLane(string const & laneString, char delimiter, TSingleLane & la
return true;
}
-bool ParseLanes(string lanesString, vector<TSingleLane> & lanes)
+bool ParseLanes(string lanesString, vector<SingleLaneInfo> & lanes)
{
if (lanesString.empty())
return false;
@@ -135,11 +206,11 @@ bool ParseLanes(string lanesString, vector<TSingleLane> & lanes)
lanesString.end());
vector<string> SplitLanesStrings;
- TSingleLane lane;
+ SingleLaneInfo lane;
SplitLanes(lanesString, '|', SplitLanesStrings);
for (string const & s : SplitLanesStrings)
{
- if (!ParseSingleLane(s, ';', lane))
+ if (!ParseSingleLane(s, ';', lane.m_lane))
{
lanes.clear();
return false;
@@ -179,5 +250,13 @@ string DebugPrint(TurnDirection const turn)
return out.str();
}
+string DebugPrint(SingleLaneInfo const & singleLaneInfo)
+{
+ stringstream out;
+ out << "[ m_isActive == " << singleLaneInfo.m_isActive << ". m_lane == "
+ << ::DebugPrint(singleLaneInfo.m_lane) << " ]" << endl;
+ return out.str();
+}
+
}
}
diff --git a/routing/turns.hpp b/routing/turns.hpp
index 3b5b711f51..8ff71486d0 100644
--- a/routing/turns.hpp
+++ b/routing/turns.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "std/initializer_list.hpp"
#include "std/iostream.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
@@ -88,6 +89,18 @@ string DebugPrint(TurnGeom const & turnGeom);
typedef vector<turns::TurnGeom> TurnsGeomT;
typedef vector<LaneWay> TSingleLane;
+struct SingleLaneInfo
+{
+ SingleLaneInfo(initializer_list<LaneWay> const & l = {}) : m_lane(l), m_isActive(false) {}
+
+ TSingleLane m_lane;
+ bool m_isActive;
+
+ bool operator==(SingleLaneInfo const & other) const;
+};
+
+string DebugPrint(SingleLaneInfo const & singleLaneInfo);
+
string const GetTurnString(TurnDirection turn);
bool IsLeftTurn(TurnDirection t);
@@ -96,6 +109,9 @@ bool IsLeftOrRightTurn(TurnDirection t);
bool IsStayOnRoad(TurnDirection t);
bool IsGoStraightOrSlightTurn(TurnDirection t);
+bool IsLaneWayConformedTurnDirection(LaneWay l, TurnDirection t);
+bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, TurnDirection t);
+
/*!
* \brief Parse lane information which comes from @lanesString
* \param lanesString lane information. Example through|through|through|through;right
@@ -104,7 +120,7 @@ bool IsGoStraightOrSlightTurn(TurnDirection t);
* Note 1: if @lanesString is empty returns false.
* Note 2: @laneString is passed by value on purpose. It'll be used(changed) in the method.
*/
-bool ParseLanes(string lanesString, vector<TSingleLane> & lanes);
+bool ParseLanes(string lanesString, vector<SingleLaneInfo> & lanes);
void SplitLanes(string const & lanesString, char delimiter, vector<string> & lanes);
bool ParseSingleLane(string const & laneString, char delimiter, TSingleLane & lane);
diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp
index b056407c62..d69d1a9e1c 100644
--- a/routing/turns_generator.cpp
+++ b/routing/turns_generator.cpp
@@ -8,6 +8,31 @@
#include "std/numeric.hpp"
#include "std/string.hpp"
+namespace
+{
+using namespace routing::turns;
+
+bool FixupLaneSet(TurnDirection turn, vector<SingleLaneInfo> & lanes, function<bool (LaneWay l, TurnDirection t)> checker)
+{
+ bool isLaneConformed = false;
+ // There are two hidden nested loops below (transform and find_if).
+ // But the number of calls of the body of inner one (lambda in find_if) is relatively small.
+ // Less than 10 in most cases.
+ transform(lanes.begin(), lanes.end(), lanes.begin(),
+ [&isLaneConformed, turn, checker] (SingleLaneInfo & singleLane)
+ {
+ if (find_if(singleLane.m_lane.cbegin(), singleLane.m_lane.cend(),
+ [turn, checker] (LaneWay l) { return checker(l, turn); }) != singleLane.m_lane.cend())
+ {
+ singleLane.m_isActive = true;
+ isLaneConformed = true;
+ }
+ return singleLane;
+ });
+ return isLaneConformed;
+}
+} // namespace
+
namespace routing
{
namespace turns
@@ -21,13 +46,13 @@ OsrmMappingTypes::FtSeg GetSegment(PathData const & node, RoutingMapping const &
return seg;
}
-vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
+vector<SingleLaneInfo> GetLanesInfo(PathData const & node,
RoutingMapping const & routingMapping,
TGetIndexFunction GetIndex, Index const & index)
{
// seg1 is the last segment before a point of bifurcation (before turn)
OsrmMappingTypes::FtSeg const seg1 = GetSegment(node, routingMapping, GetIndex);
- vector<routing::turns::TSingleLane> lanes;
+ vector<SingleLaneInfo> lanes;
if (seg1.IsValid())
{
FeatureType ft1;
@@ -38,7 +63,7 @@ vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
if (ftypes::IsOneWayChecker::Instance()(ft1))
{
string const turnLanes = ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES);
- routing::turns::ParseLanes(turnLanes, lanes);
+ ParseLanes(turnLanes, lanes);
return lanes;
}
// two way roads
@@ -47,20 +72,20 @@ vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
// forward direction
string const turnLanesForward =
ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_FORWARD);
- routing::turns::ParseLanes(turnLanesForward, lanes);
+ ParseLanes(turnLanesForward, lanes);
return lanes;
}
// backward direction
string const turnLanesBackward =
ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_BACKWARD);
- routing::turns::ParseLanes(turnLanesBackward, lanes);
+ ParseLanes(turnLanesBackward, lanes);
return lanes;
}
return lanes;
}
void CalculateTurnGeometry(vector<m2::PointD> const & points, Route::TurnsT const & turnsDir,
- turns::TurnsGeomT & turnsGeom)
+ TurnsGeomT & turnsGeom)
{
size_t const kNumPoints = points.size();
/// "Pivot point" is a point of bifurcation (a point of a turn).
@@ -113,24 +138,24 @@ void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
for (size_t idx = 0; idx < turnsDir.size(); )
{
TurnItem & t = turnsDir[idx];
- if (roundabout && t.m_turn != turns::TurnDirection::StayOnRoundAbout
- && t.m_turn != turns::TurnDirection::LeaveRoundAbout)
+ if (roundabout && t.m_turn != TurnDirection::StayOnRoundAbout
+ && t.m_turn != TurnDirection::LeaveRoundAbout)
{
exitNum = 0;
roundabout = nullptr;
}
- else if (t.m_turn == turns::TurnDirection::EnterRoundAbout)
+ else if (t.m_turn == TurnDirection::EnterRoundAbout)
{
ASSERT(!roundabout, ());
roundabout = &t;
}
- else if (t.m_turn == turns::TurnDirection::StayOnRoundAbout)
+ else if (t.m_turn == TurnDirection::StayOnRoundAbout)
{
++exitNum;
turnsDir.erase(turnsDir.begin() + idx);
continue;
}
- else if (roundabout && t.m_turn == turns::TurnDirection::LeaveRoundAbout)
+ else if (roundabout && t.m_turn == TurnDirection::LeaveRoundAbout)
{
roundabout->m_exitNum = exitNum + 1;
roundabout = nullptr;
@@ -142,8 +167,8 @@ void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
// means the distance in meters between the former turn (idx - 1)
// and the current turn (idx).
if (idx > 0 &&
- turns::IsStayOnRoad(turnsDir[idx - 1].m_turn) &&
- turns::IsLeftOrRightTurn(turnsDir[idx].m_turn) &&
+ IsStayOnRoad(turnsDir[idx - 1].m_turn) &&
+ IsLeftOrRightTurn(turnsDir[idx].m_turn) &&
routeDistanceMeters(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters)
{
turnsDir.erase(turnsDir.begin() + idx - 1);
@@ -151,7 +176,7 @@ void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
}
if (!t.m_keepAnyway
- && turns::IsGoStraightOrSlightTurn(t.m_turn)
+ && IsGoStraightOrSlightTurn(t.m_turn)
&& !t.m_sourceName.empty()
&& strings::AlmostEqual(t.m_sourceName, t.m_targetName, 2 /* mismatched symbols count */))
{
@@ -161,7 +186,23 @@ void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
++idx;
}
+ AddingActiveLaneInformation(turnsDir);
return;
}
+
+void AddingActiveLaneInformation(Route::TurnsT & turnsDir)
+{
+ for (auto & t : turnsDir)
+ {
+ vector<turns::SingleLaneInfo> & lanes = t.m_lanes;
+ if (lanes.empty())
+ continue;
+ TurnDirection const turn = t.m_turn;
+ if (FixupLaneSet(turn, lanes, IsLaneWayConformedTurnDirection))
+ continue;
+ FixupLaneSet(turn, lanes, IsLaneWayConformedTurnDirectionApproximately);
+ }
+}
+
}
}
diff --git a/routing/turns_generator.hpp b/routing/turns_generator.hpp
index c4e3099514..c461911908 100644
--- a/routing/turns_generator.hpp
+++ b/routing/turns_generator.hpp
@@ -22,14 +22,16 @@ typedef function<size_t(pair<size_t, size_t>)> TGetIndexFunction;
OsrmMappingTypes::FtSeg GetSegment(PathData const & node, RoutingMapping const & routingMapping,
TGetIndexFunction GetIndex);
-vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
+vector<SingleLaneInfo> GetLanesInfo(PathData const & node,
RoutingMapping const & routingMapping,
TGetIndexFunction GetIndex, Index const & index);
/// CalculateTurnGeometry calculates geometry for all the turns. That means that for every turn
/// CalculateTurnGeometry calculates a sequence of points which will be used
/// for displaying arrows on the route.
void CalculateTurnGeometry(vector<m2::PointD> const & points, Route::TurnsT const & turnsDir,
- turns::TurnsGeomT & turnsGeom);
+ TurnsGeomT & turnsGeom);
+// Selects lanes which are recommended for the end user.
+void AddingActiveLaneInformation(Route::TurnsT & turnsDir);
void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir);
}
}