diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/app/organicmaps/Framework.cpp
index 407e73e852..4fd22617f4 100644
--- a/android/jni/app/organicmaps/Framework.cpp
+++ b/android/jni/app/organicmaps/Framework.cpp
@@ -1425,6 +1425,7 @@ Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint router
case 1: type = Type::Pedestrian; break;
case 2: type = Type::Bicycle; break;
case 3: type = Type::Transit; break;
+ case 4: type = Type::Ruler; break;
default: assert(false); break;
}
g_framework->GetRoutingManager().SetRouter(type);
diff --git a/android/res/drawable/ic_ruler_route.xml b/android/res/drawable/ic_ruler_route.xml
new file mode 100644
index 0000000000..c502863276
--- /dev/null
+++ b/android/res/drawable/ic_ruler_route.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/routing_bottom_panel_transit.xml b/android/res/layout/routing_bottom_panel_transit.xml
index 22156f22ad..cce2c490be 100644
--- a/android/res/layout/routing_bottom_panel_transit.xml
+++ b/android/res/layout/routing_bottom_panel_transit.xml
@@ -46,7 +46,7 @@
android:id="@+id/transit_recycler_view"
android:layout_marginTop="@dimen/margin_half_plus"
android:layout_alignParentStart="true"
- android:layout_below="@id/total_distance"
+ android:layout_below="@id/total_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
diff --git a/android/res/layout/routing_plan.xml b/android/res/layout/routing_plan.xml
index 1ca805f769..23382f782f 100644
--- a/android/res/layout/routing_plan.xml
+++ b/android/res/layout/routing_plan.xml
@@ -73,6 +73,14 @@
android:layout_marginEnd="12dp"
tools:button="@drawable/ic_bike"
tools:buttonTint="?iconTintLight" />
+
+
+
+
diff --git a/android/res/values-ar/strings.xml b/android/res/values-ar/strings.xml
index a8923fb9fc..0878e695bf 100644
--- a/android/res/values-ar/strings.xml
+++ b/android/res/values-ar/strings.xml
@@ -240,6 +240,7 @@
6 ساعات
12 ساعة
1 يوم
+ المسافة
مشاهدة على الخريطة
القائمة
diff --git a/android/res/values-be/strings.xml b/android/res/values-be/strings.xml
index e32d5d9138..185f87d83e 100644
--- a/android/res/values-be/strings.xml
+++ b/android/res/values-be/strings.xml
@@ -238,6 +238,7 @@
6 гадзін
12 гадзін
1 дзень
+ Адлегласць
Паглядзець на мапе
Вэб-сайт
diff --git a/android/res/values-ca/strings.xml b/android/res/values-ca/strings.xml
index 6509b9173c..318cc5023f 100644
--- a/android/res/values-ca/strings.xml
+++ b/android/res/values-ca/strings.xml
@@ -229,6 +229,7 @@
6 hores
12 hores
1 dia
+ Distància
Veure al mapa
Menú
diff --git a/android/res/values-cs/strings.xml b/android/res/values-cs/strings.xml
index 1fddef10a8..b195fb12c3 100644
--- a/android/res/values-cs/strings.xml
+++ b/android/res/values-cs/strings.xml
@@ -224,6 +224,7 @@
6 hodin
12 hodin
1 den
+ Vzdálenost
Zobrazit na mapě
Webové stránky
diff --git a/android/res/values-da/strings.xml b/android/res/values-da/strings.xml
index e2f8fe4bab..0e8c0cba0b 100644
--- a/android/res/values-da/strings.xml
+++ b/android/res/values-da/strings.xml
@@ -220,6 +220,7 @@
6 timer
12 timer
1 dag
+ Afstand
Vis på kortet
Hjemmeside
diff --git a/android/res/values-de/strings.xml b/android/res/values-de/strings.xml
index 77273b732d..c232779a57 100644
--- a/android/res/values-de/strings.xml
+++ b/android/res/values-de/strings.xml
@@ -237,6 +237,7 @@
6 Stunden
12 Stunden
1 Tag
+ Entfernung
Auf der Karte ansehen
Webseite
diff --git a/android/res/values-es/strings.xml b/android/res/values-es/strings.xml
index d18079ce8a..bec07608b8 100644
--- a/android/res/values-es/strings.xml
+++ b/android/res/values-es/strings.xml
@@ -237,6 +237,7 @@
6 horas
12 horas
1 día
+ Distancia
Ver en el mapa
Menú
diff --git a/android/res/values-et/strings.xml b/android/res/values-et/strings.xml
index 4ade70e815..7f76b663df 100644
--- a/android/res/values-et/strings.xml
+++ b/android/res/values-et/strings.xml
@@ -229,6 +229,7 @@
6 tundi
12 tundi
1 päev
+ Kaugus
Vaata kaardil
Veebileht
diff --git a/android/res/values-eu/strings.xml b/android/res/values-eu/strings.xml
index a48ae6563c..c2dd253ec7 100644
--- a/android/res/values-eu/strings.xml
+++ b/android/res/values-eu/strings.xml
@@ -237,6 +237,7 @@
6 ordu
12 ordu
egun 1
+ Distantzia
Ikusi mapan
Menua
diff --git a/android/res/values-fa/strings.xml b/android/res/values-fa/strings.xml
index 2e84f208e8..8e6016bd80 100644
--- a/android/res/values-fa/strings.xml
+++ b/android/res/values-fa/strings.xml
@@ -213,6 +213,7 @@
6 ساعت
12 ساعت
1 روز
+ مسافت
مشاهده بر روی نقشه
وب سایت
diff --git a/android/res/values-fi/strings.xml b/android/res/values-fi/strings.xml
index c3542f46f2..077a680c4f 100644
--- a/android/res/values-fi/strings.xml
+++ b/android/res/values-fi/strings.xml
@@ -239,6 +239,7 @@
6 tuntia
12 tuntia
1 päivä
+ Etäisyys
Näytä kartalla
Menu
diff --git a/android/res/values-fr/strings.xml b/android/res/values-fr/strings.xml
index ea676004b5..715c9996c4 100644
--- a/android/res/values-fr/strings.xml
+++ b/android/res/values-fr/strings.xml
@@ -239,6 +239,7 @@
6 heures
12 heures
1 jour
+ Distance
Voir sur la carte
Menu
diff --git a/android/res/values-hu/strings.xml b/android/res/values-hu/strings.xml
index 9188a13972..727afeebf5 100644
--- a/android/res/values-hu/strings.xml
+++ b/android/res/values-hu/strings.xml
@@ -234,6 +234,7 @@
6 óra
12 óra
1 nap
+ Távolság
Megtekintés a térképen
Honlap
diff --git a/android/res/values-in/strings.xml b/android/res/values-in/strings.xml
index c95119f35a..31598c9d1b 100644
--- a/android/res/values-in/strings.xml
+++ b/android/res/values-in/strings.xml
@@ -222,6 +222,7 @@
6 jam
12 jam
1 hari
+ Jarak
Tampilkan pada peta
Situs Web
diff --git a/android/res/values-it/strings.xml b/android/res/values-it/strings.xml
index 8f4ea392ae..c370266b13 100644
--- a/android/res/values-it/strings.xml
+++ b/android/res/values-it/strings.xml
@@ -225,6 +225,7 @@
6 ore
12 ore
1 giorno
+ Distanza
Visualizza sulla mappa
Sito web
diff --git a/android/res/values-iw/strings.xml b/android/res/values-iw/strings.xml
index af51fb157b..81610d5c3e 100644
--- a/android/res/values-iw/strings.xml
+++ b/android/res/values-iw/strings.xml
@@ -172,6 +172,7 @@
הצג על המסך
מבנים תלת מימדיים כבויים במצב חיסכון בחשמל
+ מרחק
ראה במפה
תוֹשׁדָחֲ
diff --git a/android/res/values-ja/strings.xml b/android/res/values-ja/strings.xml
index 0214f1f5af..957cbf2d25 100644
--- a/android/res/values-ja/strings.xml
+++ b/android/res/values-ja/strings.xml
@@ -218,6 +218,7 @@
6時間
12時間
1日
+ 距離
地図に表示
ウェブサイト
diff --git a/android/res/values-ko/strings.xml b/android/res/values-ko/strings.xml
index 550c1ee84a..28fc0d629a 100644
--- a/android/res/values-ko/strings.xml
+++ b/android/res/values-ko/strings.xml
@@ -220,6 +220,7 @@
6시간
12시간
1일
+ 거리
지도 보기
웹사이트
diff --git a/android/res/values-mr/strings.xml b/android/res/values-mr/strings.xml
index 4c5374d4ac..9386aa4f90 100644
--- a/android/res/values-mr/strings.xml
+++ b/android/res/values-mr/strings.xml
@@ -213,6 +213,7 @@
६ तास
१२ तास
१ दिवस
+ अंतर
नकाशावर पहा
संकेतस्थळ
diff --git a/android/res/values-nb/strings.xml b/android/res/values-nb/strings.xml
index 71f31b3832..150296c1e7 100644
--- a/android/res/values-nb/strings.xml
+++ b/android/res/values-nb/strings.xml
@@ -239,6 +239,7 @@
6 timer
12 timer
1 dag
+ Avstand
Vis på kartet
Meny
diff --git a/android/res/values-nl/strings.xml b/android/res/values-nl/strings.xml
index 5342bb9e29..dd786151d2 100644
--- a/android/res/values-nl/strings.xml
+++ b/android/res/values-nl/strings.xml
@@ -237,6 +237,7 @@
6 uur
12 uur
1 dag
+ Afstand
Op kaart bekijken
Website
diff --git a/android/res/values-pl/strings.xml b/android/res/values-pl/strings.xml
index 1028273130..cab770122a 100644
--- a/android/res/values-pl/strings.xml
+++ b/android/res/values-pl/strings.xml
@@ -237,6 +237,7 @@
6 godzin
12 godzin
1 dzień
+ Dystans
Wyświetl na mapie
Menu
diff --git a/android/res/values-pt-rBR/strings.xml b/android/res/values-pt-rBR/strings.xml
index f95d535aac..af26ff7a9f 100644
--- a/android/res/values-pt-rBR/strings.xml
+++ b/android/res/values-pt-rBR/strings.xml
@@ -235,6 +235,7 @@
6 horas
12 horas
1 dia
+ Distância
Ver no mapa
Site
diff --git a/android/res/values-pt/strings.xml b/android/res/values-pt/strings.xml
index 70b7d596a7..f70a9e976f 100644
--- a/android/res/values-pt/strings.xml
+++ b/android/res/values-pt/strings.xml
@@ -225,6 +225,7 @@
6 horas
12 horas
1 dia
+ Distância
Ver no mapa
Site
diff --git a/android/res/values-ro/strings.xml b/android/res/values-ro/strings.xml
index 56ffd26526..0db52e6bbb 100644
--- a/android/res/values-ro/strings.xml
+++ b/android/res/values-ro/strings.xml
@@ -225,6 +225,7 @@
6 ore
12 ore
1 zi
+ Distanță
Vezi pe hartă
Site web
diff --git a/android/res/values-ru/strings.xml b/android/res/values-ru/strings.xml
index 8c57d7444c..548d62eec2 100644
--- a/android/res/values-ru/strings.xml
+++ b/android/res/values-ru/strings.xml
@@ -240,6 +240,7 @@
6 часов
12 часов
1 сутки
+ Расстояние
Посмотреть на карте
Меню
diff --git a/android/res/values-sk/strings.xml b/android/res/values-sk/strings.xml
index eb40cc562b..4b0390da47 100644
--- a/android/res/values-sk/strings.xml
+++ b/android/res/values-sk/strings.xml
@@ -220,6 +220,7 @@
6 hodín
12 hodín
1 deň
+ Vzdialenosť
Zobraziť na mape
Webové stránky
diff --git a/android/res/values-sv/strings.xml b/android/res/values-sv/strings.xml
index 63554e39a6..dfc48273ba 100644
--- a/android/res/values-sv/strings.xml
+++ b/android/res/values-sv/strings.xml
@@ -218,6 +218,7 @@
6 timmar
12 timmar
1 dag
+ Avstånd
Visa på kartan
Webbplats
diff --git a/android/res/values-th/strings.xml b/android/res/values-th/strings.xml
index f3c9b581f9..ccee81d82e 100644
--- a/android/res/values-th/strings.xml
+++ b/android/res/values-th/strings.xml
@@ -222,6 +222,7 @@
6 ชั่วโมง
12 ชั่วโมง
1 วัน
+ ระยะห่าง
ดูบนแผนที่
เว็บไซต์
diff --git a/android/res/values-tr/strings.xml b/android/res/values-tr/strings.xml
index 91829c1766..d57363ffec 100644
--- a/android/res/values-tr/strings.xml
+++ b/android/res/values-tr/strings.xml
@@ -239,6 +239,7 @@
6 saat
12 saat
1 gün
+ Mesafe
Haritada görüntüle
Web Sitesi
diff --git a/android/res/values-uk/strings.xml b/android/res/values-uk/strings.xml
index 808e1f7c31..291007ad46 100644
--- a/android/res/values-uk/strings.xml
+++ b/android/res/values-uk/strings.xml
@@ -233,6 +233,7 @@
6 годин
12 годин
1 день
+ Відстань
Подивитись на мапі
Меню
diff --git a/android/res/values-vi/strings.xml b/android/res/values-vi/strings.xml
index 53ce37a3b4..0e18ebbff9 100644
--- a/android/res/values-vi/strings.xml
+++ b/android/res/values-vi/strings.xml
@@ -220,6 +220,7 @@
6 giờ
12 giờ
1 ngày
+ Khoảng cách
Xem trên bản đồ
Trang web
diff --git a/android/res/values-zh-rTW/strings.xml b/android/res/values-zh-rTW/strings.xml
index 5c91bf1f2c..684f78d926 100644
--- a/android/res/values-zh-rTW/strings.xml
+++ b/android/res/values-zh-rTW/strings.xml
@@ -225,6 +225,7 @@
6小時
12小時
1天
+ 距离
在地圖上查看
網站
diff --git a/android/res/values-zh/strings.xml b/android/res/values-zh/strings.xml
index 742497a15a..9c3d875572 100644
--- a/android/res/values-zh/strings.xml
+++ b/android/res/values-zh/strings.xml
@@ -224,6 +224,7 @@
6小时
12小时
1天
+ 距离
在地图上查看
网站
diff --git a/android/res/values/font_sizes.xml b/android/res/values/font_sizes.xml
index 63aee99c7a..c118412a70 100644
--- a/android/res/values/font_sizes.xml
+++ b/android/res/values/font_sizes.xml
@@ -51,6 +51,7 @@
20sp
16sp
14sp
+ 20sp
56sp
17sp
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 14007d0f72..928ab80a85 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -240,6 +240,7 @@
6 hours
12 hours
1 day
+ Distance
View on map
Menu
diff --git a/android/res/values/themes-attrs.xml b/android/res/values/themes-attrs.xml
index a5bd6ca2cb..d5b1c19b8c 100644
--- a/android/res/values/themes-attrs.xml
+++ b/android/res/values/themes-attrs.xml
@@ -42,6 +42,7 @@
+
diff --git a/android/res/values/themes-base.xml b/android/res/values/themes-base.xml
index da9956219d..79aeb84d0d 100644
--- a/android/res/values/themes-base.xml
+++ b/android/res/values/themes-base.xml
@@ -87,6 +87,7 @@
- @drawable/back_arrow
- @color/black_4
+ - @color/black_4
- @drawable/dot_divider
- @drawable/ic_layers_traffic_active
- @drawable/ic_layers_subway_active
@@ -221,6 +222,7 @@
- @drawable/back_arrow
- @color/white_4
+ - @color/white_4
- @drawable/dot_divider_night
- @drawable/ic_layers_traffic_active_night
- @drawable/ic_layers_subway_active_night
diff --git a/android/src/app/organicmaps/Framework.java b/android/src/app/organicmaps/Framework.java
index 1b84662aab..7cbb8d1ab5 100644
--- a/android/src/app/organicmaps/Framework.java
+++ b/android/src/app/organicmaps/Framework.java
@@ -46,7 +46,7 @@ public class Framework
public static final int MAP_STYLE_VEHICLE_DARK = 4;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE, ROUTER_TYPE_TRANSIT })
+ @IntDef({ ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE, ROUTER_TYPE_TRANSIT, ROUTER_TYPE_RULER })
public @interface RouterType {}
@@ -54,6 +54,7 @@ public class Framework
public static final int ROUTER_TYPE_PEDESTRIAN = 1;
public static final int ROUTER_TYPE_BICYCLE = 2;
public static final int ROUTER_TYPE_TRANSIT = 3;
+ public static final int ROUTER_TYPE_RULER = 4;
@Retention(RetentionPolicy.SOURCE)
@IntDef({DO_AFTER_UPDATE_NOTHING, DO_AFTER_UPDATE_AUTO_UPDATE, DO_AFTER_UPDATE_ASK_FOR_UPDATE})
diff --git a/android/src/app/organicmaps/routing/RoutingBottomMenuController.java b/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
index 35ab883c59..acb5488dd9 100644
--- a/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
+++ b/android/src/app/organicmaps/routing/RoutingBottomMenuController.java
@@ -29,13 +29,17 @@ import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.Framework;
import app.organicmaps.R;
+import app.organicmaps.bookmarks.data.DistanceAndAzimut;
import app.organicmaps.location.LocationHelper;
+import app.organicmaps.util.Distance;
import app.organicmaps.widget.recycler.DotDividerItemDecoration;
import app.organicmaps.widget.recycler.MultilineLayoutManager;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.UiUtils;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Locale;
final class RoutingBottomMenuController implements View.OnClickListener
@@ -135,9 +139,10 @@ final class RoutingBottomMenuController implements View.OnClickListener
void showAltitudeChartAndRoutingDetails()
{
- UiUtils.hide(mError, mActionFrame, mTransitFrame);
+ UiUtils.hide(mError, mActionFrame, mAltitudeChart, mAltitudeDifference, mTransitFrame);
- showRouteAltitudeChart();
+ if (!RoutingController.get().isVehicleRouterType() && !RoutingController.get().isRulerRouterType())
+ showRouteAltitudeChart();
showRoutingDetails();
UiUtils.show(mAltitudeChartFrame);
}
@@ -172,6 +177,53 @@ final class RoutingBottomMenuController implements View.OnClickListener
distanceView.setText(info.getTotalPedestrianDistance() + " " + info.getTotalPedestrianDistanceUnits());
}
+ @SuppressLint("SetTextI18n")
+ void showRulerInfo(@NonNull RouteMarkData[] points, Distance totalLength)
+ {
+ UiUtils.hide(mError, mAltitudeChartFrame, mActionFrame, mAltitudeChartFrame);
+ showStartButton(false);
+ UiUtils.show(mTransitFrame);
+ final RecyclerView rv = mTransitFrame.findViewById(R.id.transit_recycler_view);
+ if (points.length > 2)
+ {
+ UiUtils.show(rv);
+ final TransitStepAdapter adapter = new TransitStepAdapter();
+ rv.setLayoutManager(new MultilineLayoutManager());
+ rv.setNestedScrollingEnabled(false);
+ rv.removeItemDecoration(mTransitViewDecorator);
+ rv.addItemDecoration(mTransitViewDecorator);
+ rv.setAdapter(adapter);
+ adapter.setItems(pointsToRulerSteps(points));
+ }
+ else
+ UiUtils.hide(rv); // Show only distance between start and finish
+
+ TextView totalTimeView = mTransitFrame.findViewById(R.id.total_time);
+ totalTimeView.setText(mContext.getString(R.string.placepage_distance) + ": " +
+ totalLength.mDistanceStr + " " + totalLength.getUnitsStr(mContext));
+
+ UiUtils.hide(mTransitFrame, R.id.dot);
+ UiUtils.hide(mTransitFrame, R.id.pedestrian_icon);
+ UiUtils.hide(mTransitFrame, R.id.total_distance);
+ }
+
+ // Create steps info to use in TransitStepAdapter.
+ private List pointsToRulerSteps(RouteMarkData[] points)
+ {
+ List transitSteps = new LinkedList<>();
+ for (int i = 1; i < points.length; i++)
+ {
+ RouteMarkData segmentStart = points[i - 1];
+ RouteMarkData segmentEnd = points[i];
+ DistanceAndAzimut dist = Framework.nativeGetDistanceAndAzimuthFromLatLon(segmentStart.mLat, segmentStart.mLon, segmentEnd.mLat, segmentEnd.mLon, 0);
+ if (i > 1)
+ transitSteps.add(TransitStepInfo.intermediatePoint(i - 2));
+ transitSteps.add(TransitStepInfo.ruler(dist.getDistance().mDistanceStr, dist.getDistance().getUnitsStr(mContext)));
+ }
+
+ return transitSteps;
+ }
+
void showAddStartFrame()
{
UiUtils.hide(mError, mTransitFrame);
@@ -206,15 +258,18 @@ final class RoutingBottomMenuController implements View.OnClickListener
UiUtils.hide(mActionFrame);
}
- void setStartButton()
+ void setStartButton(boolean show)
{
- mStart.setText(mContext.getText(R.string.p2p_start));
- mStart.setOnClickListener(v -> {
- if (mListener != null)
- mListener.onRoutingStart();
- });
+ if (show)
+ {
+ mStart.setText(mContext.getText(R.string.p2p_start));
+ mStart.setOnClickListener(v -> {
+ if (mListener != null)
+ mListener.onRoutingStart();
+ });
+ }
- showStartButton(true);
+ showStartButton(show);
}
private void showError(@NonNull String message)
diff --git a/android/src/app/organicmaps/routing/RoutingController.java b/android/src/app/organicmaps/routing/RoutingController.java
index 2461fb5664..5ac320a141 100644
--- a/android/src/app/organicmaps/routing/RoutingController.java
+++ b/android/src/app/organicmaps/routing/RoutingController.java
@@ -603,6 +603,11 @@ public class RoutingController implements Initializable
return mLastRouterType == Framework.ROUTER_TYPE_VEHICLE;
}
+ boolean isRulerRouterType()
+ {
+ return mLastRouterType == Framework.ROUTER_TYPE_RULER;
+ }
+
public boolean isNavigating()
{
return mState == State.NAVIGATION;
@@ -815,22 +820,14 @@ public class RoutingController implements Initializable
}
if (isSamePoint)
- {
- Logger.d(TAG, "setEndPoint: skip the same end point");
return false;
- }
if (point != null && point.sameAs(startPoint))
{
if (endPoint == null)
- {
- Logger.d(TAG, "setEndPoint: skip because end point is empty");
return false;
- }
- Logger.d(TAG, "setEndPoint: swap with starting point");
startPoint = endPoint;
-
}
endPoint = point;
diff --git a/android/src/app/organicmaps/routing/RoutingPlanController.java b/android/src/app/organicmaps/routing/RoutingPlanController.java
index f3ca006bf4..403e1c23d2 100644
--- a/android/src/app/organicmaps/routing/RoutingPlanController.java
+++ b/android/src/app/organicmaps/routing/RoutingPlanController.java
@@ -39,6 +39,8 @@ public class RoutingPlanController extends ToolbarController
private final WheelProgressView mProgressTransit;
@NonNull
private final WheelProgressView mProgressBicycle;
+ @NonNull
+ private final WheelProgressView mProgressRuler;
// @NonNull
// private final WheelProgressView mProgressTaxi;
@@ -93,6 +95,7 @@ public class RoutingPlanController extends ToolbarController
mProgressPedestrian = progressFrame.findViewById(R.id.progress_pedestrian);
mProgressTransit = progressFrame.findViewById(R.id.progress_transit);
mProgressBicycle = progressFrame.findViewById(R.id.progress_bicycle);
+ mProgressRuler = progressFrame.findViewById(R.id.progress_ruler);
// mProgressTaxi = (WheelProgressView) progressFrame.findViewById(R.id.progress_taxi);
mRoutingBottomMenuController = RoutingBottomMenuController.newInstance(requireActivity(), mFrame, listener);
@@ -128,12 +131,13 @@ public class RoutingPlanController extends ToolbarController
{
setupRouterButton(R.id.vehicle, R.drawable.ic_car, this::onVehicleModeSelected);
setupRouterButton(R.id.pedestrian, R.drawable.ic_pedestrian, this::onPedestrianModeSelected);
- setupRouterButton(R.id.bicycle, R.drawable.ic_bike, this::onBicycleModeSelected);
// setupRouterButton(R.id.taxi, R.drawable.ic_taxi, this::onTaxiModeSelected);
- setupRouterButton(R.id.transit, R.drawable.ic_transit, v -> onTransitModeSelected());
+ setupRouterButton(R.id.transit, R.drawable.ic_transit, this::onTransitModeSelected);
+ setupRouterButton(R.id.bicycle, R.drawable.ic_bike, this::onBicycleModeSelected);
+ setupRouterButton(R.id.ruler, R.drawable.ic_ruler_route, this::onRulerModeSelected);
}
- private void onTransitModeSelected()
+ private void onTransitModeSelected(@NonNull View v)
{
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_TRANSIT);
}
@@ -143,6 +147,11 @@ public class RoutingPlanController extends ToolbarController
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_BICYCLE);
}
+ private void onRulerModeSelected(@NonNull View v)
+ {
+ RoutingController.get().setRouterType(Framework.ROUTER_TYPE_RULER);
+ }
+
private void onPedestrianModeSelected(@NonNull View v)
{
RoutingController.get().setRouterType(Framework.ROUTER_TYPE_PEDESTRIAN);
@@ -172,7 +181,7 @@ public class RoutingPlanController extends ToolbarController
{
RoutingController.BuildState buildState = RoutingController.get().getBuildState();
- boolean ready = (buildState == RoutingController.BuildState.BUILT);
+ final boolean ready = (buildState == RoutingController.BuildState.BUILT);
if (!ready)
{
@@ -188,39 +197,53 @@ public class RoutingPlanController extends ToolbarController
return;
}
- mRoutingBottomMenuController.setStartButton();
+ if (isRulerType())
+ {
+ RoutingInfo routingInfo = RoutingController.get().getCachedRoutingInfo();
+ if (routingInfo != null)
+ mRoutingBottomMenuController.showRulerInfo(Framework.nativeGetRoutePoints(), routingInfo.distToTarget);
+ return;
+ }
+
+ final boolean showStartButton = !RoutingController.get().isRulerRouterType();
+ mRoutingBottomMenuController.setStartButton(showStartButton);
mRoutingBottomMenuController.showAltitudeChartAndRoutingDetails();
}
public void updateBuildProgress(int progress, @Framework.RouterType int router)
{
UiUtils.invisible(mProgressVehicle, mProgressPedestrian, mProgressTransit,
- mProgressBicycle);
+ mProgressBicycle, mProgressRuler);
WheelProgressView progressView;
- if (router == Framework.ROUTER_TYPE_VEHICLE)
+ switch(router)
{
+ case Framework.ROUTER_TYPE_VEHICLE:
mRouterTypes.check(R.id.vehicle);
progressView = mProgressVehicle;
- }
- else if (router == Framework.ROUTER_TYPE_PEDESTRIAN)
- {
+ break;
+ case Framework.ROUTER_TYPE_PEDESTRIAN:
mRouterTypes.check(R.id.pedestrian);
progressView = mProgressPedestrian;
- }
-// else if (router == Framework.ROUTER_TYPE_TAXI)
-// {
-// mRouterTypes.check(R.id.taxi);
-// progressView = mProgressTaxi;
-// }
- else if (router == Framework.ROUTER_TYPE_TRANSIT)
- {
+ break;
+ //case Framework.ROUTER_TYPE_TAXI:
+ // {
+ // mRouterTypes.check(R.id.taxi);
+ // progressView = mProgressTaxi;
+ // }
+ case Framework.ROUTER_TYPE_TRANSIT:
mRouterTypes.check(R.id.transit);
progressView = mProgressTransit;
- }
- else
- {
+ break;
+ case Framework.ROUTER_TYPE_BICYCLE:
mRouterTypes.check(R.id.bicycle);
progressView = mProgressBicycle;
+ break;
+ case Framework.ROUTER_TYPE_RULER:
+ mRouterTypes.check(R.id.ruler);
+ progressView = mProgressRuler;
+ break;
+ default:
+ throw new IllegalArgumentException("unknown router: " + router);
}
RoutingToolbarButton button = mRouterTypes
@@ -246,6 +269,11 @@ public class RoutingPlanController extends ToolbarController
return RoutingController.get().isTransitType();
}
+ private boolean isRulerType()
+ {
+ return RoutingController.get().isRulerRouterType();
+ }
+
void saveRoutingPanelState(@NonNull Bundle outState)
{
mRoutingBottomMenuController.saveRoutingPanelState(outState);
diff --git a/android/src/app/organicmaps/routing/TransitStepInfo.java b/android/src/app/organicmaps/routing/TransitStepInfo.java
index 64b3a517fb..9bcff82c4d 100644
--- a/android/src/app/organicmaps/routing/TransitStepInfo.java
+++ b/android/src/app/organicmaps/routing/TransitStepInfo.java
@@ -18,10 +18,11 @@ public class TransitStepInfo
private static final int TRANSIT_TYPE_TRAIN = 3;
private static final int TRANSIT_TYPE_LIGHT_RAIL = 4;
private static final int TRANSIT_TYPE_MONORAIL = 5;
+ private static final int TRANSIT_TYPE_RULER = 6;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ TRANSIT_TYPE_INTERMEDIATE_POINT, TRANSIT_TYPE_PEDESTRIAN, TRANSIT_TYPE_SUBWAY,
- TRANSIT_TYPE_TRAIN, TRANSIT_TYPE_LIGHT_RAIL, TRANSIT_TYPE_MONORAIL })
+ TRANSIT_TYPE_TRAIN, TRANSIT_TYPE_LIGHT_RAIL, TRANSIT_TYPE_MONORAIL, TRANSIT_TYPE_RULER})
@interface TransitType {}
@NonNull
@@ -48,6 +49,18 @@ public class TransitStepInfo
mIntermediateIndex = intermediateIndex;
}
+ @NonNull
+ public static TransitStepInfo intermediatePoint(int intermediateIndex)
+ {
+ return new TransitStepInfo(TRANSIT_TYPE_INTERMEDIATE_POINT, null, null, 0, null, 0, intermediateIndex);
+ }
+
+ @NonNull
+ public static TransitStepInfo ruler(@NonNull String distance, @NonNull String distanceUnits)
+ {
+ return new TransitStepInfo(TRANSIT_TYPE_RULER, distance, distanceUnits, 0, null, 0, -1);
+ }
+
@NonNull
public TransitStepType getType()
{
diff --git a/android/src/app/organicmaps/routing/TransitStepType.java b/android/src/app/organicmaps/routing/TransitStepType.java
index 4aea7389b8..bf1ffd9a6d 100644
--- a/android/src/app/organicmaps/routing/TransitStepType.java
+++ b/android/src/app/organicmaps/routing/TransitStepType.java
@@ -12,7 +12,8 @@ public enum TransitStepType
SUBWAY(R.drawable.ic_20px_route_planning_metro),
TRAIN(R.drawable.ic_20px_route_planning_train),
LIGHT_RAIL(R.drawable.ic_20px_route_planning_lightrail),
- MONORAIL(R.drawable.ic_20px_route_planning_monorail);
+ MONORAIL(R.drawable.ic_20px_route_planning_monorail),
+ RULER(R.drawable.ic_ruler_route);
@DrawableRes
private final int mDrawable;
diff --git a/android/src/app/organicmaps/routing/TransitStepView.java b/android/src/app/organicmaps/routing/TransitStepView.java
index 5955557530..87d5116828 100644
--- a/android/src/app/organicmaps/routing/TransitStepView.java
+++ b/android/src/app/organicmaps/routing/TransitStepView.java
@@ -85,6 +85,12 @@ public class TransitStepView extends View implements MultilineLayoutManager.Sque
mDrawable = null;
mText = String.valueOf(info.getIntermediateIndex() + 1);
}
+ else if (mStepType == TransitStepType.RULER)
+ {
+ mDrawable = null;
+ mText = info.getDistance() + " " + info.getDistanceUnits();
+ mTextPaint.setColor(Color.BLACK);
+ }
else
{
mDrawable = ResourcesCompat.getDrawable(getResources(), mStepType.getDrawable(), null);
@@ -101,6 +107,8 @@ public class TransitStepView extends View implements MultilineLayoutManager.Sque
{
case PEDESTRIAN:
return ThemeUtils.getColor(context, R.attr.transitPedestrianBackground);
+ case RULER:
+ return ThemeUtils.getColor(context, R.attr.transitRulerBackground);
case INTERMEDIATE_POINT:
return ThemeUtils.getColor(context, R.attr.colorPrimary);
default:
diff --git a/data/colors.txt b/data/colors.txt
index 43c3bd1185..ee5c2672dd 100644
--- a/data/colors.txt
+++ b/data/colors.txt
@@ -313,6 +313,7 @@
436207616
437326080
442260561
+442905727
444234362
451800027
452984831
@@ -367,6 +368,7 @@
1300793480
1301043238
1301133440
+1301433013
1304608947
1306780114
1308576652
diff --git a/data/drules_proto_clear.bin b/data/drules_proto_clear.bin
index b479ab2e63..5cf3f60360 100644
Binary files a/data/drules_proto_clear.bin and b/data/drules_proto_clear.bin differ
diff --git a/data/drules_proto_clear.txt b/data/drules_proto_clear.txt
index 8cea0cb280..e9b727d5ca 100644
--- a/data/drules_proto_clear.txt
+++ b/data/drules_proto_clear.txt
@@ -104992,6 +104992,10 @@ colors {
name: "RoutePreview"
color: 3003121664
}
+ value {
+ name: "RouteRuler"
+ color: 442905727
+ }
value {
name: "RouteTrafficG0"
color: 10167040
diff --git a/data/drules_proto_dark.bin b/data/drules_proto_dark.bin
index d958dff215..795d3045cb 100644
Binary files a/data/drules_proto_dark.bin and b/data/drules_proto_dark.bin differ
diff --git a/data/drules_proto_dark.txt b/data/drules_proto_dark.txt
index 5ccfbe244a..6fb75ebf1c 100644
--- a/data/drules_proto_dark.txt
+++ b/data/drules_proto_dark.txt
@@ -105079,6 +105079,10 @@ colors {
name: "RoutePreview"
color: 3019898879
}
+ value {
+ name: "RouteRuler"
+ color: 1301433013
+ }
value {
name: "RouteTrafficG0"
color: 6164237
diff --git a/data/drules_proto_vehicle_clear.bin b/data/drules_proto_vehicle_clear.bin
index 53fd640686..47b81afd34 100644
Binary files a/data/drules_proto_vehicle_clear.bin and b/data/drules_proto_vehicle_clear.bin differ
diff --git a/data/drules_proto_vehicle_clear.txt b/data/drules_proto_vehicle_clear.txt
index 5b48316f63..77a8db1659 100644
--- a/data/drules_proto_vehicle_clear.txt
+++ b/data/drules_proto_vehicle_clear.txt
@@ -74571,6 +74571,10 @@ colors {
name: "RoutePreview"
color: 3003121664
}
+ value {
+ name: "RouteRuler"
+ color: 857551774
+ }
value {
name: "RouteTrafficG0"
color: 10167040
diff --git a/data/drules_proto_vehicle_dark.bin b/data/drules_proto_vehicle_dark.bin
index a1de38ecf3..e3105de600 100644
Binary files a/data/drules_proto_vehicle_dark.bin and b/data/drules_proto_vehicle_dark.bin differ
diff --git a/data/drules_proto_vehicle_dark.txt b/data/drules_proto_vehicle_dark.txt
index 593deb0ebc..8b5f2aa239 100644
--- a/data/drules_proto_vehicle_dark.txt
+++ b/data/drules_proto_vehicle_dark.txt
@@ -74948,6 +74948,10 @@ colors {
name: "RoutePreview"
color: 3019898879
}
+ value {
+ name: "RouteRuler"
+ color: 1308604747
+ }
value {
name: "RouteTrafficG0"
color: 6164237
diff --git a/data/strings/strings.txt b/data/strings/strings.txt
index 0eaae0a004..408e2300a9 100644
--- a/data/strings/strings.txt
+++ b/data/strings/strings.txt
@@ -5710,7 +5710,7 @@
zh-Hant = 它可讓您記錄特定期間所行經的路徑,並在地圖上看到該路徑。請注意:啟用此項功能會增加電池使用量。在時間間隔過期後,會從地圖中自動移除行進路線。
[placepage_distance]
- tags = ios
+ tags = android,ios
en = Distance
af = Afstand
ar = المسافة
diff --git a/data/styles/clear/style-clear/style.mapcss b/data/styles/clear/style-clear/style.mapcss
index 338e3c114a..b4ac9186ea 100644
--- a/data/styles/clear/style-clear/style.mapcss
+++ b/data/styles/clear/style-clear/style.mapcss
@@ -36,6 +36,8 @@ colors
RoutePedestrian-opacity: 0.8;
RouteBicycle-color: #9C27B0;
RouteBicycle-opacity: 0.8;
+ RouteRuler-color: #66347F;
+ RouteRuler-opacity: 0.9;
RoutePreview-color: #000000;
RoutePreview-opacity: 0.3;
RouteMaskCar-color: #000000;
diff --git a/data/styles/clear/style-night/style.mapcss b/data/styles/clear/style-night/style.mapcss
index dc1da1d58e..a66b39e474 100644
--- a/data/styles/clear/style-night/style.mapcss
+++ b/data/styles/clear/style-night/style.mapcss
@@ -36,6 +36,8 @@ colors
RoutePedestrian-opacity: 0.7;
RouteBicycle-color: #FF4B8C;
RouteBicycle-opacity: 0.7;
+ RouteRuler-color: #924ab5;
+ RouteRuler-opacity: 0.7;
RoutePreview-color: #FFFFFF;
RoutePreview-opacity: 0.3;
RouteMaskCar-color: #000000;
diff --git a/data/styles/vehicle/style-clear/style.mapcss b/data/styles/vehicle/style-clear/style.mapcss
index 1c7bc14404..1ea44c0a29 100644
--- a/data/styles/vehicle/style-clear/style.mapcss
+++ b/data/styles/vehicle/style-clear/style.mapcss
@@ -36,6 +36,8 @@ colors
RoutePedestrian-opacity: 0.8;
RouteBicycle-color: #9C27B0;
RouteBicycle-opacity: 0.8;
+ RouteRuler-color: #1D339E;
+ RouteRuler-opacity: 0.8;
RoutePreview-color: #000000;
RoutePreview-opacity: 0.3;
RouteMaskCar-color: #000000;
diff --git a/data/styles/vehicle/style-night/style.mapcss b/data/styles/vehicle/style-night/style.mapcss
index fd3fa97c52..15f4579130 100644
--- a/data/styles/vehicle/style-night/style.mapcss
+++ b/data/styles/vehicle/style-night/style.mapcss
@@ -36,6 +36,8 @@ colors
RoutePedestrian-opacity: 0.7;
RouteBicycle-color: #FF4B8C;
RouteBicycle-opacity: 0.7;
+ RouteRuler-color: #FFB94B;
+ RouteRuler-opacity: 0.7;
RoutePreview-color: #FFFFFF;
RoutePreview-opacity: 0.3;
RouteMaskCar-color: #000000;
diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp
index 9de12aaf60..a29bc30b03 100755
--- a/drape_frontend/frontend_renderer.cpp
+++ b/drape_frontend/frontend_renderer.cpp
@@ -1433,7 +1433,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView, bool activeFram
Render2dLayer(modelView);
RenderUserMarksLayer(modelView, DepthLayer::UserLineLayer);
- if (m_buildingsFramebuffer->IsSupported())
+ if (m_buildingsFramebuffer->IsSupported() && !m_routeRenderer->IsRulerRoute())
{
RenderTrafficLayer(modelView);
if (!HasTransitRouteData())
diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp
index 86cd564b66..8b7d1ad3aa 100644
--- a/drape_frontend/route_renderer.cpp
+++ b/drape_frontend/route_renderer.cpp
@@ -17,6 +17,7 @@ std::string const kRouteColor = "Route";
std::string const kRouteOutlineColor = "RouteOutline";
std::string const kRoutePedestrian = "RoutePedestrian";
std::string const kRouteBicycle = "RouteBicycle";
+std::string const kRouteRuler = "RouteRuler";
std::string const kRoutePreview = "RoutePreview";
std::string const kRouteMaskCar = "RouteMaskCar";
std::string const kRouteFirstSegmentArrowsMaskCar = "RouteFirstSegmentArrowsMaskCar";
@@ -797,10 +798,18 @@ void RouteRenderer::SetSubrouteVisibility(dp::DrapeID id, bool isVisible)
bool RouteRenderer::HasTransitData() const
{
for (auto const & subroute : m_subroutes)
- {
if (subroute.m_subroute->m_routeType == RouteType::Transit)
return true;
- }
+
+ return false;
+}
+
+bool RouteRenderer::IsRulerRoute() const
+{
+ for (auto const & subroute : m_subroutes)
+ if (subroute.m_subroute->m_routeType == RouteType::Ruler)
+ return true;
+
return false;
}
diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp
index 5a1b2ab7ce..3bd4d0d668 100644
--- a/drape_frontend/route_renderer.hpp
+++ b/drape_frontend/route_renderer.hpp
@@ -24,6 +24,7 @@ extern std::string const kRouteColor;
extern std::string const kRouteOutlineColor;
extern std::string const kRoutePedestrian;
extern std::string const kRouteBicycle;
+extern std::string const kRouteRuler;
extern std::string const kTransitStopInnerMarkerColor;
class RouteRenderer final
@@ -98,6 +99,7 @@ public:
void SetSubrouteVisibility(dp::DrapeID id, bool isVisible);
bool HasTransitData() const;
+ bool IsRulerRoute() const;
bool HasData() const;
bool HasPreviewData() const;
diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp
index 76a4efb8e6..0380d5441d 100644
--- a/drape_frontend/route_shape.hpp
+++ b/drape_frontend/route_shape.hpp
@@ -46,7 +46,8 @@ enum class RouteType : uint8_t
Pedestrian,
Bicycle,
Taxi,
- Transit
+ Transit,
+ Ruler
};
struct RoutePattern
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.h b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.h
index bbc1346f52..76c35e3290 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.h
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.h
@@ -1,4 +1,5 @@
#import "MWMNavigationDashboardManager.h"
+#import "MWMRoutePoint.h"
#import "MWMRouterType.h"
namespace routing {
@@ -9,7 +10,7 @@ struct TransitRouteInfo;
@interface MWMNavigationDashboardManager (Entity)
-- (void)updateFollowingInfo:(routing::FollowingInfo const &)info type:(MWMRouterType)type;
+- (void)updateFollowingInfo:(routing::FollowingInfo const &)info routePoints:(NSArray *)points type:(MWMRouterType)type;
- (void)updateTransitInfo:(TransitRouteInfo const &)info;
@end
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.mm b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.mm
index 419434c207..19c58e5584 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.mm
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager+Entity.mm
@@ -6,6 +6,7 @@
#import "SwiftBridge.h"
#import
+#import
#include "routing/following_info.hpp"
#include "routing/turns.hpp"
@@ -69,10 +70,13 @@ UIImage *image(routing::turns::PedestrianDirection t) {
}
NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *distanceUnits,
- NSDictionary *primaryAttributes, NSDictionary *secondaryAttributes, BOOL isWalk) {
- NSString *eta = [NSDateComponentsFormatter etaStringFrom:time];
- auto result = [[NSMutableAttributedString alloc] initWithString:eta attributes:primaryAttributes];
- [result appendAttributedString:MWMNavigationDashboardEntity.estimateDot];
+ NSDictionary *primaryAttributes, NSDictionary *secondaryAttributes, BOOL isWalk, BOOL showEta) {
+ auto result = [[NSMutableAttributedString alloc] initWithString:@""];
+ if (showEta) {
+ NSString *eta = [NSDateComponentsFormatter etaStringFrom:time];
+ [result appendAttributedString:[[NSMutableAttributedString alloc] initWithString:eta attributes:primaryAttributes]];
+ [result appendAttributedString:MWMNavigationDashboardEntity.estimateDot];
+ }
if (isWalk) {
UIFont *font = primaryAttributes[NSFontAttributeName];
@@ -95,6 +99,33 @@ NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *
return result;
}
+
+NSArray *buildRouteTransitSteps(NSArray *points) {
+ // Generate step info in format: (Segment 1 distance) (1) (Segment 2 distance) (2) ... (n-1) (Segment N distance).
+ NSMutableArray *steps = [NSMutableArray arrayWithCapacity:[points count] * 2 - 1];
+ auto const numPoints = [points count];
+ for (int i = 0; i < numPoints - 1; i++) {
+ MWMRoutePoint* segmentStart = points[i];
+ MWMRoutePoint* segmentEnd = points[i + 1];
+ auto const distance = platform::Distance::CreateFormatted(
+ ms::DistanceOnEarth(segmentStart.latitude, segmentStart.longitude, segmentEnd.latitude, segmentEnd.longitude));
+
+ MWMRouterTransitStepInfo* segmentInfo = [[MWMRouterTransitStepInfo alloc] init];
+ segmentInfo.type = MWMRouterTransitTypeRuler;
+ segmentInfo.distance = @(distance.GetDistanceString().c_str());
+ segmentInfo.distanceUnits = @(distance.GetUnitsString().c_str());
+ steps[i * 2] = segmentInfo;
+
+ if (i < numPoints - 2) {
+ MWMRouterTransitStepInfo* stopInfo = [[MWMRouterTransitStepInfo alloc] init];
+ stopInfo.type = MWMRouterTransitTypeIntermediatePoint;
+ stopInfo.intermediateIndex = i;
+ steps[i * 2 + 1] = stopInfo;
+ }
+ }
+
+ return steps;
+}
} // namespace
@interface MWMNavigationDashboardEntity ()
@@ -155,7 +186,7 @@ NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *
@implementation MWMNavigationDashboardManager (Entity)
-- (void)updateFollowingInfo:(routing::FollowingInfo const &)info type:(MWMRouterType)type {
+- (void)updateFollowingInfo:(routing::FollowingInfo const &)info routePoints:(NSArray *)points type:(MWMRouterType)type {
if ([MWMRouter isRouteFinished]) {
[MWMRouter stopRouting];
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
@@ -163,6 +194,8 @@ NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *
}
if (auto entity = self.entity) {
+ BOOL const showEta = (type != MWMRouterTypeRuler);
+
entity.isValid = YES;
entity.timeToTarget = info.m_time;
entity.targetDistance = @(info.m_distToTarget.GetDistanceString().c_str());
@@ -174,7 +207,11 @@ NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *
entity.speedLimitMps = info.m_speedLimitMps;
entity.estimate = estimate(entity.timeToTarget, entity.targetDistance, entity.targetUnits,
- self.etaAttributes, self.etaSecondaryAttributes, NO);
+ self.etaAttributes, self.etaSecondaryAttributes, NO, showEta);
+ if (type == MWMRouterTypeRuler && [points count] > 2)
+ entity.transitSteps = buildRouteTransitSteps(points);
+ else
+ entity.transitSteps = [[NSArray alloc] init];
if (type == MWMRouterTypePedestrian) {
entity.turnImage = image(info.m_pedestrianTurn);
@@ -200,8 +237,8 @@ NSAttributedString *estimate(NSTimeInterval time, NSString *distance, NSString *
entity.isValid = YES;
entity.estimate =
estimate(info.m_totalTimeInSec, @(info.m_totalPedestrianDistanceStr.c_str()),
- @(info.m_totalPedestrianUnitsSuffix.c_str()), self.etaAttributes, self.etaSecondaryAttributes, YES);
- NSMutableArray *transitSteps = [@[] mutableCopy];
+ @(info.m_totalPedestrianUnitsSuffix.c_str()), self.etaAttributes, self.etaSecondaryAttributes, YES, YES);
+ NSMutableArray *transitSteps = [NSMutableArray new];
for (auto const &stepInfo : info.m_steps)
[transitSteps addObject:[[MWMRouterTransitStepInfo alloc] initWithStepInfo:stepInfo]];
entity.transitSteps = transitSteps;
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager.mm b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager.mm
index 1b0f753654..95b56068bd 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager.mm
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/MWMNavigationDashboardManager.mm
@@ -82,8 +82,10 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
if (!entity.isValid)
return;
[_navigationInfoView onNavigationInfoUpdated:entity];
- if ([MWMRouter type] == MWMRouterTypePublicTransport)
- [_transportRoutePreviewStatus onNavigationInfoUpdated:entity];
+ bool const isPublicTransport = [MWMRouter type] == MWMRouterTypePublicTransport;
+ bool const isRuler = [MWMRouter type] == MWMRouterTypeRuler;
+ if (isPublicTransport || isRuler)
+ [_transportRoutePreviewStatus onNavigationInfoUpdated:entity prependDistance:isRuler];
else
[_baseRoutePreviewStatus onNavigationInfoUpdated:entity];
[_navigationControlView onNavigationInfoUpdated:entity];
@@ -172,17 +174,24 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
- (void)stateReady {
// TODO: Here assert sometimes fires with _state = MWMNavigationDashboardStateReady, if app was stopped while navigating and then restarted.
- NSAssert(_state == MWMNavigationDashboardStatePlanning, @"Invalid state change (ready)");
+ // Also in ruler mode when new point is added by single tap on the map state MWMNavigationDashboardStatePlanning is skipped and we get _state = MWMNavigationDashboardStateReady.
+ NSAssert(_state == MWMNavigationDashboardStatePlanning || _state == MWMNavigationDashboardStateReady, @"Invalid state change (ready)");
[self setRouteBuilderProgress:100.];
[self updateGoButtonTitle];
- auto const isTransport = ([MWMRouter type] == MWMRouterTypePublicTransport);
- if (isTransport)
+ bool const isTransport = ([MWMRouter type] == MWMRouterTypePublicTransport);
+ bool const isRuler = ([MWMRouter type] == MWMRouterTypeRuler);
+ if (isTransport || isRuler)
[self.transportRoutePreviewStatus showReady];
else
[self.baseRoutePreviewStatus showReady];
- self.goButtonsContainer.hidden = isTransport;
+ self.goButtonsContainer.hidden = isTransport || isRuler;
for (MWMRouteStartButton *button in self.goButtons)
- [button stateReady];
+ {
+ if (isRuler)
+ [button stateHidden];
+ else
+ [button stateReady];
+ }
}
- (void)onRouteStart {
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMRoutePreview.mm b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMRoutePreview.mm
index 1536ed3c0a..b9a12b74d1 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMRoutePreview.mm
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMRoutePreview.mm
@@ -18,7 +18,7 @@ static CGFloat const kDrivingOptionsHeight = 48;
@property(weak, nonatomic) IBOutlet UIView * contentView;
@property(weak, nonatomic) IBOutlet UIView * pedestrian;
@property(weak, nonatomic) IBOutlet UIView * publicTransport;
-@property(weak, nonatomic) IBOutlet UIView * helicopter;
+@property(weak, nonatomic) IBOutlet UIView * ruler;
@property(weak, nonatomic) IBOutlet UIView * vehicle;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint * drivingOptionHeightConstraint;
@property(strong, nonatomic) IBOutlet UIButton * drivingOptionsButton;
@@ -73,6 +73,7 @@ static CGFloat const kDrivingOptionsHeight = 48;
imageName:@"ic_train"
routerType:MWMRouterTypePublicTransport];
[self addProgress:self.bicycle imageName:@"ic_bike" routerType:MWMRouterTypeBicycle];
+ [self addProgress:self.ruler imageName:@"ic_ruler_route" routerType:MWMRouterTypeRuler];
}
- (void)addProgress:(UIView *)parentView
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPadRoutePreview.xib b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPadRoutePreview.xib
index 9870f1e607..e8c16dba64 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPadRoutePreview.xib
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPadRoutePreview.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -109,10 +109,10 @@
-
+
-
+
@@ -139,9 +139,6 @@
-
-
-
@@ -355,7 +352,7 @@
-
+
-
+
@@ -381,7 +378,7 @@
-
+
@@ -459,7 +456,7 @@
-
+
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPhoneRoutePreview.xib b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPhoneRoutePreview.xib
index 282404ff77..47e16d7fae 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPhoneRoutePreview.xib
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/MWMiPhoneRoutePreview.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -22,7 +22,7 @@
-
+
-
+
-
+
-
+
@@ -82,7 +82,7 @@
-
+
@@ -90,7 +90,7 @@
-
+
@@ -98,17 +98,17 @@
-
+
-
-
+
+
-
+
@@ -142,17 +142,6 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -198,9 +187,9 @@
-
+
@@ -209,7 +198,7 @@
-
+
@@ -239,8 +228,8 @@
-
@@ -400,7 +392,7 @@
-
+
@@ -412,8 +404,11 @@
-
-
+
+
+
+
+
@@ -431,7 +426,7 @@
-
+
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift
index b4a7177d5b..07bdf67372 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift
@@ -145,6 +145,7 @@ final class BaseRoutePreviewStatus: SolidTouchView {
result.append(MWMNavigationDashboardEntity.estimateDot())
result.append(elevation)
}
+
resultLabel.attributedText = result
}
}
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportRoutePreviewStatus.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportRoutePreviewStatus.swift
index b731110b99..2fdba999dd 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportRoutePreviewStatus.swift
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportRoutePreviewStatus.swift
@@ -38,10 +38,19 @@ final class TransportRoutePreviewStatus: SolidTouchView {
updateHeight()
}
- @objc func onNavigationInfoUpdated(_ info: MWMNavigationDashboardEntity) {
+ @objc func onNavigationInfoUpdated(_ info: MWMNavigationDashboardEntity, prependDistance: Bool) {
navigationInfo = info
- etaLabel.attributedText = info.estimate
+ if (prependDistance) {
+ let labelText = NSMutableAttributedString(string: NSLocalizedString("placepage_distance", comment: "") + ": ")
+ labelText.append(info.estimate)
+ etaLabel.attributedText = labelText
+ }
+ else {
+ etaLabel.attributedText = info.estimate
+ }
stepsCollectionView.steps = info.transitSteps
+
+ stepsCollectionView.isHidden = info.transitSteps.isEmpty
}
private func updateHeight() {
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.swift
new file mode 100644
index 0000000000..988a697860
--- /dev/null
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.swift
@@ -0,0 +1,36 @@
+final class TransportRuler: TransportTransitCell {
+ enum Config {
+ static let backgroundCornerRadius: CGFloat = 4
+ static var backgroundColor: UIColor { return UIColor.blackOpaque() }
+ static var imageColor: UIColor { return UIColor.blackSecondaryText() }
+ static var labelTextColor: UIColor { return .black }
+ static let labelTextFont = UIFont.bold12()
+ static let labelTrailing: CGFloat = 8
+ }
+
+ @IBOutlet private weak var background: UIView! {
+ didSet {
+ background.layer.cornerRadius = Config.backgroundCornerRadius
+ background.backgroundColor = Config.backgroundColor
+ }
+ }
+
+ @IBOutlet private weak var label: UILabel! {
+ didSet {
+ label.textColor = Config.labelTextColor
+ label.font = Config.labelTextFont
+ }
+ }
+
+ override class func estimatedCellSize(step: MWMRouterTransitStepInfo) -> CGSize {
+ let defaultSize = super.estimatedCellSize(step: step)
+ let labelText = step.distance + " " + step.distanceUnits;
+ let labelSize = labelText.size(width: CGFloat.greatestFiniteMagnitude, font: Config.labelTextFont, maxNumberOfLines: 1)
+ return CGSize(width: labelSize.width + Config.labelTrailing, height: defaultSize.height)
+ }
+
+ override func config(step: MWMRouterTransitStepInfo) {
+ label.isHidden = step.distance.isEmpty && step.distanceUnits.isEmpty
+ label.text = step.distance + " " + step.distanceUnits
+ }
+}
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.xib b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.xib
new file mode 100644
index 0000000000..3e4894b43b
--- /dev/null
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportRuler.xib
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitStepsCollectionView.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitStepsCollectionView.swift
index 587e1e55c4..8d1549ccad 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitStepsCollectionView.swift
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitStepsCollectionView.swift
@@ -20,7 +20,8 @@ final class TransportTransitStepsCollectionView: UICollectionView {
override func awakeFromNib() {
super.awakeFromNib()
dataSource = self
- [TransportTransitIntermediatePoint.self, TransportTransitPedestrian.self, TransportTransitTrain.self].forEach {
+ [TransportTransitIntermediatePoint.self, TransportTransitPedestrian.self,
+ TransportTransitTrain.self, TransportRuler.self].forEach {
register(cellClass: $0)
}
}
@@ -34,6 +35,7 @@ final class TransportTransitStepsCollectionView: UICollectionView {
case .subway: fallthrough
case .lightRail: fallthrough
case .monorail: return TransportTransitTrain.self
+ case .ruler: return TransportRuler.self
}
}
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitTrain.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitTrain.swift
index 53efec52ed..d6f7f5c628 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitTrain.swift
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/TransportTransitSteps/TransportTransitTrain.swift
@@ -42,6 +42,7 @@ final class TransportTransitTrain: TransportTransitCell {
case .subway: image.image = #imageLiteral(resourceName: "ic_20px_route_planning_metro")
case .lightRail: image.image = #imageLiteral(resourceName: "ic_20px_route_planning_lightrail")
case .monorail: image.image = #imageLiteral(resourceName: "ic_20px_route_planning_monorail")
+ case .ruler: fatalError()
}
background.backgroundColor = step.color
diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RouteStartButton.swift b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RouteStartButton.swift
index 03811fa0ce..f37b0534ae 100644
--- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RouteStartButton.swift
+++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RouteStartButton.swift
@@ -15,6 +15,11 @@ final class RouteStartButton: UIButton {
isEnabled = true
}
+ @objc func stateHidden() {
+ isHidden = true
+ isEnabled = true
+ }
+
override func applyTheme() {
super.applyTheme()
setBackgroundImage(UIColor.linkBlue().getImage(), for: .normal)
diff --git a/iphone/Maps/Core/Routing/MWMCoreRouterType.h b/iphone/Maps/Core/Routing/MWMCoreRouterType.h
index 7d9550dd27..487bc89063 100644
--- a/iphone/Maps/Core/Routing/MWMCoreRouterType.h
+++ b/iphone/Maps/Core/Routing/MWMCoreRouterType.h
@@ -10,6 +10,7 @@ static inline routing::RouterType coreRouterType(MWMRouterType type)
case MWMRouterTypePedestrian: return routing::RouterType::Pedestrian;
case MWMRouterTypePublicTransport: return routing::RouterType::Transit;
case MWMRouterTypeBicycle: return routing::RouterType::Bicycle;
+ case MWMRouterTypeRuler: return routing::RouterType::Ruler;
default:
ASSERT(false, ("Invalid routing type"));
return routing::RouterType::Vehicle;
@@ -24,6 +25,7 @@ static inline MWMRouterType routerType(routing::RouterType type)
case routing::RouterType::Transit: return MWMRouterTypePublicTransport;
case routing::RouterType::Pedestrian: return MWMRouterTypePedestrian;
case routing::RouterType::Bicycle: return MWMRouterTypeBicycle;
+ case routing::RouterType::Ruler: return MWMRouterTypeRuler;
default:
ASSERT(false, ("Invalid routing type"));
return MWMRouterTypeVehicle;
diff --git a/iphone/Maps/Core/Routing/MWMRouter.mm b/iphone/Maps/Core/Routing/MWMRouter.mm
index 90390bd073..264767421e 100644
--- a/iphone/Maps/Core/Routing/MWMRouter.mm
+++ b/iphone/Maps/Core/Routing/MWMRouter.mm
@@ -56,6 +56,7 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
switch ([self type]) {
case MWMRouterTypeVehicle:
case MWMRouterTypePublicTransport:
+ case MWMRouterTypeRuler:
return NO;
case MWMRouterTypePedestrian:
case MWMRouterTypeBicycle:
@@ -350,7 +351,7 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
if ([MWMRouter type] == MWMRouterTypePublicTransport)
[navManager updateTransitInfo:rm.GetTransitRouteInfo()];
else
- [navManager updateFollowingInfo:info type:[MWMRouter type]];
+ [navManager updateFollowingInfo:info routePoints:[MWMRouter points] type:[MWMRouter type]];
}
+ (void)routeAltitudeImageForSize:(CGSize)size completion:(MWMImageHeightBlock)block {
diff --git a/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.h b/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.h
index 80ae7f5d43..bf7acaa324 100644
--- a/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.h
+++ b/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.h
@@ -2,11 +2,11 @@
@interface MWMRouterTransitStepInfo : NSObject
-@property(nonatomic, readonly) MWMRouterTransitType type;
-@property(copy, nonatomic, readonly) NSString * distance;
-@property(copy, nonatomic, readonly) NSString * distanceUnits;
-@property(copy, nonatomic, readonly) NSString * number;
-@property(nonatomic, readonly) UIColor * color;
-@property(nonatomic, readonly) NSInteger intermediateIndex;
+@property(nonatomic, readwrite) MWMRouterTransitType type;
+@property(copy, nonatomic, readwrite) NSString * distance;
+@property(copy, nonatomic, readwrite) NSString * distanceUnits;
+@property(copy, nonatomic, readwrite) NSString * number;
+@property(nonatomic, readwrite) UIColor * color;
+@property(nonatomic, readwrite) NSInteger intermediateIndex;
@end
diff --git a/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.mm b/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.mm
index 64842d73be..16348c13a7 100644
--- a/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.mm
+++ b/iphone/Maps/Core/Routing/MWMRouterTransitStepInfo.mm
@@ -34,17 +34,6 @@ UIColor * convertColor(uint32_t colorARGB)
}
} // namespace
-@interface MWMRouterTransitStepInfo ()
-
-@property(nonatomic, readwrite) MWMRouterTransitType type;
-@property(copy, nonatomic, readwrite) NSString * distance;
-@property(copy, nonatomic, readwrite) NSString * distanceUnits;
-@property(copy, nonatomic, readwrite) NSString * number;
-@property(nonatomic, readwrite) UIColor * color;
-@property(nonatomic, readwrite) NSInteger intermediateIndex;
-
-@end
-
@implementation MWMRouterTransitStepInfo
- (instancetype)initWithStepInfo:(TransitStepInfo const &)info
diff --git a/iphone/Maps/Core/Routing/MWMRouterTransitType.h b/iphone/Maps/Core/Routing/MWMRouterTransitType.h
index 66346a029e..b4c6ed0aa0 100644
--- a/iphone/Maps/Core/Routing/MWMRouterTransitType.h
+++ b/iphone/Maps/Core/Routing/MWMRouterTransitType.h
@@ -4,5 +4,6 @@ typedef NS_CLOSED_ENUM(NSUInteger, MWMRouterTransitType) {
MWMRouterTransitTypeSubway,
MWMRouterTransitTypeTrain,
MWMRouterTransitTypeLightRail,
- MWMRouterTransitTypeMonorail
+ MWMRouterTransitTypeMonorail,
+ MWMRouterTransitTypeRuler
};
diff --git a/iphone/Maps/Core/Routing/MWMRouterType.h b/iphone/Maps/Core/Routing/MWMRouterType.h
index 53fedea27a..4771013fd5 100644
--- a/iphone/Maps/Core/Routing/MWMRouterType.h
+++ b/iphone/Maps/Core/Routing/MWMRouterType.h
@@ -3,4 +3,5 @@ typedef NS_ENUM(NSUInteger, MWMRouterType) {
MWMRouterTypePedestrian,
MWMRouterTypePublicTransport,
MWMRouterTypeBicycle,
+ MWMRouterTypeRuler,
};
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/Contents.json b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/Contents.json
new file mode 100644
index 0000000000..e2899cad91
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_ruler_route.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/ic_ruler_route.svg b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/ic_ruler_route.svg
new file mode 100644
index 0000000000..44daafd459
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route.imageset/ic_ruler_route.svg
@@ -0,0 +1,13 @@
+
+
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/Contents.json b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/Contents.json
new file mode 100644
index 0000000000..92f8d1227f
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_ruler_route_highlighted.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/ic_ruler_route_highlighted.svg b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/ic_ruler_route_highlighted.svg
new file mode 100644
index 0000000000..c3aef60549
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_highlighted.imageset/ic_ruler_route_highlighted.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/Contents.json b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/Contents.json
new file mode 100644
index 0000000000..af96255d3f
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "ic_ruler_route_selected.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/ic_ruler_route_selected.svg b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/ic_ruler_route_selected.svg
new file mode 100644
index 0000000000..28e1a96a1b
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/NavigationDashboard/ic_ruler_route_selected.imageset/ic_ruler_route_selected.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj
index 92b7931741..2ce25a9f3c 100644
--- a/iphone/Maps/Maps.xcodeproj/project.pbxproj
+++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj
@@ -184,6 +184,8 @@
3DBD7BE42425015C00ED9FE8 /* ParntersStyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBD7BE32425015C00ED9FE8 /* ParntersStyleSheet.swift */; };
3DEE1AEB21F72CD300054A91 /* MWMPowerManagmentViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3DEE1AEA21F72CD300054A91 /* MWMPowerManagmentViewController.mm */; };
408645FC21495EB1000A4A1D /* categories_cuisines.txt in Resources */ = {isa = PBXBuildFile; fileRef = 408645FB21495EB1000A4A1D /* categories_cuisines.txt */; };
+ 44360A0D2A7D34990016F412 /* TransportRuler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44360A0C2A7D34990016F412 /* TransportRuler.swift */; };
+ 44360A112A7D35440016F412 /* TransportRuler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 44360A102A7D35440016F412 /* TransportRuler.xib */; };
4501B1942077C35A001B9173 /* resources-xxxhdpi_clear in Resources */ = {isa = PBXBuildFile; fileRef = 4501B1922077C35A001B9173 /* resources-xxxhdpi_clear */; };
4501B1952077C35A001B9173 /* resources-xxxhdpi_dark in Resources */ = {isa = PBXBuildFile; fileRef = 4501B1932077C35A001B9173 /* resources-xxxhdpi_dark */; };
4554B6EC1E55F0EF0084017F /* drules_proto_vehicle_clear.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4554B6E81E55F02B0084017F /* drules_proto_vehicle_clear.bin */; };
@@ -1027,6 +1029,8 @@
3DEE1AE921F72CD300054A91 /* MWMPowerManagmentViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMPowerManagmentViewController.h; sourceTree = ""; };
3DEE1AEA21F72CD300054A91 /* MWMPowerManagmentViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPowerManagmentViewController.mm; sourceTree = ""; };
408645FB21495EB1000A4A1D /* categories_cuisines.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = categories_cuisines.txt; path = ../../data/categories_cuisines.txt; sourceTree = ""; };
+ 44360A0C2A7D34990016F412 /* TransportRuler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransportRuler.swift; sourceTree = ""; };
+ 44360A102A7D35440016F412 /* TransportRuler.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TransportRuler.xib; sourceTree = ""; };
4501B1922077C35A001B9173 /* resources-xxxhdpi_clear */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-xxxhdpi_clear"; path = "../../data/resources-xxxhdpi_clear"; sourceTree = ""; };
4501B1932077C35A001B9173 /* resources-xxxhdpi_dark */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-xxxhdpi_dark"; path = "../../data/resources-xxxhdpi_dark"; sourceTree = ""; };
451950391B7A3E070085DA05 /* patterns.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = patterns.txt; path = ../../data/patterns.txt; sourceTree = ""; };
@@ -2341,6 +2345,8 @@
34AB65F61FC5AA320078E451 /* TransportTransitStepsCollectionView.swift */,
34AB65F31FC5AA320078E451 /* TransportTransitTrain.swift */,
34AB65F71FC5AA320078E451 /* TransportTransitTrain.xib */,
+ 44360A0C2A7D34990016F412 /* TransportRuler.swift */,
+ 44360A102A7D35440016F412 /* TransportRuler.xib */,
);
path = TransportTransitSteps;
sourceTree = "";
@@ -3854,6 +3860,7 @@
6741A9551BF340DE002C974C /* resources-xxhdpi_dark in Resources */,
340E1EF51E2F614400CE49BF /* SearchFilters.storyboard in Resources */,
340E1EF81E2F614400CE49BF /* Settings.storyboard in Resources */,
+ 44360A112A7D35440016F412 /* TransportRuler.xib in Resources */,
6741A9421BF340DE002C974C /* sound-strings in Resources */,
F69018BD1E9F7CB600B3C10B /* MWMAutoupdateController.xib in Resources */,
6741A97D1BF340DE002C974C /* synonyms.txt in Resources */,
@@ -3988,6 +3995,7 @@
47E3C72D2111E6A2008B3B27 /* FadeTransitioning.swift in Sources */,
34845DAF1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift in Sources */,
993DF0B523F6B2EF00AC231A /* PlacePageElevationLayout.swift in Sources */,
+ 44360A0D2A7D34990016F412 /* TransportRuler.swift in Sources */,
CD6E8677226774C700D1EDF7 /* CPConstants.swift in Sources */,
99A906DE23F6F7030005872B /* PlacePageBookmarkViewController.swift in Sources */,
F6791B141C43DF0B007A8A6E /* MWMStartButton.m in Sources */,
diff --git a/map/framework.cpp b/map/framework.cpp
index 4fb8133c81..b223fbe554 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -2043,6 +2043,32 @@ void Framework::DeactivateHotelSearchMark()
void Framework::OnTapEvent(place_page::BuildInfo const & buildInfo)
{
auto placePageInfo = BuildPlacePageInfo(buildInfo);
+ bool isRoutePoint = placePageInfo.has_value() && placePageInfo->IsRoutePoint();
+
+ if (m_routingManager.IsRoutingActive()
+ && m_routingManager.GetCurrentRouterType() == routing::RouterType::Ruler
+ && !buildInfo.m_isLongTap
+ && !isRoutePoint)
+ {
+ DeactivateMapSelection(true /* notifyUI */);
+
+ // Continue route to the point
+ RouteMarkData data;
+ data.m_title = placePageInfo ? placePageInfo->GetTitle() : std::string();
+ data.m_subTitle = std::string();
+ data.m_pointType = RouteMarkType::Finish;
+ data.m_intermediateIndex = m_routingManager.GetRoutePointsCount();
+ data.m_isMyPosition = false;
+ data.m_position = buildInfo.m_mercator;
+
+ m_routingManager.ContinueRouteToPoint(std::move(data));
+
+ // Refresh route
+ m_routingManager.RemoveRoute(false /* deactivateFollowing */);
+ m_routingManager.BuildRoute();
+
+ return;
+ }
if (placePageInfo)
{
diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp
index fd1fd4f467..82c5c5345b 100644
--- a/map/routing_manager.cpp
+++ b/map/routing_manager.cpp
@@ -9,6 +9,7 @@
#include "routing/route.hpp"
#include "routing/routing_callbacks.hpp"
#include "routing/routing_helpers.hpp"
+#include "routing/ruler_router.hpp"
#include "routing/speed_camera.hpp"
#include "storage/country_info_getter.hpp"
@@ -200,6 +201,7 @@ VehicleType GetVehicleType(RouterType routerType)
case RouterType::Bicycle: return VehicleType::Bicycle;
case RouterType::Vehicle: return VehicleType::Car;
case RouterType::Transit: return VehicleType::Transit;
+ case RouterType::Ruler: return VehicleType::Transit;
case RouterType::Count: CHECK(false, ("Invalid type", routerType)); return VehicleType::Count;
}
UNREACHABLE();
@@ -219,7 +221,7 @@ RoadWarningMarkType GetRoadType(RoutingOptions::Road road)
}
drape_ptr CreateDrapeSubroute(vector const & segments, m2::PointD const & startPt,
- double baseDistance, double baseDepth, bool isTransit)
+ double baseDistance, double baseDepth, routing::RouterType routerType)
{
auto subroute = make_unique_dp();
subroute->m_baseDistance = baseDistance;
@@ -227,7 +229,7 @@ drape_ptr CreateDrapeSubroute(vector const & segment
auto constexpr kBias = 1.0;
- if (isTransit)
+ if (routerType == RouterType::Transit)
{
subroute->m_headFakeDistance = -kBias;
subroute->m_tailFakeDistance = kBias;
@@ -247,6 +249,15 @@ drape_ptr CreateDrapeSubroute(vector const & segment
return nullptr;
}
+ if (routerType == RouterType::Ruler)
+ {
+ auto const subrouteLen = segments.back().GetDistFromBeginningMerc() - baseDistance;
+ subroute->m_headFakeDistance = -kBias;
+ subroute->m_tailFakeDistance = subrouteLen + kBias;
+ subroute->m_polyline = m2::PolylineD(std::move(points));
+ return subroute;
+ }
+
// We support visualization of fake edges only in the head and in the tail of subroute.
auto constexpr kInvalidId = std::numeric_limits::max();
auto firstReal = kInvalidId;
@@ -292,7 +303,7 @@ drape_ptr CreateDrapeSubroute(vector const & segment
subroute->m_tailFakeDistance = tailLen;
}
- subroute->m_polyline = m2::PolylineD(points);
+ subroute->m_polyline = m2::PolylineD(std::move(points));
return subroute;
}
} // namespace
@@ -401,7 +412,7 @@ void RoutingManager::OnBuildRouteReady(Route const & route, RouterResultCode cod
// Validate route (in case of bicycle routing it can be invalid).
ASSERT(route.IsValid(), ());
- if (route.IsValid())
+ if (route.IsValid() && m_currentRouterType != routing::RouterType::Ruler)
{
m2::RectD routeRect = route.GetPoly().GetLimitRect();
routeRect.Scale(kRouteScaleMultiplier);
@@ -479,7 +490,8 @@ RouterType RoutingManager::GetLastUsedRouter() const
{
case RouterType::Pedestrian:
case RouterType::Bicycle:
- case RouterType::Transit: return routerType;
+ case RouterType::Transit:
+ case RouterType::Ruler: return routerType;
default: return RouterType::Vehicle;
}
}
@@ -517,7 +529,11 @@ void RoutingManager::SetRouterImpl(RouterType type)
auto regionsFinder =
make_unique(countryFileGetter, localFileChecker, numMwmIds, dataSource);
- auto router = make_unique(vehicleType, m_loadAltitudes, m_callbacks.m_countryParentNameGetterFn,
+ std::unique_ptr router;
+ if (type == RouterType::Ruler)
+ router = make_unique();
+ else
+ router = make_unique(vehicleType, m_loadAltitudes, m_callbacks.m_countryParentNameGetterFn,
countryFileGetter, getMwmRectByName, numMwmIds,
MakeNumMwmTree(*numMwmIds, m_callbacks.m_countryInfoGetter()),
m_routingSession, dataSource);
@@ -668,7 +684,8 @@ bool RoutingManager::InsertRoute(Route const & route)
auto const startPt = route.GetSubrouteAttrs(subrouteIndex).GetStart().GetPoint();
auto subroute = CreateDrapeSubroute(segments, startPt, distance,
- static_cast(subroutesCount - subrouteIndex - 1), isTransitRoute);
+ static_cast(subroutesCount - subrouteIndex - 1),
+ m_currentRouterType);
if (!subroute)
continue;
distance = segments.back().GetDistFromBeginningMerc();
@@ -702,6 +719,12 @@ bool RoutingManager::InsertRoute(Route const & route)
FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, subroute->m_turns);
break;
}
+ case RouterType::Ruler:
+ {
+ subroute->m_routeType = df::RouteType::Ruler;
+ subroute->AddStyle(df::SubrouteStyle(df::kRouteRuler, df::RoutePattern(16.0, 2.0)));
+ break;
+ }
default: CHECK(false, ("Unknown router type"));
}
@@ -838,6 +861,30 @@ void RoutingManager::AddRoutePoint(RouteMarkData && markData)
ReorderIntermediatePoints();
}
+void RoutingManager::ContinueRouteToPoint(RouteMarkData && markData)
+{
+ ASSERT(m_bmManager != nullptr, ());
+ ASSERT(markData.m_pointType == RouteMarkType::Finish, ("New route point should have type RouteMarkType::Finish"));
+ RoutePointsLayout routePoints(*m_bmManager);
+
+ // Finish point is now Intermediate point
+ RouteMarkPoint * finishMarkData = routePoints.GetRoutePointForEdit(RouteMarkType::Finish);
+ finishMarkData->SetRoutePointType(RouteMarkType::Intermediate);
+ finishMarkData->SetIntermediateIndex(routePoints.GetRoutePointsCount()-1);
+
+ if (markData.m_isMyPosition)
+ {
+ RouteMarkPoint const * mark = routePoints.GetMyPositionPoint();
+ if (mark)
+ routePoints.RemoveRoutePoint(mark->GetRoutePointType(), mark->GetIntermediateIndex());
+ }
+
+ markData.m_intermediateIndex = routePoints.GetRoutePointsCount();
+ markData.m_isVisible = !markData.m_isMyPosition;
+ routePoints.AddRoutePoint(move(markData));
+ ReorderIntermediatePoints();
+}
+
void RoutingManager::RemoveRoutePoint(RouteMarkType type, size_t intermediateIndex)
{
ASSERT(m_bmManager != nullptr, ());
diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp
index 6995010828..2b42c5781d 100644
--- a/map/routing_manager.hpp
+++ b/map/routing_manager.hpp
@@ -226,6 +226,7 @@ public:
void GenerateNotifications(std::vector & notifications);
void AddRoutePoint(RouteMarkData && markData);
+ void ContinueRouteToPoint(RouteMarkData && markData);
std::vector GetRoutePoints() const;
size_t GetRoutePointsCount() const;
void RemoveRoutePoint(RouteMarkType type, size_t intermediateIndex = 0);
diff --git a/qt/routing_settings_dialog.cpp b/qt/routing_settings_dialog.cpp
index a7f7ab8646..7c014d61f1 100644
--- a/qt/routing_settings_dialog.cpp
+++ b/qt/routing_settings_dialog.cpp
@@ -131,6 +131,7 @@ RoutingSettings::RoutingSettings(QWidget * parent, Framework & framework)
m_routerType->insertItem(static_cast(RouterType::Pedestrian), "pedestrian");
m_routerType->insertItem(static_cast(RouterType::Bicycle), "bicycle");
m_routerType->insertItem(static_cast(RouterType::Transit), "transit");
+ m_routerType->insertItem(static_cast(RouterType::Ruler), "ruler");
form->addRow("Choose router:", m_routerType);
m_showTurnsCheckbox = new QCheckBox({}, frame);
diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt
index 0dc40f83c8..6911fc0383 100644
--- a/routing/CMakeLists.txt
+++ b/routing/CMakeLists.txt
@@ -139,6 +139,8 @@ set(SRC
routing_session.hpp
routing_settings.cpp
routing_settings.hpp
+ ruler_router.cpp
+ ruler_router.hpp
segment.cpp
segment.hpp
segmented_route.cpp
diff --git a/routing/async_router.cpp b/routing/async_router.cpp
index 1b9679d2c8..161fc51028 100644
--- a/routing/async_router.cpp
+++ b/routing/async_router.cpp
@@ -371,17 +371,21 @@ void AsyncRouter::CalculateRoute()
[delegateProxy, route, code]() { delegateProxy->OnReady(route, code); });
}
- bool const needAbsentRegions = (code != RouterResultCode::Cancelled);
+ bool const needAbsentRegions = (code != RouterResultCode::Cancelled &&
+ route->GetRouterId() != "ruler-router");
std::set absent;
- if (absentRegionsFinder && needAbsentRegions)
- absentRegionsFinder->GetAbsentRegions(absent);
-
- absent.insert(route->GetAbsentCountries().cbegin(), route->GetAbsentCountries().cend());
- if (!absent.empty())
+ if (needAbsentRegions)
{
- code = RouterResultCode::NeedMoreMaps;
- LOG(LDEBUG, ("Absent regions:", absent));
+ if (absentRegionsFinder)
+ absentRegionsFinder->GetAbsentRegions(absent);
+
+ absent.insert(route->GetAbsentCountries().cbegin(), route->GetAbsentCountries().cend());
+ if (!absent.empty())
+ {
+ code = RouterResultCode::NeedMoreMaps;
+ LOG(LDEBUG, ("Absent regions:", absent));
+ }
}
elapsedSec = timer.ElapsedSeconds(); // routing time + absents fetch time
diff --git a/routing/router.cpp b/routing/router.cpp
index f05e70ca60..fb76876bf7 100644
--- a/routing/router.cpp
+++ b/routing/router.cpp
@@ -10,6 +10,7 @@ std::string ToString(RouterType type)
case RouterType::Pedestrian: return "pedestrian";
case RouterType::Bicycle: return "bicycle";
case RouterType::Transit: return "transit";
+ case RouterType::Ruler: return "ruler";
case RouterType::Count: return "count";
}
ASSERT(false, ());
@@ -26,6 +27,8 @@ RouterType FromString(std::string const & str)
return RouterType::Bicycle;
if (str == "transit")
return RouterType::Transit;
+ if (str == "ruler" || str == "helicopter") // TODO: "helicopter" is left for Beta version compatibility. Remove after ruler release.
+ return RouterType::Ruler;
ASSERT(false, ("Incorrect routing string:", str));
return RouterType::Vehicle;
diff --git a/routing/router.hpp b/routing/router.hpp
index 1d5220f4f6..e6c0b87750 100644
--- a/routing/router.hpp
+++ b/routing/router.hpp
@@ -43,6 +43,7 @@ enum class RouterType
Pedestrian, /// For A star pedestrian routing.
Bicycle, /// For A star bicycle routing.
Transit, /// For A star pedestrian + transit routing.
+ Ruler, /// For simple straight line router.
Count /// Number of router types.
};
diff --git a/routing/ruler_router.cpp b/routing/ruler_router.cpp
new file mode 100644
index 0000000000..886a837814
--- /dev/null
+++ b/routing/ruler_router.cpp
@@ -0,0 +1,131 @@
+#include "routing/ruler_router.hpp"
+#include "routing/route.hpp"
+#include "routing/routing_helpers.hpp"
+
+namespace routing
+{
+using namespace std;
+
+void RulerRouter::ClearState()
+{
+}
+
+void RulerRouter::SetGuides(GuidesTracks && guides) { /*m_guides = GuidesConnections(guides);*/ }
+
+
+/* Ruler router doesn't read roads graph and uses only checkpoints to build a route.
+
+ 1-----------2
+ / \
+ / \
+ / F
+ S
+
+ For example we need to build route from start (S) to finish (F) with intermediate
+ points (1) and (2).
+ Target route should have parameters:
+
+ m_geometry = [S, S, 1, 1, 2, 2, F, F]
+ m_routeSegments = [S, 1, 1, 2, 2, F, F]
+ m_subroutes =
+ +-------+--------+-----------------+---------------+
+ | start | finish | beginSegmentIdx | endSegmentIdx |
+ +-------+--------+-----------------+---------------+
+ | S | 1 | 0 | 2 |
+ | 1 | 1 | 1 | 2 |
+ | 1 | 2 | 2 | 4 |
+ | 2 | 2 | 3 | 4 |
+ | 2 | F | 4 | 6 |
+ | 2 | F | 4 | 6 |
+ +-------+--------+-----------------+---------------+
+
+ Constraints:
+ * m_geometry.size() == 2 * checkpoints.size()
+ * m_routeSegments.size() == m_geometry.size()-1
+ * m_subroutes.size() == m_routeSegments.size()-1
+
+ */
+RouterResultCode RulerRouter::CalculateRoute(Checkpoints const & checkpoints,
+ m2::PointD const & startDirection,
+ bool adjustToPrevRoute,
+ RouterDelegate const & delegate, Route & route)
+{
+ vector const & points = checkpoints.GetPoints();
+ size_t const count = points.size();
+ ASSERT(count > 0, ());
+
+ vector routeSegments;
+ routeSegments.reserve(count * 2 - 1);
+ vector times;
+ times.reserve(count * 2 - 1);
+
+ Segment const segment(kFakeNumMwmId, 0, 0, false);
+
+ auto const ToPointWA = [](m2::PointD const & p)
+ {
+ return geometry::PointWithAltitude(p, 0 /* altitude */);
+ };
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ turns::TurnItem turn(i, turns::PedestrianDirection::None);
+ geometry::PointWithAltitude const junction = ToPointWA(points[i]);
+ RouteSegment::RoadNameInfo const roadNameInfo;
+
+ auto routeSegment = RouteSegment(segment, turn, junction, roadNameInfo);
+ routeSegments.emplace_back(segment, turn, junction, roadNameInfo);
+ times.push_back(0);
+
+ if (i == count - 1)
+ turn = turns::TurnItem(i + 1, turns::PedestrianDirection::ReachedYourDestination);
+ else if (i == 0)
+ continue;
+
+ routeSegments.emplace_back(segment, turn, junction, roadNameInfo);
+ times.push_back(0);
+ }
+
+ FillSegmentInfo(times, routeSegments);
+ route.SetRouteSegments(std::move(routeSegments));
+
+ vector subroutes;
+ for(size_t i = 1; i < count; ++i)
+ {
+ if (i < count-1)
+ {
+ // Note: endSegmentIdx in decreased in Route::IsSubroutePassed(size_t) method. See routing/route.cpp:448
+ subroutes.emplace_back(ToPointWA(points[i-1]), ToPointWA(points[i]), i*2-2, i*2);
+ subroutes.emplace_back(ToPointWA(points[i-1]), ToPointWA(points[i]), i*2-1, i*2);
+ }
+ else
+ {
+ // Duplicate last subroute attrs.
+ subroutes.emplace_back(ToPointWA(points[i-1]), ToPointWA(points[i+1]), i*2-2, i*2);
+ subroutes.emplace_back(ToPointWA(points[i-1]), ToPointWA(points[i+1]), i*2-2, i*2);
+ }
+ }
+
+ route.SetCurrentSubrouteIdx(checkpoints.GetPassedIdx());
+ route.SetSubroteAttrs(std::move(subroutes));
+
+ vector routeGeometry;
+ for (auto p: points)
+ {
+ routeGeometry.push_back(p);
+ routeGeometry.push_back(p);
+ }
+
+ route.SetGeometry(routeGeometry.begin(), routeGeometry.end());
+
+ return RouterResultCode::NoError;
+}
+
+bool RulerRouter::FindClosestProjectionToRoad(m2::PointD const & point,
+ m2::PointD const & direction, double radius,
+ EdgeProj & proj)
+{
+ // Ruler router has no connection to road graph.
+ return false;
+}
+
+} // namespace routing
diff --git a/routing/ruler_router.hpp b/routing/ruler_router.hpp
new file mode 100644
index 0000000000..5355b2d510
--- /dev/null
+++ b/routing/ruler_router.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "routing/router.hpp"
+#include
+
+namespace routing
+{
+
+class RulerRouter : public IRouter
+{
+ std::string GetName() const override { return {"ruler-router"}; }
+ void ClearState() override;
+ void SetGuides(GuidesTracks && guides) override;
+ RouterResultCode CalculateRoute(Checkpoints const & checkpoints,
+ m2::PointD const & startDirection, bool adjustToPrevRoute,
+ RouterDelegate const & delegate, Route & route) override;
+ bool FindClosestProjectionToRoad(m2::PointD const & point, m2::PointD const & direction,
+ double radius, EdgeProj & proj) override;
+
+ // Do we need guides in this router?
+ //GuidesConnections m_guides;
+};
+} // namespace routing
diff --git a/xcode/routing/routing.xcodeproj/project.pbxproj b/xcode/routing/routing.xcodeproj/project.pbxproj
index f1812c4916..5ae9cdb64f 100644
--- a/xcode/routing/routing.xcodeproj/project.pbxproj
+++ b/xcode/routing/routing.xcodeproj/project.pbxproj
@@ -79,6 +79,8 @@
4433A8EB23993BD700E1350B /* leaps_graph.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 4433A8EA23993BD700E1350B /* leaps_graph.hpp */; };
4443DC3722789793000C8E32 /* leaps_postprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4443DC3522789793000C8E32 /* leaps_postprocessor.cpp */; };
4443DC3822789793000C8E32 /* leaps_postprocessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 4443DC3622789793000C8E32 /* leaps_postprocessor.hpp */; };
+ 44642D2D29CDA44700F8813A /* ruler_router.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 44642D2B29CDA44600F8813A /* ruler_router.hpp */; };
+ 44642D2E29CDA44700F8813A /* ruler_router.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44642D2C29CDA44700F8813A /* ruler_router.cpp */; };
44A95C71225F6A4F00C22F4F /* astar_graph.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 44A95C6F225F6A4F00C22F4F /* astar_graph.hpp */; };
44A95C72225F6A4F00C22F4F /* astar_progress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44A95C70225F6A4F00C22F4F /* astar_progress.cpp */; };
44AE4A12214FBB8E006321F5 /* speed_camera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44AE4A10214FBB8D006321F5 /* speed_camera.cpp */; };
@@ -363,6 +365,8 @@
4433A8EA23993BD700E1350B /* leaps_graph.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = leaps_graph.hpp; sourceTree = ""; };
4443DC3522789793000C8E32 /* leaps_postprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leaps_postprocessor.cpp; sourceTree = ""; };
4443DC3622789793000C8E32 /* leaps_postprocessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = leaps_postprocessor.hpp; sourceTree = ""; };
+ 44642D2B29CDA44600F8813A /* ruler_router.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ruler_router.hpp; sourceTree = ""; };
+ 44642D2C29CDA44700F8813A /* ruler_router.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ruler_router.cpp; sourceTree = ""; };
448FD3F2228B1BC500180D90 /* bfs_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bfs_tests.cpp; sourceTree = ""; };
44A95C6F225F6A4F00C22F4F /* astar_graph.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = astar_graph.hpp; path = base/astar_graph.hpp; sourceTree = ""; };
44A95C70225F6A4F00C22F4F /* astar_progress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = astar_progress.cpp; sourceTree = ""; };
@@ -685,6 +689,8 @@
675343FA1A3F640D00A0A8C3 /* routing */ = {
isa = PBXGroup;
children = (
+ 44642D2C29CDA44700F8813A /* ruler_router.cpp */,
+ 44642D2B29CDA44600F8813A /* ruler_router.hpp */,
ACAE44A327426EDB0054DD15 /* junction_visitor.cpp */,
D549BEBC25765CFB009131F2 /* absent_regions_finder.cpp */,
D549BEBA25765CFA009131F2 /* absent_regions_finder.hpp */,
@@ -931,6 +937,7 @@
674F9BCD1B0A580E00704FFA /* features_road_graph.hpp in Headers */,
40576F781F7A788B000B593B /* fake_vertex.hpp in Headers */,
670EE5741B664796001E8064 /* pedestrian_directions.hpp in Headers */,
+ 44642D2D29CDA44700F8813A /* ruler_router.hpp in Headers */,
56CBED5522E9CE2600D51AF7 /* position_accumulator.hpp in Headers */,
5694CECB1EBA25F7004576D3 /* road_access_serialization.hpp in Headers */,
0C08AA371DF8324D004195DD /* vehicle_mask.hpp in Headers */,
@@ -1210,6 +1217,7 @@
D5481E4F24BF4F70008FB1D8 /* mwm_hierarchy_handler.cpp in Sources */,
0C5FEC641DDE192A0017688C /* joint.cpp in Sources */,
0C090C871E4E276700D52AFD /* world_graph.cpp in Sources */,
+ 44642D2E29CDA44700F8813A /* ruler_router.cpp in Sources */,
44C56C0B22296498006C2A1D /* routing_options.cpp in Sources */,
D526BA7A241FC5580076E0B0 /* guides_connections.cpp in Sources */,
ACAE44A427426EDB0054DD15 /* junction_visitor.cpp in Sources */,