summaryrefslogtreecommitdiff
path: root/lib/navigation/HERENavigation.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/navigation/HERENavigation.dart')
-rw-r--r--lib/navigation/HERENavigation.dart324
1 files changed, 324 insertions, 0 deletions
diff --git a/lib/navigation/HERENavigation.dart b/lib/navigation/HERENavigation.dart
new file mode 100644
index 0000000..0504061
--- /dev/null
+++ b/lib/navigation/HERENavigation.dart
@@ -0,0 +1,324 @@
+import 'dart:async';
+import 'package:here_sdk/routing.dart' as here;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:here_sdk/core.dart';
+import 'package:here_sdk/core.errors.dart';
+import 'package:here_sdk/gestures.dart';
+import 'package:here_sdk/mapview.dart';
+import 'package:here_sdk/routing.dart';
+import 'package:here_sdk/search.dart';
+import 'package:training_planner/events/MapPanningEvent.dart';
+import 'package:training_planner/events/NextStopLoadedEvent.dart';
+import 'package:training_planner/events/RouteLoadedEvent.dart';
+import 'package:training_planner/events/StopCompletedEvent.dart';
+import 'package:training_planner/main.dart';
+import 'package:training_planner/navigation/baseNavigation.dart';
+import 'package:training_planner/pages/navigation_page.dart';
+import 'package:training_planner/route.dart';
+import '../route.dart' as DHLRoute;
+
+class HERENavigation extends BaseNavigation {
+ HERENavigation({Key? key, required route}) : super(key: key, route: route);
+
+ @override
+ _HERENavigationState createState() => _HERENavigationState();
+}
+
+class _HERENavigationState extends BaseNavigationState {
+ late HereMapController hereMapController;
+
+ List<MapPolyline> _routeSections = [];
+ List<MapPolyline> _pathSections = [];
+
+ late RoutingEngine _routingEngine;
+ late SearchOptions _searchOptions;
+ late MapMarker mapMarker;
+
+ Future<Uint8List> _loadFileAsUint8List(String assetPathToFile) async {
+ // The path refers to the assets directory as specified in pubspec.yaml.
+ ByteData fileData = await rootBundle.load(assetPathToFile);
+ return Uint8List.view(fileData.buffer);
+ }
+
+ Future<void> _addCircle(GeoCoordinates geoCoordinates) async {
+ Uint8List imagePixelData = await _loadFileAsUint8List('assets/package.png');
+ MapImage circleMapImage =
+ MapImage.withPixelDataAndImageFormat(imagePixelData, ImageFormat.png);
+ mapMarker = MapMarker(geoCoordinates, circleMapImage);
+ hereMapController.mapScene.addMapMarker(mapMarker);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return HereMap(onMapCreated: _onMapCreated);
+ }
+
+ void _updateLocation(Position value) {
+ widget.lastPosition = DHLCoordinates(value.latitude, value.longitude);
+ mapMarker.coordinates = GeoCoordinates(value.latitude, value.longitude);
+ flyTo(DHLCoordinates(value.latitude, value.longitude));
+ }
+
+ void _setLocationOnMap() {
+ if (!widget.isLookingAround) {
+ Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
+ .then(
+ (value) => {if (!widget.isLookingAround) _updateLocation(value)});
+ }
+ }
+
+ void initialize() {
+ try {
+ _routingEngine = RoutingEngine();
+ } on InstantiationException {
+ throw ("Initialization of RoutingEngine failed.");
+ }
+
+ _searchOptions = SearchOptions.withDefaults();
+ _searchOptions.languageCode = LanguageCode.enUs;
+ _searchOptions.maxItems = 5;
+
+ hereMapController.camera.lookAtPoint(GeoCoordinates(50.8434572, 5.7381166));
+ hereMapController.camera.zoomTo(widget.currentZoom);
+
+ _addCircle(GeoCoordinates(50.8434572, 5.7381166));
+
+ widget.timer =
+ Timer.periodic(Duration(seconds: 1), (Timer t) => _setLocationOnMap());
+
+ hereMapController.gestures.panListener = PanListener(
+ (GestureState state, Point2D touchPoint, Point2D p2, double d) {
+ widget.isLookingAround = true;
+ eventBus.fire(MapPanningEvent(true));
+ });
+
+ widget.stopCompletedEvent = eventBus.on<StopCompletedEvent>().listen((e) {
+ routeSectionCursor += 1;
+ if (routeSectionCursor >= widget.allTasks.length) {
+ routeSectionCursor = widget.allTasks.length - 1;
+ }
+ updateHighlightedRouteSections();
+ eventBus.fire(NextStopLoadedEvent(widget.allTasks[routeSectionCursor]));
+ });
+
+ widget.stopIncompletedEvent =
+ eventBus.on<StopIncompletedEvent>().listen((e) {
+ routeSectionCursor -= 1;
+ if (routeSectionCursor < 0) routeSectionCursor = 0;
+ updateHighlightedRouteSections(force: true);
+ eventBus.fire(NextStopLoadedEvent(widget.allTasks[routeSectionCursor]));
+ });
+
+ blacklistProvider
+ .getBlacklist()
+ .then((value) => {widget.blacklist = value});
+ }
+
+ void _onMapCreated(HereMapController hereMapController) async {
+ this.hereMapController = hereMapController;
+ hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay,
+ (MapError? error) {
+ if (error == null) {
+ initialize();
+ addRoute(widget.route).then((value) {
+ widget.doneLoading = true;
+ });
+ } else {
+ print("Map scene not loaded. MapError: " + error.toString());
+ }
+ });
+ }
+
+ @override
+ Future<void> addRoute(DHLRoute.Route route) async {
+ if (route.tasks == null) return;
+
+ Position currentPosition = await Geolocator.getCurrentPosition(
+ desiredAccuracy: LocationAccuracy.high);
+ GeoCoordinates routeStartCoords =
+ GeoCoordinates(currentPosition.latitude, currentPosition.longitude);
+
+ List<Waypoint> waypoints = [Waypoint.withDefaults(routeStartCoords)];
+
+ groupTasksIntoGroups(route);
+
+ for (var item in widget.parcelNumberPins) {
+ waypoints.add(Waypoint.withDefaults(
+ GeoCoordinates(item.coords.lattitude, item.coords.longitude)));
+ }
+
+ for (var item in widget.parcelNumberPins) {
+ item.isDoublePlannedAddress = isAddressDoublePlanned(item);
+ }
+
+ PedestrianOptions f = PedestrianOptions.withDefaults();
+ f.routeOptions.alternatives = 0;
+ f.routeOptions.enableTrafficOptimization = false;
+ f.routeOptions.optimizationMode = OptimizationMode.fastest;
+
+ _routingEngine.calculatePedestrianRoute(waypoints, f,
+ (RoutingError? routingError, List<here.Route>? routeList) async {
+ if (routingError == null) {
+ here.Route route = routeList!.first;
+
+ _showRouteOnMap(route);
+
+ for (int i = 0; i < route.sections.length; i++) {
+ _showLineToHouse(route.sections.elementAt(i),
+ waypoints.elementAt(i + 1).coordinates);
+ }
+
+ updateHighlightedRouteSections();
+ } else {
+ var error = routingError.toString();
+ }
+ });
+ }
+
+ _showLineToHouse(Section section, GeoCoordinates houseCoords) {
+ GeoPolyline routeGeoPolyline = section.geometry;
+
+ GeoPolyline walkLine =
+ GeoPolyline([routeGeoPolyline.vertices.last, houseCoords]);
+ MapPolyline walkPathPolyline =
+ MapPolyline(walkLine, 8, Color.fromARGB(160, 255, 20, 20));
+ hereMapController.mapScene.addMapPolyline(walkPathPolyline);
+
+ _pathSections.add(walkPathPolyline);
+ }
+
+ _showRouteOnMap(here.Route route) {
+ double widthInPixels = 15;
+
+ for (int i = 0; i < route.sections.length; i++) {
+ Section section = route.sections.elementAt(i);
+ GeoPolyline routeGeoPolyline = section.geometry;
+
+ MapPolyline routeMapPolyline = MapPolyline(
+ routeGeoPolyline, widthInPixels, Color.fromARGB(160, 0, 144, 138));
+ hereMapController.mapScene.addMapPolyline(routeMapPolyline);
+
+ _routeSections.add(routeMapPolyline);
+ }
+ }
+
+ @override
+ void changeZoom(double newVal) {
+ if (newVal > 20) newVal = 20;
+ if (newVal < 13) newVal = 13;
+ widget.currentZoom = newVal;
+ print('hallo' + newVal.toString());
+ hereMapController.camera.zoomTo(widget.currentZoom);
+ }
+
+ @override
+ void flyTo(DHLCoordinates coords) {
+ double bearingInDegress = 0;
+ double tiltInDegress = 0;
+ GeoOrientationUpdate orientation =
+ GeoOrientationUpdate(bearingInDegress, tiltInDegress);
+
+ hereMapController.camera.lookAtPointWithGeoOrientationAndMeasure(
+ GeoCoordinates(coords.lattitude, coords.longitude),
+ orientation,
+ MapMeasure(MapMeasureKind.zoomLevel, widget.currentZoom));
+ }
+
+ @override
+ dynamic createPinWidget(
+ DestinationPin pin, Color color, DHLCoordinates coords) {
+ var pp = hereMapController.pinWidget(
+ createPin(pin, color,
+ isDoublePlannedAddress: pin.isDoublePlannedAddress),
+ GeoCoordinates(coords.lattitude, coords.longitude));
+ pp?.anchor = Anchor2D.withHorizontalAndVertical(0.5, 0.5);
+ return pp;
+ }
+
+ @override
+ void dispose() {
+ destroyNavigation();
+ super.dispose();
+ }
+
+ @override
+ void updateHighlightedRouteSections({bool force = false}) {
+ int maxPins = 300;
+
+ for (int i = widget.parcelNumberPins.length - 1; i >= 0; i--) {
+ DestinationPin pin = widget.parcelNumberPins.elementAt(i);
+
+ Color color = Color.fromARGB(200, 0, 144, 138);
+ if (i == routeSectionCursor) color = Color.fromARGB(199, 143, 8, 31);
+ if (i == routeSectionCursor + 1) color = Color.fromARGB(197, 13, 36, 241);
+ if (destinationPinIsInBlacklist(widget.parcelNumberPins[i])) {
+ color = Color.fromRGBO(143, 8, 31, 0.78);
+ }
+
+ bool forceUpdateThisPin =
+ force && (i > routeSectionCursor - 3 && i < routeSectionCursor + 3);
+
+ if (!shouldDoublePlannedAddressBeVisible(pin)) {
+ pin.pin?.unpin();
+ pin.pin = null;
+ continue;
+ }
+
+ if (i > routeSectionCursor + 1 && i < routeSectionCursor + maxPins) {
+ if (forceUpdateThisPin) {
+ pin.pin?.unpin();
+ pin.pin = null;
+ } else if (pin.pin != null) {
+ continue;
+ }
+ var widgetPin =
+ createPinWidget(pin, color, widget.destinationCoords[i]);
+ pin.pin = widgetPin;
+ } else {
+ pin.pin?.unpin();
+ pin.pin = null;
+ }
+
+ if (i == routeSectionCursor || i == routeSectionCursor + 1) {
+ var widgetPin =
+ createPinWidget(pin, color, widget.destinationCoords[i]);
+ pin.pin = widgetPin;
+ }
+ }
+
+ // Show the next 5 sections as to not clutter the screen.
+ int maxSections = 5;
+ int maxWalkPaths = 300;
+ for (int i = _routeSections.length - 1; i >= 0; i--) {
+ MapPolyline section = _routeSections.elementAt(i);
+ MapPolyline path = _pathSections.elementAt(i);
+
+ // previous section
+ if (i == routeSectionCursor - 1) {
+ section.lineColor = Color.fromARGB(160, 168, 113, 108);
+ path.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+ // current and next 5 sections
+ else if (i >= routeSectionCursor &&
+ i < routeSectionCursor + maxSections) {
+ section.lineColor = Color.fromARGB(
+ (255 - ((255 / (maxSections + 1)) * (i - routeSectionCursor)))
+ .toInt(),
+ 0,
+ 144,
+ 138);
+ } else {
+ section.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+
+ if (i >= routeSectionCursor && i < routeSectionCursor + maxWalkPaths) {
+ path.lineColor = Color.fromARGB(160, 255, 0, 0);
+ } else {
+ path.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+ }
+ }
+}