Update routing helper

This commit is contained in:
Victor Shcherb 2012-08-30 21:19:50 +02:00
parent 20da399a5d
commit a0055e2f08
6 changed files with 145 additions and 125 deletions

View file

@ -210,7 +210,7 @@ public class NavigationService extends Service implements LocationListener {
liveMonitoringHelper.insertData(location.getLatitude(), location.getLongitude(), location.getAltitude(),
location.getSpeed(), location.getAccuracy(), locationTime, settings);
if(routingHelper.isFollowingMode()){
routingHelper.setCurrentLocation(location);
routingHelper.setCurrentLocation(location, false);
}
}

View file

@ -573,6 +573,13 @@ public class OsmandSettings {
public final OsmandPreference<RouteService> ROUTER_SERVICE =
new EnumIntPreference<RouteService>("router_service", RouteService.OSMAND, RouteService.values()).makeProfile();
public final CommonPreference<Boolean> SNAP_TO_ROAD = new BooleanPreference("snap_to_road", true).makeProfile().cache();
{
SNAP_TO_ROAD.setModeDefaultValue(ApplicationMode.CAR, true);
SNAP_TO_ROAD.setModeDefaultValue(ApplicationMode.BICYCLE, false);
SNAP_TO_ROAD.setModeDefaultValue(ApplicationMode.PEDESTRIAN, false);
}
public final CommonPreference<Boolean> LEFT_SIDE_NAVIGATION = new BooleanPreference("left_side_navigation", false).makeGlobal();

View file

@ -267,7 +267,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
// if destination point was changed try to recalculate route
if (routingHelper.isFollowingMode() && !Algoritms.objectEquals(settings.getPointToNavigate(), routingHelper.getFinalLocation())) {
routingHelper.setFinalAndCurrentLocation(settings.getPointToNavigate(), routingHelper.getCurrentLocation(), routingHelper.getCurrentGPXRoute());
routingHelper.setFinalAndCurrentLocation(settings.getPointToNavigate(), getLastKnownLocation(), routingHelper.getCurrentGPXRoute());
}
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
@ -621,7 +621,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
final LatLon point = settings.getPointToNavigate();
if (point != null) {
if (routingHelper.isRouteCalculated()) {
routingHelper.getVoiceRouter().announceCurrentDirection(routingHelper.getLastFixedLocation());
routingHelper.getVoiceRouter().announceCurrentDirection(getLastKnownLocation());
} else {
AccessibleToast.makeText(this, getNavigationHint(point), Toast.LENGTH_LONG).show();
}
@ -738,8 +738,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
// For network/gps it's bad way (not accurate). It's widely used for testing purposes
// possibly keep using only for emulator case
PointLocationLayer locationLayer = mapLayers.getLocationLayer();
if (isRunningOnEmulator()
&& locationLayer.getLastKnownLocation() != null) {
if (locationLayer.getLastKnownLocation() != null) {
if (locationLayer.getLastKnownLocation().distanceTo(location) > 3) {
float d = location.distanceTo(locationLayer.getLastKnownLocation());
long time = location.getTime() - locationLayer.getLastKnownLocation().getTime();
@ -758,7 +757,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
}
if(locationLayer.getLastKnownLocation() != null && !location.hasBearing()){
if(locationLayer.getLastKnownLocation().distanceTo(location) > 10 && !isRunningOnEmulator()){
// very innacurate?
// very innacurate
// location.setBearing(locationLayer.getLastKnownLocation().bearingTo(location));
}
}
@ -772,6 +771,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
if (Log.isLoggable(LogUtil.TAG, Log.DEBUG)) {
Log.d(LogUtil.TAG, "Location changed " + location.getProvider()); //$NON-NLS-1$
}
// 1. Logging services
if (location != null) {
// use because there is a bug on some devices with location.getTime()
long locationTime = System.currentTimeMillis();
@ -788,18 +788,25 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
}
}
}
if(location != null && isRunningOnEmulator()) {
// only for emulator
updateSpeedBearingEmulator(location);
}
// 2. accessibility routing
navigationInfo.setLocation(location);
// 3. routing
boolean enableSensorNavigation = routingHelper.isFollowingMode() && settings.USE_COMPASS_IN_NAVIGATION.get() ? location == null
|| !location.hasBearing() : false;
registerUnregisterSensor(location, enableSensorNavigation);
Location updatedLocation = location;
if (routingHelper.isFollowingMode()) {
if (location == null || !location.hasAccuracy() || location.getAccuracy() < ACCURACY_FOR_GPX_AND_ROUTING) {
// Update routing position and get location for sticking mode
Location updatedLocation = routingHelper.setCurrentLocation(location);
updatedLocation = routingHelper.setCurrentLocation(location, settings.SNAP_TO_ROAD.get());
if(!routingHelper.isFollowingMode()) {
// finished
Message msg = Message.obtain(uiHandler, new Runnable() {
@ -811,7 +818,6 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
});
uiHandler.sendMessage(msg);
}
location = updatedLocation;
// Check with delay that gps location is not lost
if (location != null && routingHelper.getLeftDistance() > 0) {
final long fixTime = location.getTime();
@ -834,60 +840,67 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
}
}
}
mapLayers.getLocationLayer().setLastKnownLocation(location);
navigationInfo.setLocation(location);
// Update information
mapLayers.getLocationLayer().setLastKnownLocation(updatedLocation);
if (location != null) {
long now = System.currentTimeMillis();
if (isMapLinkedToLocation()) {
if (settings.AUTO_ZOOM_MAP.get() && location.hasSpeed()) {
float zdelta = defineZoomFromSpeed(location.getSpeed());
if (Math.abs(zdelta) >= OsmandMapTileView.ZOOM_DELTA_1) {
// prevent ui hysteresis (check time interval for autozoom)
if (zdelta >= 2) {
// decrease a bit
zdelta -= 3 * OsmandMapTileView.ZOOM_DELTA_1;
} else if (zdelta <= -2) {
// decrease a bit
zdelta += 3 * OsmandMapTileView.ZOOM_DELTA_1;
}
if (now - lastTimeAutoZooming > 4500) {
lastTimeAutoZooming = now;
mapView.setZoom(mapView.getFloatZoom() + zdelta);
// mapView.getAnimatedDraggingThread().startZooming(mapView.getFloatZoom() + zdelta, false);
}
}
}
int currentMapRotation = settings.ROTATE_MAP.get();
if (currentMapRotation == OsmandSettings.ROTATE_MAP_BEARING) {
if (location.hasBearing()) {
mapView.setRotate(-location.getBearing());
} else if (routingHelper.isFollowingMode() && settings.USE_COMPASS_IN_NAVIGATION.get()) {
if (Math.abs(MapUtils.degreesDiff(mapView.getRotate(), -previousSensorValue)) > 15
&& now - lastTimeSensorRotation > 1500) {
lastTimeSensorRotation = now;
mapView.setRotate(-previousSensorValue);
}
}
}
mapView.setLatLon(location.getLatitude(), location.getLongitude());
} else {
if (!mapLayers.getMapInfoLayer().getBackToLocation().isEnabled()) {
mapLayers.getMapInfoLayer().getBackToLocation().setEnabled(true);
}
if (settings.AUTO_FOLLOW_ROUTE.get() > 0 && routingHelper.isFollowingMode() && !uiHandler.hasMessages(AUTO_FOLLOW_MSG_ID)) {
backToLocationWithDelay(1);
}
}
updateAutoMapViewConfiguration(updatedLocation);
} else {
if (mapLayers.getMapInfoLayer().getBackToLocation().isEnabled()) {
mapLayers.getMapInfoLayer().getBackToLocation().setEnabled(false);
}
}
// When location is changed we need to refresh map in order to show movement!
mapView.refreshMap();
}
private void updateAutoMapViewConfiguration(Location location) {
long now = System.currentTimeMillis();
if (isMapLinkedToLocation()) {
if (settings.AUTO_ZOOM_MAP.get() && location.hasSpeed()) {
float zdelta = defineZoomFromSpeed(location.getSpeed());
if (Math.abs(zdelta) >= OsmandMapTileView.ZOOM_DELTA_1) {
// prevent ui hysteresis (check time interval for autozoom)
if (zdelta >= 2) {
// decrease a bit
zdelta -= 3 * OsmandMapTileView.ZOOM_DELTA_1;
} else if (zdelta <= -2) {
// decrease a bit
zdelta += 3 * OsmandMapTileView.ZOOM_DELTA_1;
}
if (now - lastTimeAutoZooming > 4500) {
lastTimeAutoZooming = now;
mapView.setZoom(mapView.getFloatZoom() + zdelta);
// mapView.getAnimatedDraggingThread().startZooming(mapView.getFloatZoom() + zdelta, false);
}
}
}
int currentMapRotation = settings.ROTATE_MAP.get();
if (currentMapRotation == OsmandSettings.ROTATE_MAP_BEARING) {
if (location.hasBearing()) {
mapView.setRotate(-location.getBearing());
} else if (routingHelper.isFollowingMode() && settings.USE_COMPASS_IN_NAVIGATION.get()) {
if (previousSensorValue != 0 && Math.abs(MapUtils.degreesDiff(mapView.getRotate(), -previousSensorValue)) > 15) {
if(now - lastTimeSensorRotation > 1500 && now - lastTimeSensorRotation < 15000) {
lastTimeSensorRotation = now;
mapView.setRotate(-previousSensorValue);
}
}
}
}
mapView.setLatLon(location.getLatitude(), location.getLongitude());
} else {
if (!mapLayers.getMapInfoLayer().getBackToLocation().isEnabled()) {
mapLayers.getMapInfoLayer().getBackToLocation().setEnabled(true);
}
if (settings.AUTO_FOLLOW_ROUTE.get() > 0 && routingHelper.isFollowingMode() && !uiHandler.hasMessages(AUTO_FOLLOW_MSG_ID)) {
backToLocationWithDelay(1);
}
}
}
public float defineZoomFromSpeed(float speed) {
if (speed < 7f / 3.6) {
return 0;
@ -915,7 +928,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
} else {
settings.clearPointToNavigate();
}
routingHelper.setFinalAndCurrentLocation(point, routingHelper.getCurrentLocation(), routingHelper.getCurrentGPXRoute());
routingHelper.setFinalAndCurrentLocation(point, getLastKnownLocation(), routingHelper.getCurrentGPXRoute());
mapLayers.getNavigationLayer().setPointToNavigate(point);
}

View file

@ -910,7 +910,7 @@ public class MapActivityActions implements DialogProvider {
public boolean onClick(MenuItem item) {
if (mapActivity.getMapLayers().getNavigationLayer().getPointToNavigate() != null) {
if (routingHelper.isRouteCalculated() || routingHelper.isFollowingMode() || routingHelper.isRouteBeingCalculated()) {
routingHelper.setFinalAndCurrentLocation(null, routingHelper.getCurrentLocation(), routingHelper.getCurrentGPXRoute());
routingHelper.setFinalAndCurrentLocation(null, mapActivity.getLastKnownLocation(), routingHelper.getCurrentGPXRoute());
// restore default mode
boolean changed = settings.APPLICATION_MODE.set(settings.PREV_APPLICATION_MODE.get());
mapActivity.updateApplicationModeSettings();

View file

@ -49,7 +49,9 @@ public class RoutingHelper {
private RouteCalculationResult route = new RouteCalculationResult("");
private LatLon finalLocation;
private Location lastProjection;
private Location lastFixedLocation;
private RouteRecalculationThread currentRunningJob;
private long lastTimeEvaluatedRoute = 0;
private int evalWaitInterval = 3000;
@ -64,6 +66,7 @@ public class RoutingHelper {
private boolean makeUturnWhenPossible = false;
private long makeUTwpDetected = 0;
public boolean makeUturnWhenPossible() {
return makeUturnWhenPossible;
}
@ -93,7 +96,7 @@ public class RoutingHelper {
clearCurrentRoute(finalLocation);
currentGPXRoute = gpxRoute;
// to update route
setCurrentLocation(currentLocation);
setCurrentLocation(currentLocation, false);
}
@ -117,7 +120,7 @@ public class RoutingHelper {
settings.FOLLOW_THE_ROUTE.set(false);
settings.FOLLOW_THE_GPX_ROUTE.set(null);
// clear last fixed location
this.lastFixedLocation = null;
this.lastProjection = null;
this.isFollowingMode = false;
}
}
@ -144,10 +147,6 @@ public class RoutingHelper {
return finalLocation;
}
public Location getLastFixedLocation() {
return lastFixedLocation;
}
public boolean isRouteCalculated(){
return route.isCalculated();
}
@ -156,8 +155,8 @@ public class RoutingHelper {
return voiceRouter;
}
public Location getCurrentLocation() {
return lastFixedLocation;
public Location getLastProjection(){
return lastProjection;
}
public void addListener(IRouteInformationListener l){
@ -169,22 +168,22 @@ public class RoutingHelper {
}
public Location setCurrentLocation(Location currentLocation) {
public Location setCurrentLocation(Location currentLocation, boolean returnUpdatedLocation ) {
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 {
float posTolerance = POSITION_TOLERANCE;
if(currentLocation.hasAccuracy()) {
posTolerance = POSITION_TOLERANCE / 2 + currentLocation.getAccuracy();
}
// 1. Update current route position status according to latest received location
boolean finished = updateCurrentRouteStatus(currentLocation, posTolerance);
if (finished) {
@ -221,46 +220,48 @@ public class RoutingHelper {
// calculate projection of current location
if (currentRoute > 0) {
double dist = getOrthogonalDistance(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute));
double projectDist = mode == ApplicationMode.CAR ? posTolerance : posTolerance / 2;
locationProjection = new Location(locationProjection);
if (dist < projectDist) {
Location nextLocation = routeNodes.get(currentRoute);
LatLon project = getProject(currentLocation, routeNodes.get(currentRoute - 1), routeNodes.get(currentRoute));
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
if (locationProjection.hasBearing()) {
float bearingTo = locationProjection.bearingTo(nextLocation);
locationProjection.setBearing(bearingTo);
}
locationProjection.setLatitude(project.getLatitude());
locationProjection.setLongitude(project.getLongitude());
// we need to update bearing too
if (locationProjection.hasBearing()) {
float bearingTo = locationProjection.bearingTo(nextLocation);
locationProjection.setBearing(bearingTo);
}
}
}
lastFixedLocation = locationProjection;
lastFixedLocation = currentLocation;
lastProjection = locationProjection;
}
if (calculateRoute) {
recalculateRouteInBackground(lastFixedLocation, finalLocation, currentGPXRoute,
recalculateRouteInBackground(currentLocation, finalLocation, currentGPXRoute,
route.isCalculated()? route : null);
}
return locationProjection;
double projectDist = mode == ApplicationMode.CAR ? posTolerance : posTolerance / 2;
if(returnUpdatedLocation && currentLocation.distanceTo(locationProjection) < projectDist) {
return locationProjection;
} else {
return currentLocation;
}
}
private double getOrthogonalDistance(Location loc, Location from, Location to) {
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());
}
private LatLon getProject(Location loc, Location from, Location to) {
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 int lookAheadFindMinOrthogonalDistance(Location currentLocation, List<Location> routeNodes, int currentRoute, int iterations) {
private static int lookAheadFindMinOrthogonalDistance(Location currentLocation, List<Location> routeNodes, int currentRoute, int iterations) {
double newDist;
double dist = Double.POSITIVE_INFINITY;
int index = currentRoute;
@ -353,9 +354,8 @@ public class RoutingHelper {
return makeUturnWhenPossible;
}
boolean makeUturnWhenPossible = false;
if (currentLocation.hasBearing() || lastFixedLocation != null) {
float bearingMotion = currentLocation.hasBearing() ? currentLocation.getBearing() : lastFixedLocation
.bearingTo(currentLocation);
if (currentLocation.hasBearing()) {
float bearingMotion = currentLocation.getBearing() ;
Location nextRoutePosition = route.getNextRouteLocation();
float bearingToRoute = currentLocation.bearingTo(nextRoutePosition);
double diff = MapUtils.degreesDiff(bearingMotion, bearingToRoute);
@ -387,12 +387,12 @@ public class RoutingHelper {
* the difference is more than 90 degrees
*/
public boolean checkWrongMovementDirection(Location currentLocation, Location nextRouteLocation) {
if ((currentLocation.hasBearing() || lastFixedLocation != null) && nextRouteLocation!= null) {
float bearingMotion = currentLocation.hasBearing() ? currentLocation.getBearing() : lastFixedLocation
.bearingTo(currentLocation);
// 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);
// 6. Suppress turn prompt if prescribed direction of motion is between 45 and 135 degrees off
if (Math.abs(diff) > 60f) {
return true;
}
@ -404,24 +404,24 @@ public class RoutingHelper {
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;
Location prev = res.getNextRouteLocation();
if (prev != null) {
int i = 1;
while (res.getNextRouteLocation(i) != null && prev.distanceTo(start) < POSITION_TOLERANCE) {
prev = res.getNextRouteLocation(i);
i++;
}
// This check could be valid only for Online/GPX services
// because offline routing is aware of route directions
wrongMovementDirection = checkWrongMovementDirection(start, prev);
// 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);
List<Location> routeNodes = res.getImmutableLocations();
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);
}
}
}
@ -466,9 +466,9 @@ public class RoutingHelper {
}
public synchronized NextDirectionInfo getNextRouteDirectionInfo(NextDirectionInfo info, boolean toSpeak){
NextDirectionInfo i = route.getNextRouteDirectionInfo(info, lastFixedLocation, toSpeak);
NextDirectionInfo i = route.getNextRouteDirectionInfo(info, lastProjection, toSpeak);
if(i != null) {
i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastFixedLocation);
i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastProjection);
}
return i;
}
@ -476,9 +476,9 @@ public class RoutingHelper {
public synchronized AlarmInfo getMostImportantAlarm(MetricsConstants mc, boolean showCameras){
float mxspeed = route.getCurrentMaxSpeed();
AlarmInfo speedAlarm = null;
if(mxspeed != 0 && lastFixedLocation != null && lastFixedLocation.hasSpeed()) {
if(mxspeed != 0 && lastProjection != null && lastProjection.hasSpeed()) {
float delta = 5f/3.6f;
if(lastFixedLocation.getSpeed() > mxspeed + delta) {
if(lastProjection.getSpeed() > mxspeed + delta) {
int speed;
if(mc == MetricsConstants.KILOMETERS_AND_METERS) {
speed = Math.round(mxspeed * 3.6f);
@ -488,7 +488,7 @@ public class RoutingHelper {
speedAlarm = AlarmInfo.createSpeedLimit(speed);
}
}
return route.getMostImportantAlarm(lastFixedLocation, speedAlarm, showCameras);
return route.getMostImportantAlarm(lastProjection, speedAlarm, showCameras);
}
public String formatStreetName(String name, String ref) {

View file

@ -3,7 +3,6 @@ package net.osmand.plus.views;
import java.util.ArrayList;
import java.util.List;
import net.osmand.osm.MapUtils;
import net.osmand.plus.R;
import net.osmand.plus.routing.RoutingHelper;
import android.graphics.Canvas;
@ -66,8 +65,9 @@ public class RouteLayer extends OsmandMapLayer {
}
int w = view.getWidth();
int h = view.getHeight();
if(helper.getCurrentLocation() != null &&
view.isPointOnTheRotatedMap(helper.getCurrentLocation().getLatitude(), helper.getCurrentLocation().getLongitude())){
Location lastProjection = helper.getLastProjection();
if(lastProjection != null &&
view.isPointOnTheRotatedMap(lastProjection.getLatitude(), lastProjection.getLongitude())){
boundsRect = new Rect(-w / 2, -h, 3 * w / 2, h);
} else {
boundsRect = new Rect(0, 0, w, h);
@ -102,11 +102,11 @@ public class RouteLayer extends OsmandMapLayer {
public synchronized void fillLocationsToShow(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) {
points.clear();
boolean previousVisible = false;
Location lastFixedLocation = helper.getLastFixedLocation();
if (lastFixedLocation != null) {
if (leftLongitude <= lastFixedLocation.getLongitude() && lastFixedLocation.getLongitude() <= rightLongitude
&& bottomLatitude <= lastFixedLocation.getLatitude() && lastFixedLocation.getLatitude() <= topLatitude) {
points.add(lastFixedLocation);
Location lastProjection = helper.getLastProjection();
if (lastProjection != null) {
if (leftLongitude <= lastProjection.getLongitude() && lastProjection.getLongitude() <= rightLongitude
&& bottomLatitude <= lastProjection.getLatitude() && lastProjection.getLatitude() <= topLatitude) {
points.add(lastProjection);
previousVisible = true;
}
}
@ -119,8 +119,8 @@ public class RouteLayer extends OsmandMapLayer {
if (!previousVisible) {
if (i > 0) {
points.add(0, routeNodes.get(i - 1));
} else if (lastFixedLocation != null) {
points.add(0, lastFixedLocation);
} else if (lastProjection != null) {
points.add(0, lastProjection);
}
}
previousVisible = true;