diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index 3771acda41..2f43176e1e 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -16,9 +16,9 @@ public class ToDoConstants { // TODO ANDROID - // 61. Provide route information for YOURS (calclate turns/angle/expected time). - // Fix some missing turns in CloudMade (for secondary roads wo name). Add them (if dist to prev/next turn > 150m) [dacha] - // 60. Audio guidance for routing + // 61. Provide route information for YOURS (calclate turns/angle/expected time) [done] + // Fix some missing turns in CloudMade (for secondary roads wo name). Add them (if dist to prev/next turn > 150m) [dacha] ! + // 60. Audio guidance for routing ! // 43. Enable poi filter by name // 58. Upload/Download zip-index from site & unzip them on phone @@ -29,15 +29,14 @@ public class ToDoConstants { // 66. Transport routing (show next stop, total distance, show stop get out) (?). // 64. Traffic information (?) - // 65. Intermediate points (?) + // 65. Intermediate points - for better control routing, to avoid traffic jam ...(?) // 40. Support simple vector road rendering (require new index file) (?) // 63. Support simple offline routing(require new index file) (?) // FIXME BUGS Android - // 1. Fix bugs with test data (bug with follow turn / left time / add turn) - // 2. Improvement : Show stops in the transport route - // 3. Pinch zoom + // 1. Improvement : Show stops in the transport route + // 2. Pinch zoom !!! // TODO swing // 9. Fix issues with big files (such as netherlands) - save memory (!) - very slow due to transport index ! diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 9203893c65..ed3a2a92ca 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:debuggable="true" android:name=".activities.OsmandApplication" android:description="@string/app_description"> diff --git a/OsmAnd/res/values-ru-rRU/strings.xml b/OsmAnd/res/values-ru-rRU/strings.xml index 39981fdf6d..8f08cdfddc 100644 --- a/OsmAnd/res/values-ru-rRU/strings.xml +++ b/OsmAnd/res/values-ru-rRU/strings.xml @@ -1,5 +1,13 @@ + Поверните направо и двигайтесь + Поверните резко направо и двигайтесь + Поверните направо и двигайтесь + Поверните налево и двигайтесь + Поверните резко налево и двигайтесь + Поверните налево и двигайтесь + Выполните разворот и двигайтесь + Двигайтесь Продолжить Загрузить индексы Спасибо за то, что выбрали OsmAnd. \n @@ -102,10 +110,10 @@ Загрузка POI Ошибка во время сохранения пути в gpx - Ошибка прокладки маршрута : + Ошибка прокладки маршрута Ошибка во время прокладки маршрута Пустой путь рассчитан - Проложен новый путь, расстояние : + Проложен новый путь, расстояние Вы прибыли в пункт назначения Координаты неправильные Вернуться к OsmAnd карте @@ -114,7 +122,7 @@ Чтение индексов... Предыдущий запуск приложения был неудачен. Лог файл в {0}. Пожалуйста откройте баг и присоедините лог файл. Сохранение gpx путей на SD... - Окончен : + Окончен Перезагрузить индексы с SD Обновить индексы Загрузить индекс файлы из интернета diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 057e6b5e66..a986f9e35e 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,13 @@ + Turn right and go + Turn sharply right and go + Turn slightly right and go + Turn left and go + Turn sharply left and go + Turn slightly left and go + Make U-turn and go + Head Continue Download indexes Thank you for choosing OsmAnd. \nTo be able to use all features of application you need index files, which you can download (Settings/Data) or prepare by yourself. After that you can use : search by address, search POI, search transport. @@ -101,10 +109,10 @@ See osmand.googlecode.com. Loading POI Error occurred while saving gpx - Error calculating route : + Error calculating route Error occurred while calculating route Empty route is calculated - New route is calculated, distance : + New route is calculated, distance You arrived at destination point Locations are invalid Go back to OsmAnd map @@ -113,7 +121,7 @@ See osmand.googlecode.com. Reading indices... Previous application run was crashed. Log file is at {0}. Please raise the issue and attach log file. Saving gpx tracks to SD... - Finished : + Finished Reload data indexes from SD Reload indexes Download indexes from internet diff --git a/OsmAnd/src/com/osmand/ProgressDialogImplementation.java b/OsmAnd/src/com/osmand/ProgressDialogImplementation.java index 971b0f21d7..a5baefa6f3 100644 --- a/OsmAnd/src/com/osmand/ProgressDialogImplementation.java +++ b/OsmAnd/src/com/osmand/ProgressDialogImplementation.java @@ -108,7 +108,7 @@ public class ProgressDialogImplementation implements IProgress { @Override public void finishTask() { if (taskName != null) { - message = context.getResources().getString(R.string.finished_task) + taskName; + message = context.getResources().getString(R.string.finished_task) +" : "+ taskName; //$NON-NLS-1$ mViewUpdateHandler.sendEmptyMessage(0); } work = -1; diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index 6dd89da660..4b2fed15d5 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -194,10 +194,10 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat savingTrackHelper = new SavingTrackHelper(this); - locationLayer.setAppMode(OsmandSettings.getApplicationMode(this)); + LatLon pointToNavigate = OsmandSettings.getPointToNavigate(this); - routingHelper.setAppMode(OsmandSettings.getApplicationMode(this)); + if(!Algoritms.objectEquals(routingHelper.getFinalLocation(), pointToNavigate)){ // there is no way how to clear mode. Only user can do : clear point to navigate, exit from app & set up new point. // that case help to not calculate route at all. @@ -566,6 +566,9 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat if(!OsmandSettings.isShowingViewAngle(this)){ locationLayer.setHeading(null); } + locationLayer.setAppMode(OsmandSettings.getApplicationMode(this)); + routingHelper.setAppMode(OsmandSettings.getApplicationMode(this)); + poiMapLayer.setFilter(OsmandSettings.getPoiFilterForMap(this)); mapView.setMapPosition(OsmandSettings.getPositionOnMap(this)); SharedPreferences prefs = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_READABLE); diff --git a/OsmAnd/src/com/osmand/activities/RouteProvider.java b/OsmAnd/src/com/osmand/activities/RouteProvider.java index c3b53387a9..2ec78574f0 100644 --- a/OsmAnd/src/com/osmand/activities/RouteProvider.java +++ b/OsmAnd/src/com/osmand/activities/RouteProvider.java @@ -21,13 +21,16 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import android.content.Context; import android.location.Location; import com.osmand.LogUtil; +import com.osmand.R; import com.osmand.OsmandSettings.ApplicationMode; import com.osmand.activities.RoutingHelper.RouteDirectionInfo; import com.osmand.activities.RoutingHelper.TurnType; import com.osmand.osm.LatLon; +import com.osmand.osm.MapUtils; public class RouteProvider { private static final org.apache.commons.logging.Log log = LogUtil.getLog(RouteProvider.class); @@ -49,7 +52,7 @@ public class RouteProvider { public static class RouteCalculationResult { private final List locations; - private final List directions; + private List directions; private final String errorMessage; private int[] listDistance = null; @@ -108,7 +111,7 @@ public class RouteProvider { } - public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode, RouteService type){ + public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode, RouteService type, Context ctx){ long time = System.currentTimeMillis(); if (start != null && end != null) { if(log.isInfoEnabled()){ @@ -118,8 +121,11 @@ public class RouteProvider { RouteCalculationResult res; if (type == RouteService.YOURS) { res = findYOURSRoute(start, end, mode); + addMissingTurnsToRoute(res, mode, ctx); } else { res = findCloudMadeRoute(start, end, mode); + // for test purpose + addMissingTurnsToRoute(res, mode, ctx); } if(log.isInfoEnabled() && res.locations != null){ log.info("Finding route contained " + res.locations.size() + " points for " + (System.currentTimeMillis() - time) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -135,6 +141,150 @@ public class RouteProvider { } return new RouteCalculationResult(null); } + + protected String getString(Context ctx, int resId){ + if(ctx == null){ + return ""; //$NON-NLS-1$ + } + return ctx.getString(resId); + } + + protected void addMissingTurnsToRoute(RouteCalculationResult res, ApplicationMode mode, Context ctx){ + if(!res.isCalculated()){ + return; + } + // speed m/s + float speed = 1.5f; + int minDistanceForTurn = 5; + if(mode == ApplicationMode.CAR){ + speed = 15.3f; + minDistanceForTurn = 25; + } else if(mode == ApplicationMode.BICYCLE){ + speed = 5.5f; + minDistanceForTurn = 12; + } + + + List directions = new ArrayList(); + int[] listDistance = res.getListDistance(); + List locations = res.getLocations(); + + + int previousLocation = 0; + int prevBearingLocation = 0; + RouteDirectionInfo previousInfo = new RouteDirectionInfo(); + previousInfo.turnType = TurnType.valueOf(TurnType.C); + previousInfo.routePointOffset = 0; + previousInfo.descriptionRoute = getString(ctx, R.string.route_head); + directions.add(previousInfo); + + int distForTurn = 0; + float previousBearing = 0; + int startTurnPoint = 0; + + + for (int i = 1; i < locations.size() - 1; i++) { + + Location next = locations.get(i + 1); + Location current = locations.get(i); + float bearing = current.bearingTo(next); + // try to get close to current location if possible + while(prevBearingLocation < i - 1){ + if(locations.get(prevBearingLocation + 1).distanceTo(current) > 70){ + prevBearingLocation ++; + } else { + break; + } + } + + if(distForTurn == 0){ + // measure only after turn + previousBearing = locations.get(prevBearingLocation).bearingTo(current); + startTurnPoint = i; + } + + TurnType type = null; + String description = null; + float delta = previousBearing - bearing; + while(delta < 0){ + delta += 360; + } + while(delta > 360){ + delta -= 360; + } + + distForTurn += locations.get(i).distanceTo(locations.get(i + 1)); + if (i < locations.size() - 1 && distForTurn < minDistanceForTurn) { + // For very smooth turn we try to accumulate whole distance + // simply skip that turn needed for situation + // 1) if you are going to have U-turn - not 2 left turns + // 2) if there is a small gap between roads (turn right and after 4m next turn left) - so the direction head + continue; + } + + + if(delta > 50 && delta < 310){ + + if(delta < 70){ + type = TurnType.valueOf(TurnType.TSLL); + description = getString(ctx, R.string.route_tsll); + } else if(delta < 110){ + type = TurnType.valueOf(TurnType.TL); + description = getString(ctx, R.string.route_tl); + } else if(delta < 125){ + type = TurnType.valueOf(TurnType.TSHL); + description = getString(ctx, R.string.route_tshl); + } else if(delta < 225){ + type = TurnType.valueOf(TurnType.TU); + description = getString(ctx, R.string.route_tu); + } else if(delta < 250){ + description = getString(ctx, R.string.route_tshr); + type = TurnType.valueOf(TurnType.TSHR); + } else if(delta < 290){ + description = getString(ctx, R.string.route_tr); + type = TurnType.valueOf(TurnType.TR); + } else { + description = getString(ctx, R.string.route_tslr); + type = TurnType.valueOf(TurnType.TSLR); + } + + // calculate for previousRoute + previousInfo.distance = listDistance[previousLocation]- listDistance[i]; + previousInfo.expectedTime = (int) (previousInfo.distance / speed); + previousInfo.descriptionRoute += " " + MapUtils.getFormattedDistance(previousInfo.distance); //$NON-NLS-1$ + + previousInfo = new RouteDirectionInfo(); + previousInfo.turnType = type; + previousInfo.turnType.setTurnAngle(360 - delta); + previousInfo.descriptionRoute = description; + previousInfo.routePointOffset = startTurnPoint; + directions.add(previousInfo); + previousLocation = startTurnPoint; + prevBearingLocation = i; // for bearing using current location + } + // clear dist for turn + distForTurn = 0; + } + + previousInfo.distance = listDistance[previousLocation]; + previousInfo.expectedTime = (int) (previousInfo.distance / speed); + previousInfo.descriptionRoute += " " + MapUtils.getFormattedDistance(previousInfo.distance); //$NON-NLS-1$ + + + + int sum = 0; + for (int i = directions.size() - 1; i >= 0; i--) { + directions.get(i).afterLeftTime = sum; + sum += directions.get(i).expectedTime; + } + + if(res.directions == null || res.directions.isEmpty()){ + res.directions = new ArrayList(directions); + } else { + // TODO try to add missing turns +// res.directions = new ArrayList(directions); + } + } protected RouteCalculationResult findYOURSRoute(Location start, LatLon end, ApplicationMode mode) throws MalformedURLException, IOException, diff --git a/OsmAnd/src/com/osmand/activities/RoutingHelper.java b/OsmAnd/src/com/osmand/activities/RoutingHelper.java index 313a7a7c37..e99bb7436c 100644 --- a/OsmAnd/src/com/osmand/activities/RoutingHelper.java +++ b/OsmAnd/src/com/osmand/activities/RoutingHelper.java @@ -215,6 +215,21 @@ public class RoutingHelper { updateCurrentRoute(currentRoute + 1); } } + + // 3.5 check that we already pass very sharp turn by missing one point (so our turn is sharper than expected) + // instead of that rule possible could be introduced another if the dist < 5m mark the location as already passed + if(currentRoute + 2 < routeNodes.size()){ + float bearing = routeNodes.get(currentRoute + 1).bearingTo(routeNodes.get(currentRoute + 2)); + float bearingMovement = currentLocation.bearingTo(routeNodes.get(currentRoute + 1)); + // only 15 degrees for that case because it wrong catches sharp turns + if(Math.abs(bearing - bearingMovement) > 165 && Math.abs(bearing - bearingMovement) < 195){ + if(log.isDebugEnabled()){ + log.debug("Processed point movement bearing 2 : "+bearingMovement +" bearing " + bearing); //$NON-NLS-1$ //$NON-NLS-2$ + } + updateCurrentRoute(currentRoute + 2); + } + } + // 4. evaluate distance to the route and reevaluate if needed if(currentRoute > 0){ float bearing = routeNodes.get(currentRoute - 1).bearingTo(routeNodes.get(currentRoute)); @@ -350,7 +365,7 @@ public class RoutingHelper { currentRunningJob = new Thread(new Runnable() { @Override public void run() { - RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode, service); + RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode, service, activity); synchronized (RoutingHelper.this) { if (res.isCalculated()) { setNewRoute(res); @@ -368,14 +383,14 @@ public class RoutingHelper { if (res.isCalculated()) { int[] dist = res.getListDistance(); int l = dist != null && dist.length > 0 ? dist[0] : 0; - showMessage(activity.getString(R.string.new_route_calculated_dist) + MapUtils.getFormattedDistance(l)); + showMessage(activity.getString(R.string.new_route_calculated_dist) +" : "+ MapUtils.getFormattedDistance(l)); //$NON-NLS-1$ if (activity instanceof MapActivity) { // be aware that is non ui thread ((MapActivity) activity).getMapView().refreshMap(); } } else { if (res.getErrorMessage() != null) { - showMessage(activity.getString(R.string.error_calculating_route) + res.getErrorMessage()); + showMessage(activity.getString(R.string.error_calculating_route)+" : " + res.getErrorMessage()); //$NON-NLS-1$ } else if (res.getLocations() == null) { showMessage(activity.getString(R.string.error_calculating_route_occured)); } else { @@ -508,11 +523,18 @@ public class RoutingHelper { public static class RouteDirectionInfo { public String descriptionRoute = ""; //$NON-NLS-1$ + // expected time after route point public int expectedTime; + public TurnType turnType; + // location when you should action (turn or go ahead) public int routePointOffset; + // calculated vars + + // after action (for i.e. after turn to next turn) public int afterLeftTime; + // distance after action (for i.e. after turn to next turn) public int distance; } diff --git a/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java b/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java index 4bfe9d9f32..26a886eaf1 100644 --- a/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java +++ b/OsmAnd/src/com/osmand/activities/ShowRouteInfoActivity.java @@ -4,6 +4,7 @@ package com.osmand.activities; import java.text.MessageFormat; +import java.util.Calendar; import java.util.List; import android.app.ListActivity; @@ -39,9 +40,6 @@ import com.osmand.views.MapInfoLayer; */ public class ShowRouteInfoActivity extends ListActivity { - - - @Override public void onCreate(Bundle icicle) { @@ -50,7 +48,8 @@ public class ShowRouteInfoActivity extends ListActivity { lv.setId(android.R.id.list); TextView header = new TextView(this); RoutingHelper helper = RoutingHelper.getInstance(this); - int time = helper.getLeftTime()* 1000; + Calendar c = Calendar.getInstance(); + int time = helper.getLeftTime() * 1000 - c.getTimeZone().getOffset(0); int dist = helper.getLeftDistance(); header.setText(MessageFormat.format(getString(R.string.route_general_information), MapUtils.getFormattedDistance(dist), DateFormat.format("kk:mm", time))); //$NON-NLS-1$ @@ -138,7 +137,7 @@ public class ShowRouteInfoActivity extends ListActivity { if(model.expectedTime < 3600){ timeLabel.setText(DateFormat.format("mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$ } else { - timeLabel.setText(DateFormat.format("k:mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$ + timeLabel.setText(DateFormat.format("kk:mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$ } return row; } diff --git a/OsmAnd/src/com/osmand/views/MapInfoLayer.java b/OsmAnd/src/com/osmand/views/MapInfoLayer.java index 335fc80210..663ba8c455 100644 --- a/OsmAnd/src/com/osmand/views/MapInfoLayer.java +++ b/OsmAnd/src/com/osmand/views/MapInfoLayer.java @@ -1,5 +1,7 @@ package com.osmand.views; +import java.util.Calendar; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; @@ -270,7 +272,8 @@ public class MapInfoLayer implements OsmandMapLayer { } if(Math.abs(toFindTime - cachedLeftTime) > 30000){ cachedLeftTime = toFindTime; - cachedLeftTimeString = DateFormat.format("kk:mm", cachedLeftTime).toString(); //$NON-NLS-1$ + Calendar c = Calendar.getInstance(); + cachedLeftTimeString = DateFormat.format("kk:mm", cachedLeftTime - c.getTimeZone().getOffset(0) ).toString(); //$NON-NLS-1$ } } if(cachedLeftTimeString != null) { diff --git a/OsmAnd/src/com/osmand/views/PointLocationLayer.java b/OsmAnd/src/com/osmand/views/PointLocationLayer.java index 176802b7b8..ecfe5758f7 100644 --- a/OsmAnd/src/com/osmand/views/PointLocationLayer.java +++ b/OsmAnd/src/com/osmand/views/PointLocationLayer.java @@ -86,7 +86,7 @@ public class PointLocationLayer implements OsmandMapLayer { if(appMode == ApplicationMode.CAR){ if(!lastKnownLocation.hasBearing()){ canvas.drawCircle(locationX, locationY, RADIUS * 2.5f, location); - canvas.drawCircle(locationX, locationY, RADIUS, bearingOver); + canvas.drawCircle(locationX, locationY, RADIUS * 2.5f, bearingOver); } } else { canvas.drawCircle(locationX, locationY, RADIUS, location);