diff --git a/OsmAnd/res/menu/map_menu.xml b/OsmAnd/res/menu/map_menu.xml index 898a6ede73..a5fe35f859 100644 --- a/OsmAnd/res/menu/map_menu.xml +++ b/OsmAnd/res/menu/map_menu.xml @@ -10,6 +10,7 @@ + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 19f0ffbace..2fd3cd2441 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,8 @@ + Animate off + Animate on + Upload GPX files to OSM community. They will be used to improve maps. %1$d of %2$d item(s) successfully uploaded. Contribute to OSM... diff --git a/OsmAnd/src/net/osmand/LatLonUtils.java b/OsmAnd/src/net/osmand/LatLonUtils.java new file mode 100644 index 0000000000..91153e9d8a --- /dev/null +++ b/OsmAnd/src/net/osmand/LatLonUtils.java @@ -0,0 +1,34 @@ +package net.osmand; + +import android.location.Location; + +public class LatLonUtils { + + public static Location middleLocation(Location start, Location end, + float meters) { + double lat1 = toRad(start.getLatitude()); + double lon1 = toRad(start.getLongitude()); + double R = 6371; // radius of earth in km + double d = meters / 1000; // in km + float brng = (float) (toRad(start.bearingTo(end))); + double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d / R) + + Math.cos(lat1) * Math.sin(d / R) * Math.cos(brng)); + double lon2 = lon1 + + Math.atan2(Math.sin(brng) * Math.sin(d / R) * Math.cos(lat1), + Math.cos(d / R) - Math.sin(lat1) * Math.sin(lat2)); + Location nl = new Location(start); + nl.setLatitude(toDegree(lat2)); + nl.setLongitude(toDegree(lon2)); + nl.setBearing(brng); + return nl; + } + + private static double toDegree(double radians) { + return radians * 180 / Math.PI; + } + + private static double toRad(double degree) { + return degree * Math.PI / 180; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index a27c48828c..20ca65753e 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -28,12 +28,12 @@ import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.PointLocationLayer; import android.app.Activity; import android.app.AlertDialog; +import android.app.AlertDialog.Builder; import android.app.Dialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProgressDialog; -import android.app.AlertDialog.Builder; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.DialogInterface; @@ -58,6 +58,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; +import android.provider.Settings.Secure; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; @@ -65,8 +66,8 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.Window; import android.view.View.OnClickListener; +import android.view.Window; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Transformation; @@ -121,6 +122,8 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso // Store previous map rotation settings for rotate button private Integer previousMapRotate = null; + private RouteAnimation routeAnimation = new RouteAnimation(); + private boolean isMapLinkedToLocation = false; private ProgressDialog startProgressDialog; @@ -436,6 +439,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso protected void onDestroy() { super.onDestroy(); savingTrackHelper.close(); + routeAnimation.close(); if(mNotificationManager != null){ mNotificationManager.cancel(APP_NOTIFICATION_ID); } @@ -948,6 +952,15 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso muteMenu.setVisible(false); } } + MenuItem animateMenu = menu.findItem(R.id.map_animate_route); + if (animateMenu != null) { + animateMenu.setTitle(routeAnimation.isRouteAnimating() ? R.string.animate_route_off + : R.string.animate_route); + animateMenu.setVisible("1".equals(Secure.getString( + getContentResolver(), Secure.ALLOW_MOCK_LOCATION)) + && settings.getPointToNavigate() != null + && routingHelper.isRouteCalculated()); + } return val; } @@ -1003,6 +1016,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso case R.id.map_show_point_options: contextMenuPoint(mapView.getLatitude(), mapView.getLongitude()); return true; + case R.id.map_animate_route: + //animate moving on route + routeAnimation.startStopRouteAnimation(routingHelper, this); + return true; default: return super.onOptionsItemSelected(item); } @@ -1104,9 +1121,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso @Override public void onClick(DialogInterface dialog, int which) { ApplicationMode mode = getAppMode(buttons); - Location location = new Location("map"); //$NON-NLS-1$ - location.setLatitude(lat); - location.setLongitude(lon); + Location location = getLocationToStartFrom(lat, lon); routingHelper.setAppMode(mode); settings.FOLLOW_TO_THE_ROUTE.set(false); routingHelper.setFollowingMode(false); diff --git a/OsmAnd/src/net/osmand/plus/activities/RouteAnimation.java b/OsmAnd/src/net/osmand/plus/activities/RouteAnimation.java new file mode 100644 index 0000000000..17dc8467a5 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/activities/RouteAnimation.java @@ -0,0 +1,65 @@ +package net.osmand.plus.activities; + +import java.util.ArrayList; +import java.util.List; + +import net.osmand.LatLonUtils; +import android.location.Location; + +public class RouteAnimation { + + private Thread routeAnimation; + + public boolean isRouteAnimating() { + return routeAnimation != null; + } + + public void startStopRouteAnimation(final RoutingHelper routingHelper, + final MapActivity ma) { + if (!isRouteAnimating()) { + routeAnimation = new Thread() { + public void run() { + final List directions = new ArrayList( + routingHelper.getCurrentRoute()); + Location current = null; + float meters = 20.0f; + while (!directions.isEmpty() && routeAnimation != null) { + if (current == null) { + current = new Location(directions.remove(0)); + } else { + if (current.distanceTo(directions.get(0)) > meters) { + current = LatLonUtils.middleLocation(current, + directions.get(0), meters); + } else { + current = new Location(directions.remove(0)); + } + } + current.setSpeed(meters); + current.setTime(System.currentTimeMillis()); + ma.setLocation(current); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // do nothing + } + } + RouteAnimation.this.stop(); + }; + }; + routeAnimation.start(); + } else { + // stop the animation + stop(); + } + } + + private void stop() { + routeAnimation = null; + } + + public void close() { + if (isRouteAnimating()) { + stop(); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/activities/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/activities/RoutingHelper.java index 9d70a5059f..66dc487219 100644 --- a/OsmAnd/src/net/osmand/plus/activities/RoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/RoutingHelper.java @@ -117,13 +117,18 @@ public class RoutingHelper { this.lastFixedLocation = null; this.isFollowingMode = false; } - } public List getCurrentGPXRoute() { return currentGPXRoute; } + public List getCurrentRoute() { + return currentGPXRoute == null || currentGPXRoute.isEmpty() ? Collections + .unmodifiableList(routeNodes) : Collections + .unmodifiableList(currentGPXRoute); + } + public void setAppMode(ApplicationMode mode){ this.mode = mode; voiceRouter.updateAppMode();