private synchronized void setNewRoute(RouteCalculationResult res, Location start) { final boolean newRoute = !this.route.isCalculated(); route = res; if (isFollowingMode) { if (lastFixedLocation != null) { start = lastFixedLocation; } // try remove false route-recalculated prompts by checking direction to second route node boolean wrongMovementDirection = false; List<Location> routeNodes = res.getImmutableAllLocations(); if (routeNodes != null && !routeNodes.isEmpty()) { int newCurrentRoute = lookAheadFindMinOrthogonalDistance(start, routeNodes, res.currentRoute, 15); if (newCurrentRoute + 1 < routeNodes.size()) { // This check is valid for Online/GPX services (offline routing is aware of route // direction) wrongMovementDirection = checkWrongMovementDirection(start, routeNodes.get(newCurrentRoute + 1)); // set/reset evalWaitInterval only if new route is in forward direction if (!wrongMovementDirection) { evalWaitInterval = 3000; } else { evalWaitInterval = evalWaitInterval * 3 / 2; evalWaitInterval = Math.min(evalWaitInterval, 120000); } } } // trigger voice prompt only if new route is in forward direction // If route is in wrong direction after one more setLocation it will be recalculated if (!wrongMovementDirection || newRoute) { voiceRouter.newRouteIsCalculated(newRoute); } } app.runInUIThread( new Runnable() { @Override public void run() { for (IRouteInformationListener l : listeners) { l.newRouteIsCalculated(newRoute); } } }); }
private Location setCurrentLocation( Location currentLocation, boolean returnUpdatedLocation, RouteCalculationResult previousRoute) { Location locationProjection = currentLocation; if (finalLocation == null || currentLocation == null) { makeUturnWhenPossible = false; return locationProjection; } float posTolerance = POSITION_TOLERANCE; if (currentLocation.hasAccuracy()) { posTolerance = POSITION_TOLERANCE / 2 + currentLocation.getAccuracy(); } boolean calculateRoute = false; synchronized (this) { // 0. Route empty or needs to be extended? Then re-calculate route. if (route.isEmpty()) { calculateRoute = true; } else { // 1. Update current route position status according to latest received location boolean finished = updateCurrentRouteStatus(currentLocation, posTolerance); if (finished) { return null; } List<Location> routeNodes = route.getImmutableAllLocations(); int currentRoute = route.currentRoute; // 2. Analyze if we need to recalculate route // >100m off current route (sideways) if (currentRoute > 0) { double dist = getOrthogonalDistance( currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); if (dist > 1.7 * posTolerance) { log.info("Recalculate route, because correlation : " + dist); // $NON-NLS-1$ calculateRoute = true; } if (dist > 350) { voiceRouter.announceOffRoute(dist); } } // 3. Identify wrong movement direction Location next = route.getNextRouteLocation(); boolean wrongMovementDirection = checkWrongMovementDirection(currentLocation, next); if (wrongMovementDirection && currentLocation.distanceTo(routeNodes.get(currentRoute)) > 2 * posTolerance) { log.info( "Recalculate route, because wrong movement direction: " + currentLocation.distanceTo(routeNodes.get(currentRoute))); // $NON-NLS-1$ calculateRoute = true; } // 4. Identify if UTurn is needed boolean uTurnIsNeeded = identifyUTurnIsNeeded(currentLocation, posTolerance); // 5. Update Voice router if (isFollowingMode) { // don't update in route planing mode announceGpxWaypoints(currentLocation); boolean inRecalc = calculateRoute || isRouteBeingCalculated(); if (!inRecalc && !uTurnIsNeeded && !wrongMovementDirection) { voiceRouter.updateStatus(currentLocation, false); } else if (uTurnIsNeeded) { voiceRouter.makeUTStatus(); } } // calculate projection of current location if (currentRoute > 0) { locationProjection = new Location(currentLocation); Location nextLocation = routeNodes.get(currentRoute); LatLon project = getProject( currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); locationProjection.setLatitude(project.getLatitude()); locationProjection.setLongitude(project.getLongitude()); // we need to update bearing too float bearingTo = locationProjection.bearingTo(nextLocation); locationProjection.setBearing(bearingTo); } } lastFixedLocation = currentLocation; lastProjection = locationProjection; } if (calculateRoute) { recalculateRouteInBackground( false, currentLocation, finalLocation, intermediatePoints, currentGPXRoute, previousRoute.isCalculated() ? previousRoute : null); } else if (currentRunningJob != null && currentRunningJob instanceof RouteRecalculationThread) { RouteRecalculationThread thread = (RouteRecalculationThread) currentRunningJob; thread.stopCalculation(); } double projectDist = mode != null && mode.hasFastSpeed() ? posTolerance : posTolerance / 2; if (returnUpdatedLocation && locationProjection != null && currentLocation.distanceTo(locationProjection) < projectDist) { return locationProjection; } else { return currentLocation; } }
private boolean updateCurrentRouteStatus(Location currentLocation, float posTolerance) { List<Location> routeNodes = route.getImmutableAllLocations(); int currentRoute = route.currentRoute; // 1. Try to proceed to next point using orthogonal distance (finding minimum orthogonal dist) while (currentRoute + 1 < routeNodes.size()) { double dist = currentLocation.distanceTo(routeNodes.get(currentRoute)); if (currentRoute > 0) { dist = getOrthogonalDistance( currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute)); } boolean processed = false; // if we are still too far try to proceed many points // if not then look ahead only 3 in order to catch sharp turns boolean longDistance = dist >= 250; int newCurrentRoute = lookAheadFindMinOrthogonalDistance( currentLocation, routeNodes, currentRoute, longDistance ? 15 : 8); double newDist = getOrthogonalDistance( currentLocation, routeNodes.get(newCurrentRoute), routeNodes.get(newCurrentRoute + 1)); if (longDistance) { if (newDist < dist) { if (log.isDebugEnabled()) { log.debug( "Processed by distance : (new) " + newDist + " (old) " + dist); //$NON-NLS-1$//$NON-NLS-2$ } processed = true; } } else if (newDist < dist || newDist < 10) { // newDist < 10 (avoid distance 0 till next turn) if (dist > posTolerance) { processed = true; if (log.isDebugEnabled()) { log.debug( "Processed by distance : " + newDist + " " + dist); // $NON-NLS-1$//$NON-NLS-2$ } } else { // case if you are getting close to the next point after turn // but you have not yet turned (could be checked bearing) if (currentLocation.hasBearing() || lastFixedLocation != null) { float bearingToRoute = currentLocation.bearingTo(routeNodes.get(currentRoute)); float bearingRouteNext = routeNodes.get(newCurrentRoute).bearingTo(routeNodes.get(newCurrentRoute + 1)); float bearingMotion = currentLocation.hasBearing() ? currentLocation.getBearing() : lastFixedLocation.bearingTo(currentLocation); double diff = Math.abs(MapUtils.degreesDiff(bearingMotion, bearingToRoute)); double diffToNext = Math.abs(MapUtils.degreesDiff(bearingMotion, bearingRouteNext)); if (diff > diffToNext) { if (log.isDebugEnabled()) { log.debug("Processed point bearing deltas : " + diff + " " + diffToNext); } processed = true; } } } } if (processed) { // that node already passed route.updateCurrentRoute(newCurrentRoute + 1); currentRoute = newCurrentRoute + 1; } else { break; } } // 2. check if intermediate found if (route.getIntermediatePointsToPass() > 0 && route.getDistanceToNextIntermediate(lastFixedLocation) < POSITION_TOLERANCE * 2) { showMessage(app.getString(R.string.arrived_at_intermediate_point)); route.passIntermediatePoint(); TargetPointsHelper targets = app.getTargetPointsHelper(); List<String> ns = targets.getIntermediatePointNames(); int toDel = targets.getIntermediatePoints().size() - route.getIntermediatePointsToPass(); int currentIndex = toDel - 1; String name = currentIndex < 0 || currentIndex >= ns.size() || ns.get(currentIndex) == null ? "" : ns.get(currentIndex); if (isFollowingMode) { voiceRouter.arrivedIntermediatePoint(name); } while (toDel > 0) { targets.removeWayPoint(false, 0); toDel--; } while (intermediatePoints != null && route.getIntermediatePointsToPass() < intermediatePoints.size()) { intermediatePoints.remove(0); } } // 3. check if destination found Location lastPoint = routeNodes.get(routeNodes.size() - 1); if (currentRoute > routeNodes.size() - 3 && currentLocation.distanceTo(lastPoint) < (((float) settings.getApplicationMode().getArrivalDistance()) * settings.ARRIVAL_DISTANCE_FACTOR.get())) { showMessage(app.getString(R.string.arrived_at_destination)); TargetPointsHelper targets = app.getTargetPointsHelper(); String description = targets.getPointNavigateDescription(); if (isFollowingMode) { voiceRouter.arrivedDestinationPoint(description); } if (OsmandPlugin.onDestinationReached()) { clearCurrentRoute(null, null); setRoutePlanningMode(false); app.runInUIThread( new Runnable() { @Override public void run() { settings.APPLICATION_MODE.set(settings.DEFAULT_APPLICATION_MODE.get()); } }); // targets.clearPointToNavigate(false); return true; } } return false; }
public List<Location> getCurrentCalculatedRoute() { return route.getImmutableAllLocations(); }