diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index c2cf95ad1d..567b848d2b 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1274,7 +1274,7 @@ Java_com_mapswithme_maps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) // boolean isPassed, double lat, double lon) static jmethodID const pointConstructor = jni::GetConstructorID(env, pointClazz, "(Ljava/lang/String;Ljava/lang/String;IIZZZDD)V"); - return jni::ToJavaArray(env, pointClazz, points, [&](JNIEnv * env, RouteMarkData const & data) + return jni::ToJavaArray(env, pointClazz, points, [&](JNIEnv * jEnv, RouteMarkData const & data) { jni::TScopedLocalRef const title(env, jni::ToJavaString(env, data.m_title)); jni::TScopedLocalRef const subtitle(env, jni::ToJavaString(env, data.m_subTitle)); @@ -1293,39 +1293,49 @@ Java_com_mapswithme_maps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) JNIEXPORT jobject JNICALL Java_com_mapswithme_maps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) { - auto const info = frm()->GetRoutingManager().GetTransitRouteInfo(); + auto const routeInfo = frm()->GetRoutingManager().GetTransitRouteInfo(); static jclass const transitStepClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/routing/TransitStepInfo"); - // Java signature : TransitStepInfo(@TransitType int type, double distance, double time, - // @Nullable String number, int color) + // Java signature : TransitStepInfo(@TransitType int type, @Nullable String distance, @Nullable String distanceUnits, + // int timeInSec, @Nullable String number, int color, int intermediateIndex) static jmethodID const transitStepConstructor = jni::GetConstructorID(env, transitStepClass, - "(IDDLjava/lang/String;I)V"); + "(ILjava/lang/String;Ljava/lang/String;ILjava/lang/String;II)V"); jni::TScopedLocalRef const steps(env, jni::ToJavaArray(env, transitStepClass, - info.m_steps, - [&](JNIEnv * env, TransitStepInfo const & info) + routeInfo.m_steps, + [&](JNIEnv * jEnv, TransitStepInfo const & stepInfo) { - jni::TScopedLocalRef const number(env, jni::ToJavaString(env, info.m_number)); + jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, stepInfo.m_distanceStr)); + jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, stepInfo.m_distanceUnitsSuffix)); + jni::TScopedLocalRef const number(env, jni::ToJavaString(env, stepInfo.m_number)); return env->NewObject(transitStepClass, transitStepConstructor, - static_cast(info.m_type), - static_cast(info.m_distance), - static_cast(info.m_time), + static_cast(stepInfo.m_type), + distance.get(), + distanceUnits.get(), + static_cast(stepInfo.m_timeInSec), number.get(), - static_cast(info.m_color)); + static_cast(stepInfo.m_colorARGB), + static_cast(stepInfo.m_intermediateIndex)); })); static jclass const transitRouteInfoClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/routing/TransitRouteInfo"); - // Java signature : TransitRouteInfo(double totalDistance, double totalTime, - // double totalPedestrianDistance, double totalPedestrianTime, - // TransitStepInfo[] steps) + // Java signature : TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits, int totalTimeInSec, + // @NonNull String totalPedestrianDistance, @NonNull String totalPedestrianDistanceUnits, + // int totalPedestrianTimeInSec, @NonNull TransitStepInfo[] steps) static jmethodID const transitRouteInfoConstructor = jni::GetConstructorID(env, transitRouteInfoClass, - "(DDDD[Lcom/mapswithme/maps/routing/TransitStepInfo;)V"); - + "(Ljava/lang/String;Ljava/lang/String;I" + "Ljava/lang/String;Ljava/lang/String;I" + "[Lcom/mapswithme/maps/routing/TransitStepInfo;)V"); + jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, routeInfo.m_totalDistanceStr)); + jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, routeInfo.m_totalDistanceUnitsSuffix)); + jni::TScopedLocalRef const distancePedestrian(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianDistanceStr)); + jni::TScopedLocalRef const distancePedestrianUnits(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianUnitsSuffix)); return env->NewObject(transitRouteInfoClass, transitRouteInfoConstructor, - info.m_totalDistance, info.m_totalTime, info.m_totalPedestrianDistance, - info.m_totalPedestrianTime, steps.get()); + distance.get(), distanceUnits.get(), static_cast(routeInfo.m_totalTimeInSec), + distancePedestrian.get(), distancePedestrianUnits.get(), static_cast(routeInfo.m_totalPedestrianTimeInSec), + steps.get()); } JNIEXPORT void JNICALL diff --git a/android/src/com/mapswithme/maps/routing/TransitRouteInfo.java b/android/src/com/mapswithme/maps/routing/TransitRouteInfo.java index 7ba64463c6..32edd6c38e 100644 --- a/android/src/com/mapswithme/maps/routing/TransitRouteInfo.java +++ b/android/src/com/mapswithme/maps/routing/TransitRouteInfo.java @@ -7,21 +7,29 @@ import android.support.annotation.NonNull; */ public class TransitRouteInfo { - public final double mTotalDistance; - public final double mTotalTime; - public final double mTotalPedestrianDistance; - public final double mTotalPedestrianTime; - @NonNull - public final TransitStepInfo[] mSteps; + @NonNull + public final String mTotalDistance; + @NonNull + public final String mTotalDistanceUnits; + public final int mTotalTimeInSec; + @NonNull + public final String mTotalPedestrianDistance; + @NonNull + public final String mTotalPedestrianDistanceUnits; + public final int mTotalPedestrianTimeInSec; + @NonNull + public final TransitStepInfo[] mSteps; - public TransitRouteInfo(double totalDistance, double totalTime, - double totalPedestrianDistance, double totalPedestrianTime, - @NonNull TransitStepInfo[] steps) - { - mTotalDistance = totalDistance; - mTotalTime = totalTime; - mTotalPedestrianDistance = totalPedestrianDistance; - mTotalPedestrianTime = totalPedestrianTime; - mSteps = steps; - } + public TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits, int totalTimeInSec, + @NonNull String totalPedestrianDistance, @NonNull String totalPedestrianDistanceUnits, + int totalPedestrianTimeInSec, @NonNull TransitStepInfo[] steps) + { + mTotalDistance = totalDistance; + mTotalDistanceUnits = totalDistanceUnits; + mTotalTimeInSec = totalTimeInSec; + mTotalPedestrianDistance = totalPedestrianDistance; + mTotalPedestrianDistanceUnits = totalPedestrianDistanceUnits; + mTotalPedestrianTimeInSec = totalPedestrianTimeInSec; + mSteps = steps; + } } diff --git a/android/src/com/mapswithme/maps/routing/TransitStepInfo.java b/android/src/com/mapswithme/maps/routing/TransitStepInfo.java index 0284effe61..f61a1cea7f 100644 --- a/android/src/com/mapswithme/maps/routing/TransitStepInfo.java +++ b/android/src/com/mapswithme/maps/routing/TransitStepInfo.java @@ -12,29 +12,40 @@ import java.lang.annotation.RetentionPolicy; */ public class TransitStepInfo { - private static final int TRANSIT_TYPE_PEDESTRIAN = 0; - private static final int TRANSIT_TYPE_SUBWAY = 1; + private static final int TRANSIT_TYPE_INTERMEDIATE_POINT = 0; + private static final int TRANSIT_TYPE_PEDESTRIAN = 1; + private static final int TRANSIT_TYPE_SUBWAY = 2; + 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; @Retention(RetentionPolicy.SOURCE) - @IntDef({ TRANSIT_TYPE_PEDESTRIAN, TRANSIT_TYPE_SUBWAY }) + @IntDef({ TRANSIT_TYPE_INTERMEDIATE_POINT, TRANSIT_TYPE_PEDESTRIAN, TRANSIT_TYPE_SUBWAY, + TRANSIT_TYPE_TRAIN, TRANSIT_TYPE_LIGHT_RAIL, TRANSIT_TYPE_MONORAIL }) @interface TransitType {} @NonNull private final TransitStepType mType; - private final double mDistance; - private final double mTime; + @Nullable + private final String mDistance; + @Nullable + private final String mDistanceUnits; + private final int mTimeInSec; @Nullable private final String mNumber; private final int mColor; + private final int mIntermediateIndex; - TransitStepInfo(@TransitType int type, double distance, double time, - @Nullable String number, int color) + TransitStepInfo(@TransitType int type, @Nullable String distance, @Nullable String distanceUnits, + int timeInSec, @Nullable String number, int color, int intermediateIndex) { mType = TransitStepType.values()[type]; mDistance = distance; - mTime = time; + mDistanceUnits = distanceUnits; + mTimeInSec = timeInSec; mNumber = number; mColor = color; + mIntermediateIndex = intermediateIndex; } @NonNull @@ -43,14 +54,21 @@ public class TransitStepInfo return mType; } - public double getDistance() + @Nullable + public String getDistance() { return mDistance; } - public double getTime() + @Nullable + public String getDistanceUnits() { - return mTime; + return mDistanceUnits; + } + + public int getTimeInSec() + { + return mTimeInSec; } @Nullable @@ -63,4 +81,9 @@ public class TransitStepInfo { return mColor; } + + public int getIntermediateIndex() + { + return mIntermediateIndex; + } } diff --git a/android/src/com/mapswithme/maps/routing/TransitStepType.java b/android/src/com/mapswithme/maps/routing/TransitStepType.java index 321e255c1a..9bb33cbd45 100644 --- a/android/src/com/mapswithme/maps/routing/TransitStepType.java +++ b/android/src/com/mapswithme/maps/routing/TransitStepType.java @@ -6,8 +6,12 @@ import com.mapswithme.maps.R; public enum TransitStepType { + INTERMEDIATE_POINT(R.drawable.ic_20px_route_planning_walk), PEDESTRIAN(R.drawable.ic_20px_route_planning_walk), - SUBWAY(R.drawable.ic_20px_route_planning_metro); + SUBWAY(R.drawable.ic_20px_route_planning_metro), + TRAIN(R.drawable.ic_20px_route_planning_metro), + LIGHT_RAIL(R.drawable.ic_20px_route_planning_metro), + MONORAIL(R.drawable.ic_20px_route_planning_metro); @DrawableRes private final int mDrawable; diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 6389eb3bfd..2364eefab4 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -207,8 +207,15 @@ uint32_t ColorToARGB(df::ColorConstant const & colorConstant) TransitType GetTransitType(string const & type) { - ASSERT_EQUAL(type, "subway", ()); - return TransitType::Subway; + if (type == "subway") + return TransitType::Subway; + if (type == "light_rail") + return TransitType::LightRail; + if (type == "monorail") + return TransitType::Monorail; + + ASSERT_EQUAL(type, "train", ()); + return TransitType::Train; } void FillTransitStyleForRendering(vector const & segments, TransitReadManager & transitReadManager, @@ -232,14 +239,14 @@ void FillTransitStyleForRendering(vector const & segments, Transit df::SubrouteMarker marker; TransitMarkInfo transitMarkInfo; - double prevDistance = routeInfo.m_totalDistance; - double prevTime = routeInfo.m_totalTime; + double prevDistance = routeInfo.m_totalDistInMeters; + double prevTime = routeInfo.m_totalTimeInSec; bool pendingEntrance = false; for (auto const & s : segments) { - auto const time = s.GetTimeFromBeginningSec() - prevTime; + auto const time = static_cast(ceil(s.GetTimeFromBeginningSec() - prevTime)); auto const distance = s.GetDistFromBeginningMeters() - prevDistance; if (!s.HasTransitInfo()) @@ -381,8 +388,8 @@ void FillTransitStyleForRendering(vector const & segments, Transit prevTime = s.GetTimeFromBeginningSec(); } - routeInfo.m_totalDistance = prevDistance; - routeInfo.m_totalTime = prevTime; + routeInfo.m_totalDistInMeters = prevDistance; + routeInfo.m_totalTimeInSec = static_cast(ceil(prevTime)); if (subroute.m_markers.size() > 1) { @@ -579,13 +586,15 @@ namespace marketing char const * const kRoutingCalculatingRoute = "Routing_CalculatingRoute"; } // namespace marketing -TransitStepInfo::TransitStepInfo(TransitType type, double distance, double time, - std::string const & number, uint32_t color) +TransitStepInfo::TransitStepInfo(TransitType type, double distance, int time, + std::string const & number, uint32_t color, + int intermediateIndex) : m_type(type) - , m_distance(distance) - , m_time(time) + , m_distanceInMeters(distance) + , m_timeInSec(time) , m_number(number) - , m_color(color) + , m_colorARGB(color) + , m_intermediateIndex(intermediateIndex) {} bool TransitStepInfo::IsEqualType(TransitStepInfo const & ts) const @@ -593,8 +602,8 @@ bool TransitStepInfo::IsEqualType(TransitStepInfo const & ts) const if (m_type != ts.m_type) return false; - if (m_type != TransitType::Pedestrian) - return m_number == ts.m_number && m_color == ts.m_color; + if (m_type != TransitType::Pedestrian && m_type != TransitType::IntermediatePoint) + return m_number == ts.m_number && m_colorARGB == ts.m_colorARGB; return true; } @@ -602,8 +611,8 @@ void TransitRouteInfo::AddStep(TransitStepInfo const & step) { if (!m_steps.empty() && m_steps.back().IsEqualType(step)) { - m_steps.back().m_distance += step.m_distance; - m_steps.back().m_time += step.m_time; + m_steps.back().m_distanceInMeters += step.m_distanceInMeters; + m_steps.back().m_timeInSec += step.m_timeInSec; } else { @@ -612,11 +621,24 @@ void TransitRouteInfo::AddStep(TransitStepInfo const & step) if (step.m_type == TransitType::Pedestrian) { - m_totalPedestrianDistance += step.m_distance; - m_totalPedestrianTime += step.m_time; + m_totalPedestrianDistInMeters += step.m_distanceInMeters; + m_totalPedestrianTimeInSec += step.m_timeInSec; } } +void TransitRouteInfo::UpdateDistanceStrings() +{ + if (m_steps.empty()) + return; + for (auto step : m_steps) + { + FormatDistance(step.m_distanceInMeters, step.m_distanceStr, step.m_distanceUnitsSuffix); + } + FormatDistance(m_totalDistInMeters, m_totalDistanceStr, m_totalDistanceUnitsSuffix); + FormatDistance(m_totalPedestrianDistInMeters, m_totalPedestrianDistanceStr, + m_totalPedestrianUnitsSuffix); +} + RoutingManager::RoutingManager(Callbacks && callbacks, Delegate & delegate) : m_callbacks(move(callbacks)) , m_delegate(delegate) @@ -896,18 +918,28 @@ void RoutingManager::InsertRoute(Route const & route) }; vector transitMarks; + if (subrouteIndex > 0) + { + TransitStepInfo step; + step.m_type = TransitType::IntermediatePoint; + step.m_intermediateIndex = static_cast(subrouteIndex - 1); + transitRouteInfo.AddStep(step); + } + FillTransitStyleForRendering(segments, m_transitReadManager, getMwmIdFn, *subroute.get(), transitMarks, transitRouteInfo); + if (subroute->m_polyline.GetSize() < 2) { LOG(LWARNING, ("Invalid transit subroute. Points number =", subroute->m_polyline.GetSize())); continue; } + auto & marksController = m_bmManager->GetUserMarksController(UserMark::Type::TRANSIT); CreateTransitMarks(transitMarks, marksController); marksController.NotifyChanges(); + break; } - break; case RouterType::Pedestrian: subroute->m_routeType = df::RouteType::Pedestrian; subroute->AddStyle(df::SubrouteStyle(df::kRoutePedestrian, df::RoutePattern(4.0, 2.0))); @@ -929,6 +961,7 @@ void RoutingManager::InsertRoute(Route const & route) lock_guard lock(m_drapeSubroutesMutex); m_drapeSubroutes.push_back(subrouteId); + transitRouteInfo.UpdateDistanceStrings(); m_transitRouteInfo = transitRouteInfo; } } diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 0b3bae1619..f8a6b3b0c8 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -53,34 +53,55 @@ struct RoutePointInfo enum class TransitType: uint32_t { // Do not change the order! + IntermediatePoint, Pedestrian, - Subway + Subway, + Train, + LightRail, + Monorail }; struct TransitStepInfo { TransitStepInfo() = default; - TransitStepInfo(TransitType type, double distance, double time, - std::string const & number = "", uint32_t color = 0); + TransitStepInfo(TransitType type, double distance, int time, + std::string const & number = "", uint32_t color = 0, + int intermediateIndex = 0); bool IsEqualType(TransitStepInfo const & ts) const; TransitType m_type = TransitType::Pedestrian; - double m_distance = 0.0; - double m_time = 0.0; + + double m_distanceInMeters = 0.0; + int m_timeInSec = 0; + + std::string m_distanceStr; + std::string m_distanceUnitsSuffix; + + // Is valid for TransitType::Subway std::string m_number; - uint32_t m_color; + uint32_t m_colorARGB = 0; + + // Is valid for TransitType::IntermediatePoint + int m_intermediateIndex = 0; }; struct TransitRouteInfo { - double m_totalDistance = 0.0; - double m_totalTime = 0.0; - double m_totalPedestrianDistance = 0.0; - double m_totalPedestrianTime = 0.0; + double m_totalDistInMeters = 0.0; + double m_totalPedestrianDistInMeters = 0.0; + int m_totalTimeInSec = 0; + int m_totalPedestrianTimeInSec = 0; + + std::string m_totalDistanceStr; + std::string m_totalDistanceUnitsSuffix; + std::string m_totalPedestrianDistanceStr; + std::string m_totalPedestrianUnitsSuffix; + std::vector m_steps; void AddStep(TransitStepInfo const & step); + void UpdateDistanceStrings(); }; class RoutingManager final diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 5bf2eceb95..d1ace09a41 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -49,6 +49,17 @@ double constexpr kMinimumETASec = 60.0; namespace routing { +void FormatDistance(double dist, string & value, string & suffix) +{ + /// @todo Make better formatting of distance and units. + UNUSED_VALUE(measurement_utils::FormatDistance(dist, value)); + + size_t const delim = value.find(' '); + ASSERT(delim != string::npos, ()); + suffix = value.substr(delim + 1); + value.erase(delim); +}; + RoutingSession::RoutingSession() : m_router(nullptr) , m_route(make_shared(string())) @@ -304,17 +315,6 @@ RoutingSession::State RoutingSession::OnLocationPositionChanged(GpsInfo const & void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const { - auto formatDistFn = [](double dist, string & value, string & suffix) - { - /// @todo Make better formatting of distance and units. - UNUSED_VALUE(measurement_utils::FormatDistance(dist, value)); - - size_t const delim = value.find(' '); - ASSERT(delim != string::npos, ()); - suffix = value.substr(delim + 1); - value.erase(delim); - }; - threads::MutexGuard guard(m_routingSessionMutex); ASSERT(m_route, ()); @@ -329,17 +329,17 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const if (!IsNavigable()) { info = FollowingInfo(); - formatDistFn(m_route->GetTotalDistanceMeters(), info.m_distToTarget, info.m_targetUnitsSuffix); + FormatDistance(m_route->GetTotalDistanceMeters(), info.m_distToTarget, info.m_targetUnitsSuffix); info.m_time = static_cast(max(kMinimumETASec, m_route->GetCurrentTimeToEndSec())); return; } - formatDistFn(m_route->GetCurrentDistanceToEndMeters(), info.m_distToTarget, info.m_targetUnitsSuffix); + FormatDistance(m_route->GetCurrentDistanceToEndMeters(), info.m_distToTarget, info.m_targetUnitsSuffix); double distanceToTurnMeters = 0.; turns::TurnItem turn; m_route->GetCurrentTurn(distanceToTurnMeters, turn); - formatDistFn(distanceToTurnMeters, info.m_distToTurn, info.m_turnUnitsSuffix); + FormatDistance(distanceToTurnMeters, info.m_distToTurn, info.m_turnUnitsSuffix); info.m_turn = turn.m_turn; // The turn after the next one. diff --git a/routing/routing_session.hpp b/routing/routing_session.hpp index 164db9c3e2..1ed72f5a4f 100644 --- a/routing/routing_session.hpp +++ b/routing/routing_session.hpp @@ -249,5 +249,7 @@ private: mutable double m_lastCompletionPercent; }; +void FormatDistance(double dist, string & value, string & suffix); + string DebugPrint(RoutingSession::State state); } // namespace routing