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 String getCurrentName() { NextDirectionInfo n = getNextRouteDirectionInfo(new NextDirectionInfo(), false); Location l = lastFixedLocation; float speed = 0; if (l != null && l.hasSpeed()) { speed = l.getSpeed(); } if (n.distanceTo > 0 && n.directionInfo != null && !n.directionInfo.getTurnType().isSkipToSpeak() && voiceRouter.isDistanceLess(speed, n.distanceTo, voiceRouter.PREPARE_DISTANCE * 0.75f)) { String nm = n.directionInfo.getStreetName(); String rf = n.directionInfo.getRef(); String dn = n.directionInfo.getDestinationName(); return "\u2566 " + formatStreetName(nm, rf, dn); } RouteSegmentResult rs = getCurrentSegmentResult(); if (rs != null) { String nm = rs.getObject().getName(); String rf = rs.getObject().getRef(); String dn = rs.getObject().getDestinationName(); return "\u21E7 " + formatStreetName(nm, rf, dn); } return null; }
public void announceCurrentDirection(Location currentLocation) { NextDirectionInfo nextInfo = router.getNextRouteDirectionInfo(new NextDirectionInfo(), true); if (nextInfo == null) { playGoAheadToDestination(); return; } NextDirectionInfo nextNextInfo = router.getNextRouteDirectionInfoAfter(nextInfo, new NextDirectionInfo(), false); float speed = DEFAULT_SPEED; RouteDirectionInfo next = nextInfo.directionInfo; int dist = nextInfo.distanceTo; if (currentLocation != null && currentLocation.hasSpeed()) { speed = Math.max(currentLocation.getSpeed(), speed); } switch (currentStatus) { case STATUS_UTWP_TOLD: playMakeUTwp(); break; case STATUS_UNKNOWN: if (nextRouteDirection != null && ((next == null) || (next.distance == 0))) { playGoAheadToDestination(); } else { playGoAhead(dist); } break; case STATUS_TOLD: if (nextRouteDirection != null) { playGoAheadToDestination(); } break; case STATUS_TURN: if (next.distance < TURN_IN_DISTANCE_END && nextNextInfo != null) { playMakeTurn(next, nextNextInfo.directionInfo); } else { playMakeTurn(next, null); } break; case STATUS_TURN_IN: if ((isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) && nextNextInfo != null) { playMakeTurnIn(next, dist, nextNextInfo.directionInfo); } else { playMakeTurnIn(next, dist, null); } break; case STATUS_PREPARE: playPrepareTurn(next, dist); break; case STATUS_LONG_PREPARE: playPrepareTurn(next, dist); break; default: break; } }
public int calculateImminent(float dist, Location loc) { float speed = DEFAULT_SPEED; if (loc != null && loc.hasSpeed()) { speed = loc.getSpeed(); } if (isDistanceLess(speed, dist, TURN_IN_DISTANCE_END)) { return 0; } else if (dist <= PREPARE_DISTANCE) { return 1; } else if (dist <= PREPARE_LONG_DISTANCE) { return 2; } else { return -1; } }
private void updateCompassVisibility() { View compassView = view.findViewById(R.id.compass_layout); Location ll = getMyApplication().getLocationProvider().getLastKnownLocation(); boolean gpsFixed = ll != null && System.currentTimeMillis() - ll.getTime() < 1000 * 60 * 60 * 20; if (gpsFixed && menu.displayDistanceDirection() && menu.getCurrentMenuState() != MenuState.FULL_SCREEN) { updateDistanceDirection(); compassView.setVisibility(View.VISIBLE); } else { if (!menu.displayDistanceDirection()) { compassView.setVisibility(View.GONE); } else { compassView.setVisibility(View.INVISIBLE); } } }
private static AlarmInfo createSpeedAlarm( MetricsConstants mc, float mxspeed, Location loc, float delta) { AlarmInfo speedAlarm = null; if (mxspeed != 0 && loc != null && loc.hasSpeed() && mxspeed != RouteDataObject.NONE_MAX_SPEED) { if (loc.getSpeed() > mxspeed + delta) { int speed; if (mc == MetricsConstants.KILOMETERS_AND_METERS) { speed = Math.round(mxspeed * 3.6f); } else { speed = Math.round(mxspeed * 3.6f / 1.6f); } speedAlarm = AlarmInfo.createSpeedLimit(speed, loc); } } return speedAlarm; }
public List<Amenity> searchAmenitiesOnThePath( List<Location> locations, double radius, SearchPoiTypeFilter filter, ResultMatcher<Amenity> matcher) { searchAmenitiesInProgress = true; final List<Amenity> amenities = new ArrayList<Amenity>(); try { if (locations != null && locations.size() > 0) { List<AmenityIndexRepository> repos = new ArrayList<AmenityIndexRepository>(); double topLatitude = locations.get(0).getLatitude(); double bottomLatitude = locations.get(0).getLatitude(); double leftLongitude = locations.get(0).getLongitude(); double rightLongitude = locations.get(0).getLongitude(); for (Location l : locations) { topLatitude = Math.max(topLatitude, l.getLatitude()); bottomLatitude = Math.min(bottomLatitude, l.getLatitude()); leftLongitude = Math.min(leftLongitude, l.getLongitude()); rightLongitude = Math.max(rightLongitude, l.getLongitude()); } if (!filter.isEmpty()) { for (AmenityIndexRepository index : amenityRepositories.values()) { if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) { repos.add(index); } } if (!repos.isEmpty()) { for (AmenityIndexRepository r : repos) { List<Amenity> res = r.searchAmenitiesOnThePath(locations, radius, filter, matcher); if (res != null) { amenities.addAll(res); } } } } } } finally { searchAmenitiesInProgress = false; } return amenities; }
public AlarmInfo calculateMostImportantAlarm( RouteDataObject ro, Location loc, MetricsConstants mc, boolean showCameras) { boolean direction = true; if (loc.hasBearing()) { double diff = MapUtils.alignAngleDifference( ro.directionRoute(0, true) - loc.getBearing() / (2 * Math.PI)); direction = Math.abs(diff) < Math.PI; } float mxspeed = ro.getMaximumSpeed(direction); float delta = app.getSettings().SPEED_LIMIT_EXCEED.get() / 3.6f; AlarmInfo speedAlarm = createSpeedAlarm(mc, mxspeed, loc, delta); if (speedAlarm != null) { getVoiceRouter().announceSpeedAlarm(); return speedAlarm; } for (int i = 0; i < ro.getPointsLength(); i++) { int[] pointTypes = ro.getPointTypes(i); RouteRegion reg = ro.region; if (pointTypes != null) { for (int r = 0; r < pointTypes.length; r++) { RouteTypeRule typeRule = reg.quickGetEncodingRule(pointTypes[r]); AlarmInfo info = AlarmInfo.createAlarmInfo(typeRule, 0, loc); if (info != null) { if (info.getType() != AlarmInfoType.SPEED_CAMERA || showCameras) { long ms = System.currentTimeMillis(); if (ms - announcedAlarmTime > 50 * 1000) { announcedAlarmTime = ms; getVoiceRouter().announceAlarm(info.getType()); } return info; } } } } } return null; }
public AlarmInfo getMostImportantAlarm(MetricsConstants mc, boolean showCameras) { Location lastProjection = app.getRoutingHelper().getLastProjection(); float mxspeed = route.getCurrentMaxSpeed(); float delta = app.getSettings().SPEED_LIMIT_EXCEED.get() / 3.6f; AlarmInfo speedAlarm = createSpeedAlarm(mc, mxspeed, lastProjection, delta); if (speedAlarm != null) { getVoiceRouter().announceSpeedAlarm(); } AlarmInfo mostImportant = speedAlarm; int value = speedAlarm != null ? speedAlarm.updateDistanceAndGetPriority(0, 0) : Integer.MAX_VALUE; if (ALARMS < pointsProgress.size()) { int kIterator = pointsProgress.get(ALARMS); List<LocationPointWrapper> lp = locationPoints.get(ALARMS); while (kIterator < lp.size()) { LocationPointWrapper lwp = lp.get(kIterator); if (lp.get(kIterator).routeIndex < route.getCurrentRoute()) { // skip } else { int d = route.getDistanceToPoint(lwp.routeIndex); if (d > LONG_ANNOUNCE_RADIUS) { break; } AlarmInfo inf = (AlarmInfo) lwp.point; float speed = lastProjection != null && lastProjection.hasSpeed() ? lastProjection.getSpeed() : 0; float time = speed > 0 ? d / speed : Integer.MAX_VALUE; int vl = inf.updateDistanceAndGetPriority(time, d); if (vl < value && (showCameras || inf.getType() != AlarmInfoType.SPEED_CAMERA)) { mostImportant = inf; value = vl; } } kIterator++; } } return mostImportant; }
public int getDistance() { int d = 0; LatLon l = getPointToNavigate(); if (l != null) { Location.distanceBetween( view.getLatitude(), view.getLongitude(), l.getLatitude(), l.getLongitude(), calculations); d = (int) calculations[0]; } return d; }
private static LatLon getProject(Location loc, Location from, Location to) { return MapUtils.getProjection( loc.getLatitude(), loc.getLongitude(), from.getLatitude(), from.getLongitude(), to.getLatitude(), to.getLongitude()); }
private static double getOrthogonalDistance(Location loc, Location from, Location to) { return MapUtils.getOrthogonalDistance( loc.getLatitude(), loc.getLongitude(), from.getLatitude(), from.getLongitude(), to.getLatitude(), to.getLongitude()); }
/** * Wrong movement direction is considered when between current location bearing (determines by 2 * last fixed position or provided) and bearing from currentLocation to next (current) point the * difference is more than 60 degrees */ public boolean checkWrongMovementDirection(Location currentLocation, Location nextRouteLocation) { // measuring without bearing could be really error prone (with last fixed location) // this code has an effect on route recalculation which should be detected without mistakes if (currentLocation.hasBearing() && nextRouteLocation != null) { float bearingMotion = currentLocation.getBearing(); float bearingToRoute = currentLocation.bearingTo(nextRouteLocation); double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute); if (Math.abs(diff) > 60f) { // require delay interval since first detection, to avoid false positive // but leave out for now, as late detection is worse than false positive (it may reset voice // router then cause bogus turn and u-turn prompting) // if (wrongMovementDetected == 0) { // wrongMovementDetected = System.currentTimeMillis(); // } else if ((System.currentTimeMillis() - wrongMovementDetected > 500)) { return true; // } } else { // wrongMovementDetected = 0; return false; } } // wrongMovementDetected = 0; return false; }
@Override public void onCreate(Bundle savedInstanceState) { app = getMyApplication(); settings = app.getSettings(); app.applyTheme(this); super.onCreate(savedInstanceState); mapActions = new MapActivityActions(this); mapLayers = new MapActivityLayers(this); requestWindowFeature(Window.FEATURE_NO_TITLE); // Full screen is not used here // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, // WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main); startProgressDialog = new ProgressDialog(this); startProgressDialog.setCancelable(true); app.checkApplicationIsBeingInitialized(this, startProgressDialog); parseLaunchIntentLocation(); mapView = (OsmandMapTileView) findViewById(R.id.MapView); mapView.setTrackBallDelegate( new OsmandMapTileView.OnTrackBallListener() { @Override public boolean onTrackBallEvent(MotionEvent e) { showAndHideMapPosition(); return MapActivity.this.onTrackballEvent(e); } }); mapView.setAccessibilityActions(new MapAccessibilityActions(this)); if (mapViewTrackingUtilities == null) { mapViewTrackingUtilities = new MapViewTrackingUtilities(app); } mapViewTrackingUtilities.setMapView(mapView); // Do some action on close startProgressDialog.setOnDismissListener( new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { app.getResourceManager().getRenderer().clearCache(); mapView.refreshMap(true); } }); app.getResourceManager() .getMapTileDownloader() .addDownloaderCallback( new IMapDownloaderCallback() { @Override public void tileDownloaded(DownloadRequest request) { if (request != null && !request.error && request.fileToSave != null) { ResourceManager mgr = app.getResourceManager(); mgr.tileDownloaded(request); } if (request == null || !request.error) { mapView.tileDownloaded(request); } } }); createProgressBarForRouting(); // This situtation could be when navigation suddenly crashed and after restarting // it tries to continue the last route if (settings.FOLLOW_THE_ROUTE.get() && !app.getRoutingHelper().isRouteCalculated() && !app.getRoutingHelper().isRouteBeingCalculated()) { FailSafeFuntions.restoreRoutingMode(this); } mapLayers.createLayers(mapView); if (!settings.isLastKnownMapLocation()) { // show first time when application ran net.osmand.Location location = app.getLocationProvider().getFirstTimeRunDefaultLocation(); if (location != null) { mapView.setLatLon(location.getLatitude(), location.getLongitude()); mapView.setZoom(14); } } addDialogProvider(mapActions); OsmandPlugin.onMapActivityCreate(this); if (lockView != null) { ((FrameLayout) mapView.getParent()).addView(lockView); } }
public void announceVisibleLocations() { Location lastKnownLocation = app.getRoutingHelper().getLastProjection(); if (lastKnownLocation != null && app.getRoutingHelper().isFollowingMode()) { for (int type = 0; type < locationPoints.size(); type++) { int currentRoute = route.getCurrentRoute(); List<LocationPointWrapper> approachPoints = new ArrayList<LocationPointWrapper>(); List<LocationPointWrapper> announcePoints = new ArrayList<LocationPointWrapper>(); List<LocationPointWrapper> lp = locationPoints.get(type); if (lp != null) { int kIterator = pointsProgress.get(type); while (kIterator < lp.size() && lp.get(kIterator).routeIndex < currentRoute) { kIterator++; } pointsProgress.set(type, kIterator); while (kIterator < lp.size()) { LocationPointWrapper lwp = lp.get(kIterator); if (route.getDistanceToPoint(lwp.routeIndex) > LONG_ANNOUNCE_RADIUS * 2) { break; } LocationPoint point = lwp.point; double d1 = Math.max( 0.0, MapUtils.getDistance( lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), point.getLatitude(), point.getLongitude()) - lwp.getDeviationDistance()); Integer state = locationPointsStates.get(point); if (state != null && state.intValue() == ANNOUNCED_ONCE && getVoiceRouter() .isDistanceLess(lastKnownLocation.getSpeed(), d1, SHORT_ANNOUNCE_RADIUS, 0f)) { locationPointsStates.put(point, ANNOUNCED_DONE); announcePoints.add(lwp); } else if (type != ALARMS && (state == null || state == NOT_ANNOUNCED) && getVoiceRouter() .isDistanceLess(lastKnownLocation.getSpeed(), d1, LONG_ANNOUNCE_RADIUS, 0f)) { locationPointsStates.put(point, ANNOUNCED_ONCE); approachPoints.add(lwp); } else if (type == ALARMS && (state == null || state == NOT_ANNOUNCED) && getVoiceRouter() .isDistanceLess(lastKnownLocation.getSpeed(), d1, ALARMS_ANNOUNCE_RADIUS, 0f)) { locationPointsStates.put(point, ANNOUNCED_ONCE); approachPoints.add(lwp); } kIterator++; } if (!announcePoints.isEmpty()) { if (announcePoints.size() > ANNOUNCE_POI_LIMIT) { announcePoints = announcePoints.subList(0, ANNOUNCE_POI_LIMIT); } if (type == WAYPOINTS) { getVoiceRouter().announceWaypoint(announcePoints); } else if (type == POI) { getVoiceRouter().announcePoi(announcePoints); } else if (type == ALARMS) { // nothing to announce } else if (type == FAVORITES) { getVoiceRouter().announceFavorite(announcePoints); } } if (!approachPoints.isEmpty()) { if (approachPoints.size() > APPROACH_POI_LIMIT) { approachPoints = approachPoints.subList(0, APPROACH_POI_LIMIT); } if (type == WAYPOINTS) { getVoiceRouter().approachWaypoint(lastKnownLocation, approachPoints); } else if (type == POI) { getVoiceRouter().approachPoi(lastKnownLocation, approachPoints); } else if (type == ALARMS) { EnumSet<AlarmInfoType> ait = EnumSet.noneOf(AlarmInfoType.class); for (LocationPointWrapper pw : approachPoints) { ait.add(((AlarmInfo) pw.point).getType()); } for (AlarmInfoType t : ait) { app.getRoutingHelper().getVoiceRouter().announceAlarm(t); } } else if (type == FAVORITES) { getVoiceRouter().approachFavorite(lastKnownLocation, approachPoints); } } } } } }
public boolean updateInfo(DrawSettings drawSettings) { boolean visible = false; int locimminent = -1; int[] loclanes = null; int dist = 0; // TurnType primary = null; if ((rh == null || !rh.isFollowingMode()) && trackingUtilities.isMapLinkedToLocation() && settings.SHOW_LANES.get()) { RouteDataObject ro = locationProvider.getLastKnownRouteSegment(); Location lp = locationProvider.getLastKnownLocation(); if (ro != null) { float degree = lp == null || !lp.hasBearing() ? 0 : lp.getBearing(); loclanes = RouteResultPreparation.parseTurnLanes(ro, degree / 180 * Math.PI); if (loclanes == null) { loclanes = RouteResultPreparation.parseLanes(ro, degree / 180 * Math.PI); } } } else if (rh != null && rh.isRouteCalculated()) { if (rh.isFollowingMode() && settings.SHOW_LANES.get()) { NextDirectionInfo r = rh.getNextRouteDirectionInfo(new NextDirectionInfo(), false); if (r != null && r.directionInfo != null && r.directionInfo.getTurnType() != null) { loclanes = r.directionInfo.getTurnType().getLanes(); // primary = r.directionInfo.getTurnType(); locimminent = r.imminent; // Do not show too far if ((r.distanceTo > 800 && r.directionInfo.getTurnType().isSkipToSpeak()) || r.distanceTo > 1200) { loclanes = null; } dist = r.distanceTo; } } else { int di = MapRouteInfoControl.getDirectionInfo(); if (di >= 0 && MapRouteInfoControl.isControlVisible() && di < rh.getRouteDirections().size()) { RouteDirectionInfo next = rh.getRouteDirections().get(di); if (next != null) { loclanes = next.getTurnType().getLanes(); // primary = next.getTurnType(); } } } } visible = loclanes != null && loclanes.length > 0; if (visible) { if (!Arrays.equals(lanesDrawable.lanes, loclanes) || (locimminent == 0) != lanesDrawable.imminent) { lanesDrawable.imminent = locimminent == 0; lanesDrawable.lanes = loclanes; lanesDrawable.updateBounds(); lanesView.setImageDrawable(null); lanesView.setImageDrawable(lanesDrawable); lanesView.requestLayout(); lanesView.invalidate(); } if (distChanged(dist, this.dist)) { this.dist = dist; if (dist == 0) { lanesShadowText.setText(""); lanesText.setText(""); } else { lanesShadowText.setText(OsmAndFormatter.getFormattedDistance(dist, app)); lanesText.setText(OsmAndFormatter.getFormattedDistance(dist, app)); } lanesShadowText.invalidate(); lanesText.invalidate(); } } updateVisibility(lanesShadowText, visible && shadowRadius > 0); updateVisibility(lanesText, visible); updateVisibility(lanesView, visible); updateVisibility(centerInfo, visible || progress.getVisibility() == View.VISIBLE); return true; }
/** * Updates status of voice guidance * * @param currentLocation */ protected void updateStatus(Location currentLocation) { // Directly after turn: goAhead (dist), unless: // < PREPARE_LONG_DISTANCE (3000m): playPrepareTurn // < PREPARE_DISTANCE (1500m): playPrepareTurn // < TURN_IN_DISTANCE (300m or 25sec): playMakeTurnIn // < TURN_DISTANCE (60m or 5sec): playMakeTurn float speed = DEFAULT_SPEED; if (currentLocation != null && currentLocation.hasSpeed()) { speed = Math.max(currentLocation.getSpeed(), speed); } NextDirectionInfo nextInfo = router.getNextRouteDirectionInfo(new NextDirectionInfo(), true); // after last turn say: if (nextInfo == null || nextInfo.directionInfo == null || nextInfo.directionInfo.distance == 0) { // if(currentStatus <= STATUS_UNKNOWN && currentDirection > 0){ This caused this prompt to be // suppressed when coming back from a if (currentStatus <= STATUS_UNKNOWN) { if (playGoAheadToDestination()) { currentStatus = STATUS_TOLD; playGoAheadDist = 0; } } return; } if (nextInfo.intermediatePoint) { if (currentStatus <= STATUS_UNKNOWN) { if (playGoAheadToIntermediate()) { currentStatus = STATUS_TOLD; playGoAheadDist = 0; } } return; } int dist = nextInfo.distanceTo; RouteDirectionInfo next = nextInfo.directionInfo; // if routing is changed update status to unknown if (next != nextRouteDirection) { nextRouteDirection = next; currentStatus = STATUS_UNKNOWN; playGoAheadDist = 0; } if (dist == 0 || currentStatus == STATUS_TOLD) { // nothing said possibly that's wrong case we should say before that // however it should be checked manually ? return; } // say how much to go if there is next turn is a bit far if (currentStatus == STATUS_UNKNOWN) { if (!isDistanceLess(speed, dist, TURN_IN_DISTANCE * 1.3)) { playGoAheadDist = dist - 80; } // say long distance message only for long distances > 10 km // if (dist >= PREPARE_LONG_DISTANCE && !isDistanceLess(speed, dist, PREPARE_LONG_DISTANCE)) { if (dist > PREPARE_LONG_DISTANCE + 300) { nextStatusAfter(STATUS_UNKNOWN); } else if (dist > PREPARE_DISTANCE + 300) { // say prepare message if it is far enough and don't say preare long distance nextStatusAfter(STATUS_LONG_PREPARE); } else { // don't say even prepare message nextStatusAfter(STATUS_PREPARE); } } NextDirectionInfo nextNextInfo = router.getNextRouteDirectionInfoAfter(nextInfo, new NextDirectionInfo(), true); if (statusNotPassed(STATUS_TURN) && isDistanceLess(speed, dist, TURN_DISTANCE, TURN_DEFAULT_SPEED)) { if (next.distance < TURN_IN_DISTANCE_END && nextNextInfo != null) { playMakeTurn(next, nextNextInfo.directionInfo); } else { playMakeTurn(next, null); } nextStatusAfter(STATUS_TURN); } else if (statusNotPassed(STATUS_TURN_IN) && isDistanceLess(speed, dist, TURN_IN_DISTANCE)) { if (dist >= TURN_IN_DISTANCE_END) { if ((isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) && nextNextInfo != null) { playMakeTurnIn(next, dist, nextNextInfo.directionInfo); } else { playMakeTurnIn(next, dist, null); } } nextStatusAfter(STATUS_TURN_IN); // } else if (statusNotPassed(STATUS_PREPARE) && isDistanceLess(speed, dist, // PREPARE_DISTANCE)) { } else if (statusNotPassed(STATUS_PREPARE) && (dist <= PREPARE_DISTANCE)) { if (dist >= PREPARE_DISTANCE_END) { if (next.getTurnType().keepLeft() || next.getTurnType().keepRight()) { // do not play prepare for keep left/right } else { playPrepareTurn(next, dist); } } nextStatusAfter(STATUS_PREPARE); // } else if (statusNotPassed(STATUS_LONG_PREPARE) && isDistanceLess(speed, dist, // PREPARE_LONG_DISTANCE)){ } else if (statusNotPassed(STATUS_LONG_PREPARE) && (dist <= PREPARE_LONG_DISTANCE)) { if (dist >= PREPARE_LONG_DISTANCE_END) { playPrepareTurn(next, dist); } nextStatusAfter(STATUS_LONG_PREPARE); } else if (statusNotPassed(STATUS_UNKNOWN)) { // strange how we get here but nextStatusAfter(STATUS_UNKNOWN); } else if (statusNotPassed(STATUS_TURN_IN) && dist < playGoAheadDist) { playGoAheadDist = 0; playGoAhead(dist); } }
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; }