public boolean identifyUTurnIsNeeded(Location currentLocation, float posTolerance) { if (finalLocation == null || currentLocation == null || !route.isCalculated()) { this.makeUturnWhenPossible = false; return makeUturnWhenPossible; } boolean makeUturnWhenPossible = false; if (currentLocation.hasBearing()) { float bearingMotion = currentLocation.getBearing(); Location nextRoutePosition = route.getNextRouteLocation(); float bearingToRoute = currentLocation.bearingTo(nextRoutePosition); double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); // 7. Check if you left the route and an unscheduled U-turn would bring you back (also Issue // 863) // This prompt is an interim advice and does only sound if a new route in forward direction // could not be found in x seconds if (Math.abs(diff) > 135f) { float d = currentLocation.distanceTo(nextRoutePosition); // 60m tolerance to allow for GPS inaccuracy if (d > posTolerance) { // require x sec continuous since first detection if (makeUTwpDetected == 0) { makeUTwpDetected = System.currentTimeMillis(); } else if ((System.currentTimeMillis() - makeUTwpDetected > 10000)) { makeUturnWhenPossible = true; // log.info("bearingMotion is opposite to bearingRoute"); //$NON-NLS-1$ } } } else { makeUTwpDetected = 0; } } this.makeUturnWhenPossible = makeUturnWhenPossible; return makeUturnWhenPossible; }
public synchronized AlarmInfo getMostImportantAlarm(MetricsConstants mc, boolean showCameras) { float mxspeed = route.getCurrentMaxSpeed(); AlarmInfo speedAlarm = createSpeedAlarm(mc, mxspeed, lastProjection); AlarmInfo alarm = route.getMostImportantAlarm(lastProjection, speedAlarm, showCameras); if (alarm != null) { voiceRouter.announceAlarm(alarm); } return alarm; }
@Override public void run() { RouteCalculationResult res = provider.calculateRouteImpl(params); if (params.calculationProgress.isCancelled) { currentRunningJob = null; return; } final boolean onlineSourceWithoutInternet = !res.isCalculated() && params.type.isOnline() && !settings.isInternetConnectionAvailable(); if (onlineSourceWithoutInternet && settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()) { if (params.previousToRecalculate != null && params.previousToRecalculate.isCalculated()) { res = provider.recalculatePartOfflineRoute(res, params); } } synchronized (RoutingHelper.this) { if (res.isCalculated()) { setNewRoute(res, params.start); } else { evalWaitInterval = evalWaitInterval * 3 / 2; evalWaitInterval = Math.min(evalWaitInterval, 120000); } currentRunningJob = null; } if (res.isCalculated()) { String msg = app.getString(R.string.new_route_calculated_dist) + ": " + OsmAndFormatter.getFormattedDistance(res.getWholeDistance(), app); if (res.getRoutingTime() != 0f) { msg += " (" + Algorithms.formatDuration((int) res.getRoutingTime()) + ")"; } showMessage(msg); } else if (onlineSourceWithoutInternet) { showMessage( app.getString(R.string.error_calculating_route) + ":\n" + app.getString( R.string.internet_connection_required_for_online_route)); // $NON-NLS-1$ } else { if (res.getErrorMessage() != null) { showMessage( app.getString(R.string.error_calculating_route) + ":\n" + res.getErrorMessage()); // $NON-NLS-1$ } else { showMessage(app.getString(R.string.empty_route_calculated)); } } lastTimeEvaluatedRoute = System.currentTimeMillis(); }
public synchronized NextDirectionInfo getNextRouteDirectionInfo( NextDirectionInfo info, boolean toSpeak) { NextDirectionInfo i = route.getNextRouteDirectionInfo(info, lastProjection, toSpeak); if (i != null) { i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastProjection); } return i; }
public synchronized NextDirectionInfo getNextRouteDirectionInfoAfter( NextDirectionInfo previous, NextDirectionInfo to, boolean toSpeak) { NextDirectionInfo i = route.getNextRouteDirectionInfoAfter(previous, to, toSpeak); if (i != null) { i.imminent = voiceRouter.calculateImminent(i.distanceTo, null); } return i; }
private void announceGpxWaypoints(Location currentLocation) { if (currentLocation != null) { List<WptPt> wpt = route.getWaypointsToAnnounce(currentLocation); if (wpt.size() > 0) { String s = ""; for (WptPt w : wpt) { if (!Algorithms.isEmpty(w.name)) { s = w.name + ","; } } if (!Algorithms.isEmpty(s)) { voiceRouter.announceWaypoint(s); } } } }
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); } } }); }
public List<RouteSegmentResult> getUpcomingTunnel(float distToStart) { return route.getUpcomingTunnel(distToStart); }
public RouteSegmentResult getCurrentSegmentResult() { return route.getCurrentSegmentResult(); }
public synchronized float getCurrentMaxSpeed() { return route.getCurrentMaxSpeed(); }
public boolean isRouteCalculated() { return route.isCalculated(); }
public synchronized int getLeftDistanceNextIntermediate() { return route.getDistanceToNextIntermediate(lastFixedLocation); }
public synchronized int getLeftDistance() { return route.getDistanceToFinish(lastFixedLocation); }
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; }
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; } }
public synchronized int getLeftTime() { return route.getLeftTime(lastFixedLocation); }
public List<RouteDirectionInfo> getRouteDirections() { return route.getRouteDirections(); }
public Location getLocationFromRouteDirection(RouteDirectionInfo i) { return route.getLocationFromRouteDirection(i); }
public void notifyIfRouteIsCalculated() { if (route.isCalculated()) { voiceRouter.newRouteIsCalculated(true); } }
public List<Location> getCurrentCalculatedRoute() { return route.getImmutableAllLocations(); }