diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 648a8abca8..e6efa7c152 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1230,12 +1230,12 @@ Java_com_mapswithme_maps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * } vector imageRGBAData; - int32_t minRouteAltitude = 0; - int32_t maxRouteAltitude = 0; + uint32_t totalAscent = 0; + uint32_t totalDescent = 0; measurement_utils::Units units = measurement_utils::Units::Metric; if (!fr->GetRoutingManager().GenerateRouteAltitudeChart( width, height, altitudes, routePointDistanceM, imageRGBAData, - minRouteAltitude, maxRouteAltitude, units)) + totalAscent, totalDescent, units)) { LOG(LWARNING, ("Can't generate route altitude image.")); return nullptr; @@ -1245,13 +1245,13 @@ Java_com_mapswithme_maps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * jclass const routeAltitudeLimitsClass = env->GetObjectClass(routeAltitudeLimits); ASSERT(routeAltitudeLimitsClass, ()); - static jfieldID const minRouteAltitudeField = env->GetFieldID(routeAltitudeLimitsClass, "minRouteAltitude", "I"); - ASSERT(minRouteAltitudeField, ()); - env->SetIntField(routeAltitudeLimits, minRouteAltitudeField, minRouteAltitude); + static jfieldID const totalAscentField = env->GetFieldID(routeAltitudeLimitsClass, "totalAscent", "I"); + ASSERT(totalAscentField, ()); + env->SetIntField(routeAltitudeLimits, totalAscentField, static_cast(totalAscent)); - static jfieldID const maxRouteAltitudeField = env->GetFieldID(routeAltitudeLimitsClass, "maxRouteAltitude", "I"); - ASSERT(maxRouteAltitudeField, ()); - env->SetIntField(routeAltitudeLimits, maxRouteAltitudeField, maxRouteAltitude); + static jfieldID const totalDescentField = env->GetFieldID(routeAltitudeLimitsClass, "totalDescent", "I"); + ASSERT(totalDescentField, ()); + env->SetIntField(routeAltitudeLimits, totalDescentField, static_cast(totalDescent)); static jfieldID const isMetricUnitsField = env->GetFieldID(routeAltitudeLimitsClass, "isMetricUnits", "Z"); ASSERT(isMetricUnitsField, ()); diff --git a/android/res/drawable-hdpi/ic_altitude_difference.webp b/android/res/drawable-hdpi/ic_altitude_difference.webp deleted file mode 100644 index 261b1c8ff8..0000000000 Binary files a/android/res/drawable-hdpi/ic_altitude_difference.webp and /dev/null differ diff --git a/android/res/drawable-mdpi/ic_altitude_difference.webp b/android/res/drawable-mdpi/ic_altitude_difference.webp deleted file mode 100644 index d68fb12bd0..0000000000 Binary files a/android/res/drawable-mdpi/ic_altitude_difference.webp and /dev/null differ diff --git a/android/res/drawable-xhdpi/ic_altitude_difference.webp b/android/res/drawable-xhdpi/ic_altitude_difference.webp deleted file mode 100644 index 979e203606..0000000000 Binary files a/android/res/drawable-xhdpi/ic_altitude_difference.webp and /dev/null differ diff --git a/android/res/drawable-xxhdpi/ic_altitude_difference.webp b/android/res/drawable-xxhdpi/ic_altitude_difference.webp deleted file mode 100644 index 697df0d6f9..0000000000 Binary files a/android/res/drawable-xxhdpi/ic_altitude_difference.webp and /dev/null differ diff --git a/android/res/drawable-xxxhdpi/ic_altitude_difference.webp b/android/res/drawable-xxxhdpi/ic_altitude_difference.webp deleted file mode 100644 index 713ba646cd..0000000000 Binary files a/android/res/drawable-xxxhdpi/ic_altitude_difference.webp and /dev/null differ diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java index 70e2020626..2a21d5dd4a 100644 --- a/android/src/com/mapswithme/maps/Framework.java +++ b/android/src/com/mapswithme/maps/Framework.java @@ -112,8 +112,8 @@ public class Framework public static class RouteAltitudeLimits { - public int minRouteAltitude; - public int maxRouteAltitude; + public int totalAscent; + public int totalDescent; public boolean isMetricUnits; } diff --git a/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java b/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java index a4d99cb141..1e671b6554 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java +++ b/android/src/com/mapswithme/maps/routing/RoutingBottomMenuController.java @@ -264,17 +264,10 @@ final class RoutingBottomMenuController implements View.OnClickListener { mAltitudeChart.setImageBitmap(bm); UiUtils.show(mAltitudeChart); - String meter = mAltitudeDifference.getResources().getString(R.string.meter); - String foot = mAltitudeDifference.getResources().getString(R.string.foot); - mAltitudeDifference.setText(String.format(Locale.getDefault(), "%d %s", - limits.maxRouteAltitude - limits.minRouteAltitude, - limits.isMetricUnits ? meter : foot)); - Drawable icon = ContextCompat.getDrawable(mContext, - R.drawable.ic_altitude_difference); - int colorAccent = ContextCompat.getColor(mContext, - UiUtils.getStyledResourceId(mContext, R.attr.colorAccent)); - mAltitudeDifference.setCompoundDrawablesRelativeWithIntrinsicBounds(Graphics.tint(icon, colorAccent), - null, null, null); + final String unit = limits.isMetricUnits ? mAltitudeDifference.getResources().getString(R.string.meter) : mAltitudeDifference.getResources().getString(R.string.foot); + mAltitudeDifference.setText(String.format(Locale.getDefault(), "▲ %d %s ▼ %d %s", + limits.totalAscent, unit, + limits.totalDescent, unit)); UiUtils.show(mAltitudeDifference); } } 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 e9a735e468..63c0f591b5 100644 --- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift +++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/RoutePreview/RoutePreviewStatus/BaseRoutePreviewStatus.swift @@ -39,6 +39,12 @@ final class BaseRoutePreviewStatus: SolidTouchView { weak var navigationInfo: MWMNavigationDashboardEntity? + static let elevationAttributes: [NSAttributedString.Key: Any] = + [ + .foregroundColor: UIColor.linkBlue(), + .font: UIFont.medium14() + ] + var elevation: NSAttributedString? { didSet { updateResultsLabel() @@ -118,15 +124,11 @@ final class BaseRoutePreviewStatus: SolidTouchView { if MWMRouter.hasRouteAltitude() { heightBox.isHidden = false MWMRouter.routeAltitudeImage(for: heightProfileImage.frame.size, - completion: { image, elevation in - self.heightProfileImage.image = image - guard let elevation = elevation else { return } - let attributes: [NSAttributedString.Key: Any] = - [ - .foregroundColor: UIColor.linkBlue(), - .font: UIFont.medium14() - ] - self.elevation = NSAttributedString(string: "▲▼ \(elevation)", attributes: attributes) + completion: { image, totalAscent, totalDescent in + self.heightProfileImage.image = image + if let totalAscent = totalAscent, let totalDescent = totalDescent { + self.elevation = NSAttributedString(string: "▲ \(totalAscent) ▼ \(totalDescent)", attributes: BaseRoutePreviewStatus.elevationAttributes) + } }) } else { heightBox.isHidden = true diff --git a/iphone/Maps/Core/Routing/MWMRouter.h b/iphone/Maps/Core/Routing/MWMRouter.h index 8fa3ae631f..b1cfe9dad2 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.h +++ b/iphone/Maps/Core/Routing/MWMRouter.h @@ -8,7 +8,7 @@ typedef NS_ENUM(NSInteger, MWMRoadType) { MWMRoadTypeMotorway }; -typedef void (^MWMImageHeightBlock)(UIImage *, NSString *); +typedef void (^MWMImageHeightBlock)(UIImage *, NSString *, NSString *); @interface MWMRouter : NSObject diff --git a/iphone/Maps/Core/Routing/MWMRouter.mm b/iphone/Maps/Core/Routing/MWMRouter.mm index a3e9e4f694..16afd18a4d 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.mm +++ b/iphone/Maps/Core/Routing/MWMRouter.mm @@ -23,7 +23,8 @@ using namespace routing; @interface MWMRouter () @property(nonatomic) NSMutableDictionary *altitudeImagesData; -@property(nonatomic) NSString *altitudeElevation; +@property(nonatomic) NSString *totalAscent; +@property(nonatomic) NSString *totalDescent; @property(nonatomic) dispatch_queue_t renderAltitudeImagesQueue; @property(nonatomic) uint32_t routeManagerTransactionId; @property(nonatomic) BOOL canAutoAddLastLocation; @@ -370,13 +371,13 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm NSData *imageData = router.altitudeImagesData[sizeValue]; if (!imageData) { std::vector imageRGBAData; - int32_t minRouteAltitude = 0; - int32_t maxRouteAltitude = 0; + uint32_t totalAscent = 0; + uint32_t totalDescent = 0; measurement_utils::Units units = measurement_utils::Units::Metric; if (!GetFramework().GetRoutingManager().GenerateRouteAltitudeChart(width, height, *altitudes, *routePointDistanceM, imageRGBAData, - minRouteAltitude, maxRouteAltitude, units)) { + totalAscent, totalDescent, units)) { return; } @@ -386,15 +387,16 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm router.altitudeImagesData[sizeValue] = imageData; auto const localizedUnits = platform::GetLocalizedAltitudeUnits(); - auto const height = maxRouteAltitude - minRouteAltitude; - router.altitudeElevation = - @(measurement_utils::FormatAltitudeWithLocalization(height, localizedUnits.m_low).c_str()); + router.totalAscent = + @(measurement_utils::FormatAltitudeWithLocalization(totalAscent, localizedUnits.m_low).c_str()); + router.totalDescent = + @(measurement_utils::FormatAltitudeWithLocalization(totalDescent, localizedUnits.m_low).c_str()); } dispatch_async(dispatch_get_main_queue(), ^{ UIImage *altitudeImage = [UIImage imageWithRGBAData:imageData width:width height:height]; if (altitudeImage) - block(altitudeImage, router.altitudeElevation); + block(altitudeImage, router.totalAscent, router.totalDescent); }); }); } @@ -403,7 +405,8 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm auto router = self.router; dispatch_async(router.renderAltitudeImagesQueue, ^{ [router.altitudeImagesData removeAllObjects]; - router.altitudeElevation = nil; + router.totalAscent = nil; + router.totalDescent = nil; }); } diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 1096cb27aa..12814a9eb2 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -1158,8 +1158,8 @@ bool RoutingManager::GenerateRouteAltitudeChart(uint32_t width, uint32_t height, geometry::Altitudes const & altitudes, vector const & routePointDistanceM, vector & imageRGBAData, - int32_t & minRouteAltitude, - int32_t & maxRouteAltitude, + uint32_t & totalAscent, + uint32_t & totalDescent, measurement_utils::Units & altitudeUnits) const { CHECK_EQUAL(altitudes.size(), routePointDistanceM.size(), ()); @@ -1170,9 +1170,17 @@ bool RoutingManager::GenerateRouteAltitudeChart(uint32_t width, uint32_t height, GetStyleReader().GetCurrentStyle(), imageRGBAData)) return false; - auto const minMaxIt = minmax_element(altitudes.cbegin(), altitudes.cend()); - geometry::Altitude const minRouteAltitudeM = *minMaxIt.first; - geometry::Altitude const maxRouteAltitudeM = *minMaxIt.second; + uint32_t totalAscentM = 0; + uint32_t totalDescentM = 0; + int16_t delta; + + for (size_t i = 1; i < altitudes.size(); i++) { + delta = altitudes[i] - altitudes[i - 1]; + if (delta > 0) + totalAscentM += delta; + else + totalDescentM += -delta; + } if (!settings::Get(settings::kMeasurementUnits, altitudeUnits)) altitudeUnits = measurement_utils::Units::Metric; @@ -1180,12 +1188,12 @@ bool RoutingManager::GenerateRouteAltitudeChart(uint32_t width, uint32_t height, switch (altitudeUnits) { case measurement_utils::Units::Imperial: - minRouteAltitude = measurement_utils::MetersToFeet(minRouteAltitudeM); - maxRouteAltitude = measurement_utils::MetersToFeet(maxRouteAltitudeM); + totalAscent = measurement_utils::MetersToFeet(totalAscentM); + totalDescent = measurement_utils::MetersToFeet(totalDescentM); break; case measurement_utils::Units::Metric: - minRouteAltitude = minRouteAltitudeM; - maxRouteAltitude = maxRouteAltitudeM; + totalAscent = totalAscentM; + totalDescent = totalDescentM; break; } return true; diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index b127e84121..c0f1e2c80f 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -277,8 +277,8 @@ public: /// \param altitudes route points altitude. /// \param routePointDistanceM distance in meters from route beginning to route points. /// \param imageRGBAData is bits of result image in RGBA. - /// \param minRouteAltitude is min altitude along the route in altitudeUnits. - /// \param maxRouteAltitude is max altitude along the route in altitudeUnits. + /// \param totalAscent is total ascent of the route in altitudeUnits. + /// \param totalDescent is total descent of the route in altitudeUnits. /// \param altitudeUnits is units (meters or feet) which is used to pass min and max altitudes. /// \returns If there is valid route info and the chart was generated returns true /// and false otherwise. If the method returns true it is guaranteed that the size of @@ -288,8 +288,9 @@ public: bool GenerateRouteAltitudeChart(uint32_t width, uint32_t height, geometry::Altitudes const & altitudes, std::vector const & routePointDistanceM, - std::vector & imageRGBAData, int32_t & minRouteAltitude, - int32_t & maxRouteAltitude, + std::vector & imageRGBAData, + uint32_t & totalAscent, + uint32_t & totalDescent, measurement_utils::Units & altitudeUnits) const; uint32_t OpenRoutePointsTransaction();