From 35b220cc06db87ce98aea56d33aec6b5379f65ef Mon Sep 17 00:00:00 2001 From: datasun Date: Thu, 30 Mar 2023 12:24:25 +0200 Subject: [PATCH] Update example apps for release 4.13.5.0 Signed-off-by: datasun --- README.md | 2 +- examples/latest/README.md | 2 +- .../java/com/here/routing/RoutingExample.java | 28 ++++-- .../routing_app/lib/RoutingExample.dart | 20 +++-- .../ios/Routing/Routing/RoutingExample.swift | 49 +++++++---- .../here/navigation/NavigationExample.java | 9 +- .../java/com/here/routing/RoutingExample.java | 28 ++++-- .../navigation_app/lib/NavigationExample.dart | 11 ++- .../routing_app/lib/RoutingExample.dart | 20 +++-- .../HikingDiary/HikingDiary/HikingApp.swift | 88 +++++++++---------- .../latest/navigate/ios/HikingDiary/README.md | 2 +- .../Navigation/NavigationExample.swift | 14 ++- .../ios/Routing/Routing/RoutingExample.swift | 49 +++++++---- 13 files changed, 204 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 6967291c..4dbafd41 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For an overview of the existing features, please check the _Developer's Guide_ f > For now, the _Navigate Edition_ is only available upon request. Please contact your HERE representative to receive access including a set of evaluation credentials. -## List of Available Example Apps (Version 4.13.4.0) +## List of Available Example Apps (Version 4.13.5.0) - **HelloMap**: Shows the classic 'Hello World'. - **HelloMapKotlin**: Shows the classic 'Hello World' using Kotlin language (Android only). diff --git a/examples/latest/README.md b/examples/latest/README.md index b763fbb5..96f84770 100644 --- a/examples/latest/README.md +++ b/examples/latest/README.md @@ -1,4 +1,4 @@ -This folder contains the HERE SDK examples apps for version: 4.13.4.0 +This folder contains the HERE SDK examples apps for version: 4.13.5.0 - HERE SDK for Android ([Lite Edition](lite/android/), [Explore Edition](explore/android/), [Navigate Edition](navigate/android/)) - HERE SDK for iOS ([Lite Edition](lite/ios/), [Explore Edition](explore/ios/), [Navigate Edition](navigate/ios/)) diff --git a/examples/latest/explore/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java b/examples/latest/explore/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java index 06baf15a..dafbad94 100644 --- a/examples/latest/explore/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java +++ b/examples/latest/explore/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java @@ -30,6 +30,7 @@ import com.here.sdk.core.GeoPolyline; import com.here.sdk.core.Point2D; import com.here.sdk.core.errors.InstantiationErrorException; +import com.here.sdk.core.threading.TaskHandle; import com.here.sdk.mapview.MapCamera; import com.here.sdk.mapview.MapImage; import com.here.sdk.mapview.MapImageFactory; @@ -125,15 +126,15 @@ private void logRouteViolations(Route route) { private void logRouteSectionDetails(Route route) { DateFormat dateFormat = new SimpleDateFormat("HH:mm"); - for (int i = 0; i< route.getSections().size(); i++) { + for (int i = 0; i < route.getSections().size(); i++) { Section section = route.getSections().get(i); - Log.d(TAG, "Route Section : " + (i+1)); + Log.d(TAG, "Route Section : " + (i + 1)); Log.d(TAG, "Route Section Departure Time : " + dateFormat.format(section.getDepartureLocationTime().localTime)); Log.d(TAG, "Route Section Arrival Time : " + dateFormat.format(section.getArrivalLocationTime().localTime)); - Log.d(TAG, "Route Section length : " + section.getLengthInMeters() + " m"); + Log.d(TAG, "Route Section length : " + section.getLengthInMeters() + " m"); Log.d(TAG, "Route Section duration : " + section.getDuration().getSeconds() + " s"); } } @@ -144,8 +145,8 @@ private void showRouteDetails(Route route) { int lengthInMeters = route.getLengthInMeters(); String routeDetails = "Travel Time: " + formatTime(estimatedTravelTimeInSeconds) - + ", traffic delay: " + formatTime(estimatedTrafficDelayInSeconds) - + ", Length: " + formatLength(lengthInMeters); + + ", traffic delay: " + formatTime(estimatedTrafficDelayInSeconds) + + ", Length: " + formatLength(lengthInMeters); showDialog("Route Details", routeDetails); } @@ -265,8 +266,19 @@ private void clearRoute() { // This renders the traffic flow on top of the route as multiple MapPolylines per span. private void showTrafficOnRoute(Route route) { + if (route.getLengthInMeters() / 1000 > 5000) { + Log.d(TAG, "Skip showing traffic-on-route for longer routes."); + return; + } + for (Section section : route.getSections()) { for (Span span : section.getSpans()) { + TrafficSpeed trafficSpeed = span.getTrafficSpeed(); + Color lineColor = getTrafficColor(trafficSpeed.jamFactor); + if (lineColor == null) { + // We skip rendering low traffic. + continue; + } GeoPolyline spanGeoPolyline; try { // A polyline needs to have two or more coordinates. @@ -276,8 +288,6 @@ private void showTrafficOnRoute(Route route) { return; } float widthInPixels = 10; - TrafficSpeed trafficSpeed = span.getTrafficSpeed(); - Color lineColor = getTrafficColor(trafficSpeed.jamFactor); MapPolyline trafficSpanMapPolyline = new MapPolyline(spanGeoPolyline, widthInPixels, lineColor); mapView.getMapScene().addMapPolyline(trafficSpanMapPolyline); mapPolylines.add(trafficSpanMapPolyline); @@ -290,9 +300,11 @@ private void showTrafficOnRoute(Route route) { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. + // Returns null in case of no or light traffic. + @Nullable private Color getTrafficColor(Double jamFactor) { if (jamFactor == null || jamFactor < 4) { - return Color.valueOf(0, 0, 0, 0); // Fully transparent (RGBA) + return null; } else if (jamFactor >= 4 && jamFactor < 8) { return Color.valueOf(1, 1, 0, 0.63f); // Yellow } else if (jamFactor >= 8 && jamFactor < 10) { diff --git a/examples/latest/explore/flutter/routing_app/lib/RoutingExample.dart b/examples/latest/explore/flutter/routing_app/lib/RoutingExample.dart index c0975ad0..16b99312 100644 --- a/examples/latest/explore/flutter/routing_app/lib/RoutingExample.dart +++ b/examples/latest/explore/flutter/routing_app/lib/RoutingExample.dart @@ -151,8 +151,19 @@ class RoutingExample { // This renders the traffic flow on top of the route as multiple MapPolylines per span. _showTrafficOnRoute(here.Route route) { + if (route.lengthInMeters / 1000 > 5000) { + print("Skip showing traffic-on-route for longer routes."); + return; + } + for (var section in route.sections) { for (var span in section.spans) { + TrafficSpeed trafficSpeed = span.trafficSpeed; + Color? lineColor = _getTrafficColor(trafficSpeed.jamFactor); + if (lineColor == null) { + // We skip rendering low traffic. + continue; + } GeoPolyline spanGeoPolyline; try { // A polyline needs to have two or more coordinates. @@ -162,8 +173,6 @@ class RoutingExample { return; } double widthInPixels = 10; - TrafficSpeed trafficSpeed = span.trafficSpeed; - Color lineColor = _getTrafficColor(trafficSpeed.jamFactor ?? 0); MapPolyline trafficSpanMapPolyline = new MapPolyline(spanGeoPolyline, widthInPixels, lineColor); _hereMapController.mapScene.addMapPolyline(trafficSpanMapPolyline); _mapPolylines.add(trafficSpanMapPolyline); @@ -176,9 +185,10 @@ class RoutingExample { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. - Color _getTrafficColor(double jamFactor) { - if (jamFactor < 4) { - return Color.fromARGB(0, 0, 0, 0); // Fully transparent + // Returns null in case of no or light traffic. + Color? _getTrafficColor(double? jamFactor) { + if (jamFactor == null || jamFactor < 4) { + return null; } else if (jamFactor >= 4 && jamFactor < 8) { return Color.fromARGB(160, 255, 255, 0); // Yellow } else if (jamFactor >= 8 && jamFactor < 10) { diff --git a/examples/latest/explore/ios/Routing/Routing/RoutingExample.swift b/examples/latest/explore/ios/Routing/Routing/RoutingExample.swift index bce62797..d0f8b436 100644 --- a/examples/latest/explore/ios/Routing/Routing/RoutingExample.swift +++ b/examples/latest/explore/ios/Routing/Routing/RoutingExample.swift @@ -78,11 +78,11 @@ class RoutingExample { } } } - + private func logRouteSectionDetails(route: Route) { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "HH:mm" - + for (i, sections) in route.sections.enumerated() { print("Route Section : " + String(i)); print("Route Section Departure Time : " + dateFormatter.string(from: sections.departureLocationTime!.localTime)); @@ -96,7 +96,7 @@ class RoutingExample { let estimatedTravelTimeInSeconds = route.duration let estimatedTrafficDelayInSeconds = route.trafficDelay let lengthInMeters = route.lengthInMeters - + let routeDetails = "Travel Time (h:m): " + formatTime(sec: estimatedTravelTimeInSeconds) + ", Traffic Delay (h:m): " + formatTime(sec: estimatedTrafficDelayInSeconds) + ", Length: " + formatLength(meters: lengthInMeters) @@ -121,7 +121,7 @@ class RoutingExample { private func showRouteOnMap(route: Route) { // Optionally, clear any previous route. clearMap() - + // Show route as polyline. let routeGeoPolyline = route.geometry let routeMapPolyline = MapPolyline(geometry: routeGeoPolyline, @@ -135,10 +135,10 @@ class RoutingExample { // Optionally, render traffic on route. showTrafficOnRoute(route) - + let startPoint = route.sections.first!.departurePlace.mapMatchedCoordinates let destination = route.sections.last!.arrivalPlace.mapMatchedCoordinates - + // Draw a circle to indicate starting point and destination. addCircleMapMarker(geoCoordinates: startPoint, imageName: "green_dot.png") addCircleMapMarker(geoCoordinates: destination, imageName: "green_dot.png") @@ -201,17 +201,26 @@ class RoutingExample { // This renders the traffic flow on top of the route as multiple MapPolylines per span. private func showTrafficOnRoute(_ route: Route) { + if route.lengthInMeters / 1000 > 5000 { + print("Skip showing traffic-on-route for longer routes."); + return + } + for section in route.sections { for span in section.spans { + let trafficSpeed = span.trafficSpeed + guard let lineColor = getTrafficColor(trafficSpeed.jamFactor) else { + // Skip rendering low traffic. + continue + } // A polyline needs to have two or more coordinates. guard let spanGeoPolyline = try? GeoPolyline(vertices: span.polyline) else { print("Error: Initialization of GeoPolyline failed.") return } - let trafficSpeed = span.trafficSpeed let trafficSpanMapPolyline = MapPolyline(geometry: spanGeoPolyline, widthInPixels: 10, - color: getTrafficColor(trafficSpeed.jamFactor ?? 0)) + color: lineColor) mapView.mapScene.addMapPolyline(trafficSpanMapPolyline) mapPolylineList.append(trafficSpanMapPolyline) } @@ -223,17 +232,21 @@ class RoutingExample { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. - private func getTrafficColor(_ jamFactor: Double) -> UIColor { - if (jamFactor < 4) { - return UIColor(red: 0, green: 0, blue: 0, alpha: 0) // Fully transparent - } else if (jamFactor >= 4 && jamFactor < 8) { - return UIColor(red: 1, green: 1, blue: 0, alpha: 0.63) // Yellow - } else if (jamFactor >= 8 && jamFactor < 10) { - return UIColor(red: 1, green: 0, blue: 0, alpha: 0.63) // Red - } - return UIColor(red: 0, green: 0, blue: 0, alpha: 0.63) // Black + // Returns nil in case of no or light traffic. + private func getTrafficColor(_ jamFactor: Double?) -> UIColor? { + guard let jamFactor = jamFactor else { + return nil + } + if jamFactor < 4 { + return nil + } else if jamFactor >= 4 && jamFactor < 8 { + return UIColor(red: 1, green: 1, blue: 0, alpha: 0.63) // Yellow + } else if jamFactor >= 8 && jamFactor < 10 { + return UIColor(red: 1, green: 0, blue: 0, alpha: 0.63) // Red + } + return UIColor(red: 0, green: 0, blue: 0, alpha: 0.63) // Black } - + func clearMap() { clearWaypointMapMarker() clearRoute() diff --git a/examples/latest/navigate/android/Navigation/app/src/main/java/com/here/navigation/NavigationExample.java b/examples/latest/navigate/android/Navigation/app/src/main/java/com/here/navigation/NavigationExample.java index 161f68a7..2ac70330 100644 --- a/examples/latest/navigate/android/Navigation/app/src/main/java/com/here/navigation/NavigationExample.java +++ b/examples/latest/navigate/android/Navigation/app/src/main/java/com/here/navigation/NavigationExample.java @@ -563,6 +563,11 @@ public void onRealisticViewWarningUpdated(@NonNull RealisticViewWarning realisti } RealisticView realisticView = realisticViewWarning.realisticView; + if (realisticView == null) { + Log.d(TAG, "A RealisticView just passed. No SVG data delivered."); + return; + } + String signpostSvgImageContent = realisticView.signpostSvgImageContent; String junctionViewSvgImageContent = realisticView.junctionViewSvgImageContent; // The resolution-independent SVG data can now be used in an application to visualize the image. @@ -582,9 +587,9 @@ private String getRoadName(Maneuver maneuver) { RoadTexts nextRoadTexts = maneuver.getNextRoadTexts(); String currentRoadName = currentRoadTexts.names.getDefaultValue(); - String currentRoadNumber = currentRoadTexts.numbers.getDefaultValue(); + String currentRoadNumber = currentRoadTexts.numbersWithDirection.getDefaultValue(); String nextRoadName = nextRoadTexts.names.getDefaultValue(); - String nextRoadNumber = nextRoadTexts.numbers.getDefaultValue(); + String nextRoadNumber = nextRoadTexts.numbersWithDirection.getDefaultValue(); String roadName = nextRoadName == null ? nextRoadNumber : nextRoadName; diff --git a/examples/latest/navigate/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java b/examples/latest/navigate/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java index 06baf15a..dafbad94 100644 --- a/examples/latest/navigate/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java +++ b/examples/latest/navigate/android/Routing/app/src/main/java/com/here/routing/RoutingExample.java @@ -30,6 +30,7 @@ import com.here.sdk.core.GeoPolyline; import com.here.sdk.core.Point2D; import com.here.sdk.core.errors.InstantiationErrorException; +import com.here.sdk.core.threading.TaskHandle; import com.here.sdk.mapview.MapCamera; import com.here.sdk.mapview.MapImage; import com.here.sdk.mapview.MapImageFactory; @@ -125,15 +126,15 @@ private void logRouteViolations(Route route) { private void logRouteSectionDetails(Route route) { DateFormat dateFormat = new SimpleDateFormat("HH:mm"); - for (int i = 0; i< route.getSections().size(); i++) { + for (int i = 0; i < route.getSections().size(); i++) { Section section = route.getSections().get(i); - Log.d(TAG, "Route Section : " + (i+1)); + Log.d(TAG, "Route Section : " + (i + 1)); Log.d(TAG, "Route Section Departure Time : " + dateFormat.format(section.getDepartureLocationTime().localTime)); Log.d(TAG, "Route Section Arrival Time : " + dateFormat.format(section.getArrivalLocationTime().localTime)); - Log.d(TAG, "Route Section length : " + section.getLengthInMeters() + " m"); + Log.d(TAG, "Route Section length : " + section.getLengthInMeters() + " m"); Log.d(TAG, "Route Section duration : " + section.getDuration().getSeconds() + " s"); } } @@ -144,8 +145,8 @@ private void showRouteDetails(Route route) { int lengthInMeters = route.getLengthInMeters(); String routeDetails = "Travel Time: " + formatTime(estimatedTravelTimeInSeconds) - + ", traffic delay: " + formatTime(estimatedTrafficDelayInSeconds) - + ", Length: " + formatLength(lengthInMeters); + + ", traffic delay: " + formatTime(estimatedTrafficDelayInSeconds) + + ", Length: " + formatLength(lengthInMeters); showDialog("Route Details", routeDetails); } @@ -265,8 +266,19 @@ private void clearRoute() { // This renders the traffic flow on top of the route as multiple MapPolylines per span. private void showTrafficOnRoute(Route route) { + if (route.getLengthInMeters() / 1000 > 5000) { + Log.d(TAG, "Skip showing traffic-on-route for longer routes."); + return; + } + for (Section section : route.getSections()) { for (Span span : section.getSpans()) { + TrafficSpeed trafficSpeed = span.getTrafficSpeed(); + Color lineColor = getTrafficColor(trafficSpeed.jamFactor); + if (lineColor == null) { + // We skip rendering low traffic. + continue; + } GeoPolyline spanGeoPolyline; try { // A polyline needs to have two or more coordinates. @@ -276,8 +288,6 @@ private void showTrafficOnRoute(Route route) { return; } float widthInPixels = 10; - TrafficSpeed trafficSpeed = span.getTrafficSpeed(); - Color lineColor = getTrafficColor(trafficSpeed.jamFactor); MapPolyline trafficSpanMapPolyline = new MapPolyline(spanGeoPolyline, widthInPixels, lineColor); mapView.getMapScene().addMapPolyline(trafficSpanMapPolyline); mapPolylines.add(trafficSpanMapPolyline); @@ -290,9 +300,11 @@ private void showTrafficOnRoute(Route route) { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. + // Returns null in case of no or light traffic. + @Nullable private Color getTrafficColor(Double jamFactor) { if (jamFactor == null || jamFactor < 4) { - return Color.valueOf(0, 0, 0, 0); // Fully transparent (RGBA) + return null; } else if (jamFactor >= 4 && jamFactor < 8) { return Color.valueOf(1, 1, 0, 0.63f); // Yellow } else if (jamFactor >= 8 && jamFactor < 10) { diff --git a/examples/latest/navigate/flutter/navigation_app/lib/NavigationExample.dart b/examples/latest/navigate/flutter/navigation_app/lib/NavigationExample.dart index f2d7146a..53f2dd29 100644 --- a/examples/latest/navigate/flutter/navigation_app/lib/NavigationExample.dart +++ b/examples/latest/navigate/flutter/navigation_app/lib/NavigationExample.dart @@ -210,9 +210,9 @@ class NavigationExample { RoadTexts nextRoadTexts = maneuver.nextRoadTexts; String? currentRoadName = currentRoadTexts.names.getDefaultValue(); - String? currentRoadNumber = currentRoadTexts.numbers.getDefaultValue(); + String? currentRoadNumber = currentRoadTexts.numbersWithDirection.getDefaultValue(); String? nextRoadName = nextRoadTexts.names.getDefaultValue(); - String? nextRoadNumber = nextRoadTexts.numbers.getDefaultValue(); + String? nextRoadNumber = nextRoadTexts.numbersWithDirection.getDefaultValue(); String? roadName = nextRoadName == null ? nextRoadNumber : nextRoadName; @@ -584,7 +584,12 @@ class NavigationExample { print("A RealisticView just passed."); } - RealisticView realisticView = realisticViewWarning.realisticView; + RealisticView? realisticView = realisticViewWarning.realisticView; + if (realisticView == null) { + print("A RealisticView just passed. No SVG content delivered."); + return; + } + String signpostSvgImageContent = realisticView.signpostSvgImageContent; String junctionViewSvgImageContent = realisticView.junctionViewSvgImageContent; // The resolution-independent SVG data can now be used in an application to visualize the image. diff --git a/examples/latest/navigate/flutter/routing_app/lib/RoutingExample.dart b/examples/latest/navigate/flutter/routing_app/lib/RoutingExample.dart index c0975ad0..16b99312 100644 --- a/examples/latest/navigate/flutter/routing_app/lib/RoutingExample.dart +++ b/examples/latest/navigate/flutter/routing_app/lib/RoutingExample.dart @@ -151,8 +151,19 @@ class RoutingExample { // This renders the traffic flow on top of the route as multiple MapPolylines per span. _showTrafficOnRoute(here.Route route) { + if (route.lengthInMeters / 1000 > 5000) { + print("Skip showing traffic-on-route for longer routes."); + return; + } + for (var section in route.sections) { for (var span in section.spans) { + TrafficSpeed trafficSpeed = span.trafficSpeed; + Color? lineColor = _getTrafficColor(trafficSpeed.jamFactor); + if (lineColor == null) { + // We skip rendering low traffic. + continue; + } GeoPolyline spanGeoPolyline; try { // A polyline needs to have two or more coordinates. @@ -162,8 +173,6 @@ class RoutingExample { return; } double widthInPixels = 10; - TrafficSpeed trafficSpeed = span.trafficSpeed; - Color lineColor = _getTrafficColor(trafficSpeed.jamFactor ?? 0); MapPolyline trafficSpanMapPolyline = new MapPolyline(spanGeoPolyline, widthInPixels, lineColor); _hereMapController.mapScene.addMapPolyline(trafficSpanMapPolyline); _mapPolylines.add(trafficSpanMapPolyline); @@ -176,9 +185,10 @@ class RoutingExample { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. - Color _getTrafficColor(double jamFactor) { - if (jamFactor < 4) { - return Color.fromARGB(0, 0, 0, 0); // Fully transparent + // Returns null in case of no or light traffic. + Color? _getTrafficColor(double? jamFactor) { + if (jamFactor == null || jamFactor < 4) { + return null; } else if (jamFactor >= 4 && jamFactor < 8) { return Color.fromARGB(160, 255, 255, 0); // Yellow } else if (jamFactor >= 8 && jamFactor < 10) { diff --git a/examples/latest/navigate/ios/HikingDiary/HikingDiary/HikingApp.swift b/examples/latest/navigate/ios/HikingDiary/HikingDiary/HikingApp.swift index b02a931c..5af3b236 100644 --- a/examples/latest/navigate/ios/HikingDiary/HikingDiary/HikingApp.swift +++ b/examples/latest/navigate/ios/HikingDiary/HikingDiary/HikingApp.swift @@ -25,7 +25,7 @@ class HikingApp: LocationDelegate { // A class to receive location events from the device. private let herePositioningProvider = HEREPositioningProvider() - + private let mapView: MapView private var myPathMapPolyline: MapPolyline? private var isHiking = false @@ -36,58 +36,58 @@ class HikingApp: LocationDelegate { private let outdoorRasterLayer: OutdoorRasterLayer private let messageTextView = UITextView() private var locationFilter: LocationFilterStrategy - + init(mapView: MapView) { self.mapView = mapView - + // A class to filter out undesired location signals. locationFilter = DistanceAccuracyLocationFilter() - + // A class to manage GPX operations. gpxManager = GPXManager(gpxDocumentFileName: "myGPXDocument.gpx") - + // A helper to show our current location and the raw location signals. positioningVisualizer = HEREPositioningVisualizer(mapView) - + // On top of the default map style, we allow to show a dedicated outdoor layer. outdoorRasterLayer = OutdoorRasterLayer(mapView: mapView) - + // Sets delegate to receive locations from HERE Positioning. herePositioningProvider.startLocating(locationDelegate: self, accuracy: .navigation) - + animateCameraToCurrentLocation() - + setupMessageView() setMessage("** Hiking Diary **") } - + func onStartHikingButtonClicked() { clearMap() isHiking = true isGPXTrackLoaded = false animateCameraToCurrentLocation() setMessage("Start Hike.") - + // Create a new GPXTrackWriter to record this trip. gpxTrackWriter = GPXTrackWriter() } - + func onStopHikingButtonClicked() { clearMap() - + if isHiking && isGPXTrackLoaded == false { saveDiaryEntry() } else { setMessage("Stopped.") } - + isHiking = false } - + func enableOutdoorRasterLayer() { outdoorRasterLayer.enable() } - + func disableOutdoorRasterLayer() { outdoorRasterLayer.disable() } @@ -100,14 +100,14 @@ class HikingApp: LocationDelegate { // Here we visualize all incoming locations, unfiltered. positioningVisualizer.renderUnfilteredLocationSignals(location) } - + if isHiking && locationFilter.checkIfLocationCanBeUsed(location) { // Here we store only locations that are considered to be accurate enough. gpxTrackWriter.onLocationUpdated(location) - + // Visualize our hiking trip as an expanding polyline. - let mapPolyline = updateTravelledPath(location) - + let mapPolyline = updateTravelledPath() + // Calculate the currently travelled distance. if let mapPolyline = mapPolyline { let distanceTravelled = getLengthOfGeoPolylineInMeters(mapPolyline.geometry) @@ -116,28 +116,28 @@ class HikingApp: LocationDelegate { } } - private func updateTravelledPath(_ location: Location) -> MapPolyline? { + private func updateTravelledPath() -> MapPolyline? { let geoCoordinatesList = gpxManager.getGeoCoordinatesList(track: gpxTrackWriter.track) - + if geoCoordinatesList.count < 2 { return nil } - + // We are sure that the number of vertices is greater than 1 (see above), so it will not crash. let geoPolyline = try! GeoPolyline(vertices: geoCoordinatesList) - + // Add polyline to the map, if instance is nil. guard let mapPolyline = myPathMapPolyline else { addMapPolyline(geoPolyline) return myPathMapPolyline } - + // Update the polyline shape that shows the travelled path of the user. mapPolyline.geometry = geoPolyline - + return mapPolyline } - + private func getLengthOfGeoPolylineInMeters(_ geoPolyLine: GeoPolyline) -> Int { var length = 0 for i in 1...geoPolyLine.vertices.count - 1 { @@ -145,7 +145,7 @@ class HikingApp: LocationDelegate { } return length } - + private func addMapPolyline(_ geoPolyline: GeoPolyline) { clearMap() myPathMapPolyline = MapPolyline(geometry: geoPolyline, @@ -153,7 +153,7 @@ class HikingApp: LocationDelegate { color: UIColor(red: 0, green: 0.56, blue: 0.54, alpha: 0.63)) mapView.mapScene.addMapPolyline(myPathMapPolyline!) } - + private func clearMap() { if myPathMapPolyline != nil { mapView.mapScene.removeMapPolyline(myPathMapPolyline!) @@ -161,22 +161,22 @@ class HikingApp: LocationDelegate { } positioningVisualizer.clearMap() } - + private func saveDiaryEntry() { // Permanently store the trip on the device. let result = gpxManager.saveGPXTrack(gpxTrackWriter.track) setMessage("Saved Hike: \(result).") } - + // Load the selected diary entry and show the polyline related to that hike. public func loadDiaryEntry(index: Int) { if isHiking { print("Stop hiking first.") return } - + isGPXTrackLoaded = true - + // Load the hiking trip. guard let gpxTrack = gpxManager.getGPXTrack(index: index) else { return @@ -185,19 +185,19 @@ class HikingApp: LocationDelegate { let diaryGeoCoordinatesList = gpxManager.getGeoCoordinatesList(track: gpxTrack) let diaryGeoPolyline = try! GeoPolyline(vertices: diaryGeoCoordinatesList) let distanceTravelled = getLengthOfGeoPolylineInMeters(diaryGeoPolyline) - + addMapPolyline(diaryGeoPolyline) animateCameraTo(diaryGeoCoordinatesList) - + setMessage("Diary Entry from: " + gpxTrack.description + "\n" + "Hike Distance: \(distanceTravelled) m") } - + public func deleteDiaryEntry(index: Int) { let isSuccess = gpxManager.deleteGPXTrack(index: index) print("Deleted entry: \(isSuccess)") } - + public func getMenuEntryKeys() -> [String] { var entryKeys: [String] = [] for track in gpxManager.gpxDocument.tracks { @@ -205,7 +205,7 @@ class HikingApp: LocationDelegate { } return entryKeys } - + public func getMenuEntryDescriptions() -> [String] { var entryDescriptions: [String] = [] for track in gpxManager.gpxDocument.tracks { @@ -213,7 +213,7 @@ class HikingApp: LocationDelegate { } return entryDescriptions } - + private func animateCameraToCurrentLocation() { if let currentLocation = herePositioningProvider.getLastKnownLocation() { let geoCoordinatesUpdate = GeoCoordinatesUpdate(currentLocation.coordinates) @@ -237,15 +237,15 @@ class HikingApp: LocationDelegate { let bearing: Double = 0 let tilt: Double = 0 let geoOrientationUpdate = GeoOrientationUpdate(bearing: bearing, tilt: tilt) - + // For very short polylines we want to have at least a distance of 100 meters. let minDistanceInMeters = MapMeasure(kind: .distance, value: 100) - + let mapCameraUpdate = MapCameraUpdateFactory.lookAt(geoCoordinateList, viewRectangle: mapViewport, orientation: geoOrientationUpdate, measureLimit: minDistanceInMeters) - + // Create animation. let durationInSeconds = TimeInterval(3) let mapCameraAnimation = MapCameraAnimationFactory.createAnimation(from: mapCameraUpdate, @@ -253,7 +253,7 @@ class HikingApp: LocationDelegate { easingFunction: EasingFunction.inCubic) mapView.camera.startAnimation(mapCameraAnimation) } - + // A permanent view to show scrollable text content. private func setupMessageView() { messageTextView.textColor = .white @@ -269,7 +269,7 @@ class HikingApp: LocationDelegate { self.mapView.addSubview(self.messageTextView) }) } - + public func setMessage(_ message: String) { messageTextView.text = message } diff --git a/examples/latest/navigate/ios/HikingDiary/README.md b/examples/latest/navigate/ios/HikingDiary/README.md index b793dac9..370bd72b 100644 --- a/examples/latest/navigate/ios/HikingDiary/README.md +++ b/examples/latest/navigate/ios/HikingDiary/README.md @@ -1,4 +1,4 @@ -This app shows how to record GPX traces with HERE Positioning. You can find how this is done in [HikingExample.swift](HikingDiary/HikingApp.swift). +This app shows how to use positioning to calculate the distance travelled by a user. You can find how this is done in [HikingExample.swift](HikingDiary/HikingApp.swift). Build instructions: ------------------- diff --git a/examples/latest/navigate/ios/Navigation/Navigation/NavigationExample.swift b/examples/latest/navigate/ios/Navigation/Navigation/NavigationExample.swift index bae41757..f4fe399c 100644 --- a/examples/latest/navigate/ios/Navigation/Navigation/NavigationExample.swift +++ b/examples/latest/navigate/ios/Navigation/Navigation/NavigationExample.swift @@ -188,9 +188,9 @@ class NavigationExample : NavigableLocationDelegate, let nextRoadTexts = maneuver.nextRoadTexts let currentRoadName = currentRoadTexts.names.defaultValue() - let currentRoadNumber = currentRoadTexts.numbers.defaultValue() + let currentRoadNumber = currentRoadTexts.numbersWithDirection.defaultValue() let nextRoadName = nextRoadTexts.names.defaultValue() - let nextRoadNumber = nextRoadTexts.numbers.defaultValue() + let nextRoadNumber = nextRoadTexts.numbersWithDirection.defaultValue() var roadName = nextRoadName == nil ? nextRoadNumber : nextRoadName @@ -544,6 +544,7 @@ class NavigationExample : NavigableLocationDelegate, } } + // Conform to RealisticViewWarningDelegate. // Notifies on signposts together with complex junction views. // Signposts are shown as they appear along a road on a shield to indicate the upcoming directions and // destinations, such as cities or road names. @@ -567,8 +568,13 @@ class NavigationExample : NavigableLocationDelegate, } let realisticView = realisticViewWarning.realisticView - let signpostSvgImageContent = realisticView.signpostSvgImageContent - let junctionViewSvgImageContent = realisticView.junctionViewSvgImageContent + guard let signpostSvgImageContent = realisticView?.signpostSvgImageContent, + let junctionViewSvgImageContent = realisticView?.junctionViewSvgImageContent + else { + print("A RealisticView just passed. No SVG data delivered.") + return + } + // The resolution-independent SVG data can now be used in an application to visualize the image. // Use a SVG library of your choice to create an SVG image out of the SVG string. // Both SVGs contain the same dimension and the signpostSvgImageContent should be shown on top of diff --git a/examples/latest/navigate/ios/Routing/Routing/RoutingExample.swift b/examples/latest/navigate/ios/Routing/Routing/RoutingExample.swift index bce62797..d0f8b436 100644 --- a/examples/latest/navigate/ios/Routing/Routing/RoutingExample.swift +++ b/examples/latest/navigate/ios/Routing/Routing/RoutingExample.swift @@ -78,11 +78,11 @@ class RoutingExample { } } } - + private func logRouteSectionDetails(route: Route) { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "HH:mm" - + for (i, sections) in route.sections.enumerated() { print("Route Section : " + String(i)); print("Route Section Departure Time : " + dateFormatter.string(from: sections.departureLocationTime!.localTime)); @@ -96,7 +96,7 @@ class RoutingExample { let estimatedTravelTimeInSeconds = route.duration let estimatedTrafficDelayInSeconds = route.trafficDelay let lengthInMeters = route.lengthInMeters - + let routeDetails = "Travel Time (h:m): " + formatTime(sec: estimatedTravelTimeInSeconds) + ", Traffic Delay (h:m): " + formatTime(sec: estimatedTrafficDelayInSeconds) + ", Length: " + formatLength(meters: lengthInMeters) @@ -121,7 +121,7 @@ class RoutingExample { private func showRouteOnMap(route: Route) { // Optionally, clear any previous route. clearMap() - + // Show route as polyline. let routeGeoPolyline = route.geometry let routeMapPolyline = MapPolyline(geometry: routeGeoPolyline, @@ -135,10 +135,10 @@ class RoutingExample { // Optionally, render traffic on route. showTrafficOnRoute(route) - + let startPoint = route.sections.first!.departurePlace.mapMatchedCoordinates let destination = route.sections.last!.arrivalPlace.mapMatchedCoordinates - + // Draw a circle to indicate starting point and destination. addCircleMapMarker(geoCoordinates: startPoint, imageName: "green_dot.png") addCircleMapMarker(geoCoordinates: destination, imageName: "green_dot.png") @@ -201,17 +201,26 @@ class RoutingExample { // This renders the traffic flow on top of the route as multiple MapPolylines per span. private func showTrafficOnRoute(_ route: Route) { + if route.lengthInMeters / 1000 > 5000 { + print("Skip showing traffic-on-route for longer routes."); + return + } + for section in route.sections { for span in section.spans { + let trafficSpeed = span.trafficSpeed + guard let lineColor = getTrafficColor(trafficSpeed.jamFactor) else { + // Skip rendering low traffic. + continue + } // A polyline needs to have two or more coordinates. guard let spanGeoPolyline = try? GeoPolyline(vertices: span.polyline) else { print("Error: Initialization of GeoPolyline failed.") return } - let trafficSpeed = span.trafficSpeed let trafficSpanMapPolyline = MapPolyline(geometry: spanGeoPolyline, widthInPixels: 10, - color: getTrafficColor(trafficSpeed.jamFactor ?? 0)) + color: lineColor) mapView.mapScene.addMapPolyline(trafficSpanMapPolyline) mapPolylineList.append(trafficSpanMapPolyline) } @@ -223,17 +232,21 @@ class RoutingExample { // 4 <= jamFactor < 8: Moderate or slow traffic. // 8 <= jamFactor < 10: Severe traffic. // jamFactor = 10: No traffic, ie. the road is blocked. - private func getTrafficColor(_ jamFactor: Double) -> UIColor { - if (jamFactor < 4) { - return UIColor(red: 0, green: 0, blue: 0, alpha: 0) // Fully transparent - } else if (jamFactor >= 4 && jamFactor < 8) { - return UIColor(red: 1, green: 1, blue: 0, alpha: 0.63) // Yellow - } else if (jamFactor >= 8 && jamFactor < 10) { - return UIColor(red: 1, green: 0, blue: 0, alpha: 0.63) // Red - } - return UIColor(red: 0, green: 0, blue: 0, alpha: 0.63) // Black + // Returns nil in case of no or light traffic. + private func getTrafficColor(_ jamFactor: Double?) -> UIColor? { + guard let jamFactor = jamFactor else { + return nil + } + if jamFactor < 4 { + return nil + } else if jamFactor >= 4 && jamFactor < 8 { + return UIColor(red: 1, green: 1, blue: 0, alpha: 0.63) // Yellow + } else if jamFactor >= 8 && jamFactor < 10 { + return UIColor(red: 1, green: 0, blue: 0, alpha: 0.63) // Red + } + return UIColor(red: 0, green: 0, blue: 0, alpha: 0.63) // Black } - + func clearMap() { clearWaypointMapMarker() clearRoute()