From 56befb372cd7092b734be3f19cde5558ff65f5b8 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 23 May 2010 20:59:55 +0000 Subject: [PATCH] implement rotating map git-svn-id: https://osmand.googlecode.com/svn/trunk@78 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8 --- .../src/com/osmand/ToDoConstants.java | 65 +++++---- .../src/com/osmand/data/DataTileManager.java | 8 +- OsmAnd/res/layout/searchlist.xml | 4 +- OsmAnd/res/values/strings.xml | 2 + OsmAnd/res/xml/settings_pref.xml | 1 + OsmAnd/src/com/osmand/OsmandSettings.java | 7 + .../com/osmand/activities/MapActivity.java | 19 ++- .../com/osmand/activities/SearchActivity.java | 6 + .../osmand/activities/SettingsActivity.java | 7 + .../com/osmand/views/OsmandMapTileView.java | 123 ++++++++++++++---- .../com/osmand/views/PointLocationLayer.java | 31 +++-- 11 files changed, 199 insertions(+), 74 deletions(-) diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index af5ffabee8..670a5be9fc 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -19,36 +19,51 @@ public class ToDoConstants { */ public int DESCRIBE_ABOUT_AUTHORS = 8; - // 0. Minimize memory used for index & improve time for read index - //// TODO for releasing version - // 1. POI SEARCH NEAR TO YOU - // 2. FIX BACK TO your location & gps & point of view (may be compass) - // 3. Revise UI icons/layout - // 5. Enable city/streets/buildings index - // 7. Search for city/streets/buildings! - // 8. Enable change POI directly on map - // 9. Log to see when exception occurred (android) - // 10. Specify auto-rotating map (compass). - // 11. Print out additional info speed, altitude, number of satellites - // 12. Show point where are you going (the arrow not the point) - // 13. Save point as favorite - // 14. Show zoom level directly on map - // 15. Investigate interruption of progress (is it available & how to support it) - // ------------------- + // TODO ANDROID +// 0. Minimize memory used for index & improve time for reading index +// 1. POI search near to map location (show categories & type). First cut. (implement incremental search) +// 3. Revise osmand UI. Preparing new icons. +// 2. Showing compass on the map : use device compass if exists(?) +// 5. Search for city/streets/buildings +// 9. Config file log & see log from file (when exception happened to see from device) +// 11. Print out additional info speed, altitude, number of satellites +// 8. Enable change POI directly on map (requires OSM login) +// 13. Save point as favourite & introduce favourite points dialog +// 14. Show zoom level on map +// 15. Investigate interruption of any long running operation & implement where it is needed +// 16. Support open street bugs api. +// 17. Enable go to location specifying coordinates +// 18. Implement go to point +// 19. Show how map is rotated where north/south on map (do not consider compass) +// 20. Implement save track/route to gpx (?) - // BUGS Androd : + // FIXME Bugs Androd : + // 0. FIX TODO for partial loading rotated map // 1. When firstly run osmand navigation (from notification bar) show map & go to menu shows desktop. // No chance to close application + // 3. Fix progress information (loading indices) for android version + // 4. Fix when POI selected & enable button backToLocation + + // TODO SWING: + // 1. download tiles without using dir tiles + // 2. Config file log & see log from file + // 3. Reinvent index mechanism (save in zip file with tile indexes, save city/town addresses separately, read partially !) + // 4. Invent different file extensions for poi.index, address.index,... + + + // Max letter : + // 1. Fix bug 1 + // 2. Create for each screen activity + // 3. Implement incremental search (reduce first time display to 10 & depth 2) + // 4. Improve navigate back/forward between screens + // 5. Implement exit confirmation - /// SWING version : - // TODO : - // 1. Accept amenity as way - // 1. Fix TODO in files + // DONE ANDROID : +// 12. Show information of where are you going (the arrow on the map) +// 10. Specify auto-rotating map (bearing of your direction) + + // DONE SWING - // 3. download tiles without using dir tiles - // 4. Config file log & see log from file - // 5. Reinvent index mechanism (save in zip file with tile indexes, save city/town addresses separately, read partially !) - // 6. Invent different file extensions for poi.index, address.index,... } diff --git a/DataExtractionOSM/src/com/osmand/data/DataTileManager.java b/DataExtractionOSM/src/com/osmand/data/DataTileManager.java index e1954d20b1..f05507190c 100644 --- a/DataExtractionOSM/src/com/osmand/data/DataTileManager.java +++ b/DataExtractionOSM/src/com/osmand/data/DataTileManager.java @@ -88,7 +88,7 @@ public class DataTileManager { if(isEmpty()){ return Collections.emptyList(); } - int dp = 1; + int dp = 0; List l = null; while (l == null || l.isEmpty()) { l = getClosestObjects(latitude, longitude, dp, dp + defaultStep); @@ -106,8 +106,10 @@ public class DataTileManager { int tileY = (int) MapUtils.getTileNumberY(zoom, latitude); List result = new ArrayList(); - - putObjects(tileX, tileY, result); + if(startDepth <= 0){ + putObjects(tileX, tileY, result); + startDepth = 1; + } // that's very difficult way visiting node : // similar to visit by spiral diff --git a/OsmAnd/res/layout/searchlist.xml b/OsmAnd/res/layout/searchlist.xml index 1c70eb39d5..7aa243025b 100644 --- a/OsmAnd/res/layout/searchlist.xml +++ b/OsmAnd/res/layout/searchlist.xml @@ -1,9 +1,9 @@ - + android:layout_height="wrap_content" android:textSize="25px" /> \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 99ccc72d8d..47a5275029 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,7 @@ + Rotate map to bearing of your direction + Rotate map Show POI on map Show POI Choose the source of tiles: diff --git a/OsmAnd/res/xml/settings_pref.xml b/OsmAnd/res/xml/settings_pref.xml index b5a346beeb..0e75b493de 100644 --- a/OsmAnd/res/xml/settings_pref.xml +++ b/OsmAnd/res/xml/settings_pref.xml @@ -5,6 +5,7 @@ + diff --git a/OsmAnd/src/com/osmand/OsmandSettings.java b/OsmAnd/src/com/osmand/OsmandSettings.java index 3b559dc04e..5431afbc55 100644 --- a/OsmAnd/src/com/osmand/OsmandSettings.java +++ b/OsmAnd/src/com/osmand/OsmandSettings.java @@ -30,6 +30,13 @@ public class OsmandSettings { return prefs.getBoolean(SHOW_POI_OVER_MAP, false); } + // this value string is synchronized with android.xml preference name + public static final String ROTATE_MAP_TO_BEARING = "rotate_map_to_bearing"; + public static boolean isRotateMapToBearing(Context ctx){ + SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); + return prefs.getBoolean(ROTATE_MAP_TO_BEARING, false); + } + // this value string is synchronized with android.xml preference name public static final String MAP_TILE_SOURCES = "map_tile_sources"; diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index 576da98408..dc5efc955c 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -135,16 +135,22 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat } public void setLocation(Location location){ - locationLayer.setLastKnownLocation(location); + // Do very strange manipulation to call redraw only once + locationLayer.setLastKnownLocation(location, true); if (location != null) { if (linkLocationWithMap) { - mapView.setLatLon(location.getLatitude(), location.getLongitude()); - } + if (location.hasBearing() && OsmandSettings.isRotateMapToBearing(this)) { + mapView.setRotateWithLocation(-location.getBearing(), location.getLatitude(), location.getLongitude()); + } else { + mapView.setLatLon(location.getLatitude(), location.getLongitude()); + } + } else { + mapView.prepareImage(); + } } else { - if(!linkLocationWithMap){ + if (!linkLocationWithMap) { backToLocation.setVisibility(View.VISIBLE); } - } } @@ -191,6 +197,9 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat if(mapView.getMap() != OsmandSettings.getMapTileSource(this)){ mapView.setMap(OsmandSettings.getMapTileSource(this)); } + if(!OsmandSettings.isRotateMapToBearing(this)){ + mapView.setRotate(0); + } if(mapView.getLayers().contains(poiMapLayer) != OsmandSettings.isShowingPoiOverMap(this)){ if(OsmandSettings.isShowingPoiOverMap(this)){ mapView.addLayer(poiMapLayer); diff --git a/OsmAnd/src/com/osmand/activities/SearchActivity.java b/OsmAnd/src/com/osmand/activities/SearchActivity.java index da8e3c9322..74fd084bbe 100644 --- a/OsmAnd/src/com/osmand/activities/SearchActivity.java +++ b/OsmAnd/src/com/osmand/activities/SearchActivity.java @@ -112,6 +112,12 @@ public class SearchActivity extends ListActivity { AmenityAdapter(Object list) { super(SearchActivity.this, R.layout.searchlist, (List) list); } + + @Override + public int getCount() { + int c = super.getCount(); + return c > 20 ? 20 : c; + } public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = getLayoutInflater(); diff --git a/OsmAnd/src/com/osmand/activities/SettingsActivity.java b/OsmAnd/src/com/osmand/activities/SettingsActivity.java index 9927045d90..4c3794c293 100644 --- a/OsmAnd/src/com/osmand/activities/SettingsActivity.java +++ b/OsmAnd/src/com/osmand/activities/SettingsActivity.java @@ -23,6 +23,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference private CheckBoxPreference showPoiOnMap; private CheckBoxPreference useInternetToDownloadTiles; private ListPreference tileSourcePreference; + private CheckBoxPreference rotateMapToBearing; @Override public void onCreate(Bundle savedInstanceState) { @@ -33,6 +34,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference useInternetToDownloadTiles.setOnPreferenceChangeListener(this); showPoiOnMap =(CheckBoxPreference) screen.findPreference(OsmandSettings.SHOW_POI_OVER_MAP); showPoiOnMap.setOnPreferenceChangeListener(this); + rotateMapToBearing =(CheckBoxPreference) screen.findPreference(OsmandSettings.ROTATE_MAP_TO_BEARING); + rotateMapToBearing.setOnPreferenceChangeListener(this); tileSourcePreference =(ListPreference) screen.findPreference(OsmandSettings.MAP_TILE_SOURCES); tileSourcePreference.setOnPreferenceChangeListener(this); @@ -45,6 +48,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference super.onResume(); useInternetToDownloadTiles.setChecked(OsmandSettings.isUsingInternetToDownloadTiles(this)); showPoiOnMap.setChecked(OsmandSettings.isShowingPoiOverMap(this)); + rotateMapToBearing.setChecked(OsmandSettings.isRotateMapToBearing(this)); List list = TileSourceManager.getKnownSourceTemplates(); String[] entries = new String[list.size()]; @@ -70,6 +74,9 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference } else if(preference == useInternetToDownloadTiles){ edit.putBoolean(OsmandSettings.USE_INTERNET_TO_DOWNLOAD_TILES, (Boolean) newValue); edit.commit(); + } else if(preference == rotateMapToBearing){ + edit.putBoolean(OsmandSettings.ROTATE_MAP_TO_BEARING, (Boolean) newValue); + edit.commit(); } else if (preference == tileSourcePreference) { edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue); edit.commit(); diff --git a/OsmAnd/src/com/osmand/views/OsmandMapTileView.java b/OsmAnd/src/com/osmand/views/OsmandMapTileView.java index 89ae16873a..e7fb3d7919 100644 --- a/OsmAnd/src/com/osmand/views/OsmandMapTileView.java +++ b/OsmAnd/src/com/osmand/views/OsmandMapTileView.java @@ -13,8 +13,10 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Paint.Style; import android.util.AttributeSet; +import android.util.FloatMath; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -48,6 +50,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall private double latitude = 0d; + private float rotate = 0; + // name of source map private ITileSource map = null; @@ -65,6 +69,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall Paint paintGrayFill; Paint paintWhiteFill; Paint paintBlack; + Paint paintBitmap; @@ -84,14 +89,21 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall paintGrayFill = new Paint(); paintGrayFill.setColor(Color.GRAY); paintGrayFill.setStyle(Style.FILL); - + // when map rotate + paintGrayFill.setAntiAlias(true); + paintWhiteFill = new Paint(); paintWhiteFill.setColor(Color.WHITE); paintWhiteFill.setStyle(Style.FILL); + // when map rotate + paintWhiteFill.setAntiAlias(true); paintBlack = new Paint(); paintBlack.setStyle(Style.STROKE); paintBlack.setColor(Color.BLACK); + + paintBitmap = new Paint(); + paintBitmap.setFilterBitmap(true); setClickable(true); getHolder().addCallback(this); @@ -140,12 +152,12 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall } - public double getXTile(){ - return MapUtils.getTileNumberX(zoom, longitude); + public float getXTile(){ + return (float) MapUtils.getTileNumberX(zoom, longitude); } - public double getYTile(){ - return MapUtils.getTileNumberY(zoom, latitude); + public float getYTile(){ + return (float) MapUtils.getTileNumberY(zoom, latitude); } @@ -157,6 +169,27 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall } } + public void setRotate(float rotate) { + float dif = this.rotate - rotate; + if (dif > 2 || dif < -2) { + this.rotate = rotate; + animatedDraggingThread.stopDragging(); + prepareImage(); + } + } + + public void setRotateWithLocation(float rotate, double latitude, double longitude){ + animatedDraggingThread.stopDragging(); + this.rotate = rotate; + this.latitude = latitude; + this.longitude = longitude; + prepareImage(); + } + + public float getRotate() { + return rotate; + } + public ITileSource getMap() { return map; } @@ -230,33 +263,59 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall } } + protected void calculateTileRectangle(RectF pixRect, float cx, float cy, RectF tileRect){ + float x1 = calcDiffTileX(pixRect.left - cx, pixRect.top - cy); + float x2 = calcDiffTileX(pixRect.left - cx, pixRect.bottom - cy); + float x3 = calcDiffTileX(pixRect.right - cx, pixRect.top - cy); + float x4 = calcDiffTileX(pixRect.right - cx, pixRect.bottom - cy); + float y1 = calcDiffTileY(pixRect.left - cx, pixRect.top - cy); + float y2 = calcDiffTileY(pixRect.left - cx, pixRect.bottom - cy); + float y3 = calcDiffTileY(pixRect.right - cx, pixRect.top - cy); + float y4 = calcDiffTileY(pixRect.right - cx, pixRect.bottom - cy); + float l = Math.min(Math.min(x1, x2), Math.min(x3, x4)) + getXTile(); + float r = Math.max(Math.max(x1, x2), Math.max(x3, x4)) + getXTile(); + float t = Math.min(Math.min(y1, y2), Math.min(y3, y4)) + getYTile(); + float b = Math.max(Math.max(y1, y2), Math.max(y3, y4)) + getYTile(); + tileRect.set(l, t, r, b); + } + + // used only to save space & reuse + protected RectF tilesRect = new RectF(); + protected RectF boundsRect = new RectF(); + public void prepareImage() { if (OsmandSettings.isUsingInternetToDownloadTiles(getContext())) { MapTileDownloader.getInstance().refuseAllPreviousRequests(); } - int width = getWidth(); - int height = getHeight(); int tileSize = getTileSize(); - - int xTileLeft = (int) Math.floor(getXTile() - width / (2d * getTileSize())); - int yTileUp = (int) Math.floor(getYTile() - height / (2d * getTileSize())); - int startingX = (int) ((xTileLeft - getXTile()) * getTileSize() + getWidth() / 2); - int startingY = (int) ((yTileUp - getYTile()) * getTileSize() + getHeight() / 2); + float tileX = getXTile(); + float tileY = getYTile(); SurfaceHolder holder = getHolder(); synchronized (holder) { Canvas canvas = holder.lockCanvas(); if (canvas != null) { -// canvas.rotate(45); + ResourceManager mgr = ResourceManager.getResourceManager(); + boolean useInternet = OsmandSettings.isUsingInternetToDownloadTiles(getContext()); + float w = getWidth() / 2; + float h = getHeight() / 2; + canvas.rotate(rotate, w , h); + boundsRect.set(0, 0, getWidth(), getHeight()); + calculateTileRectangle(boundsRect, w, h, tilesRect); try { - for (int i = 0; i * tileSize + startingX < width; i++) { - for (int j = 0; j * tileSize + startingY < height; j++) { - ResourceManager mgr = ResourceManager.getResourceManager(); - Bitmap bmp = mgr.getTileImageForMapAsync(map, xTileLeft + i, yTileUp + j, zoom, OsmandSettings.isUsingInternetToDownloadTiles(getContext())); + int left = (int) FloatMath.floor(tilesRect.left); + int top = (int) FloatMath.floor(tilesRect.top); + int width = (int) (FloatMath.ceil(tilesRect.right) - left); + int height = (int) (FloatMath.ceil(tilesRect.bottom) - top); + for (int i = 0; i = 0 && i < getWidth()) && (j + getTileSize() >= 0 && j < getHeight())) { SurfaceHolder holder = getHolder(); synchronized (holder) { - // TODO Canvas canvas = holder.lockCanvas(new Rect(i, j, getTileSize() + i, getTileSize() + j)); if (canvas != null) { -// canvas.rotate(45); + canvas.rotate(rotate,getWidth()/2, getHeight()/2); try { ResourceManager mgr = ResourceManager.getResourceManager(); Bitmap bmp = mgr.getTileImageForMapSync(map, request.xTile, request.yTile, zoom, false); @@ -309,14 +368,26 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall /////////////////////////////////// DRAGGING PART /////////////////////////////////////// + public float calcDiffTileY(float dx, float dy){ + float rad = (float) Math.toRadians(rotate); + return (-FloatMath.sin(rad) * dx + FloatMath.cos(rad) * dy) / getTileSize(); + } + + public float calcDiffTileX(float dx, float dy){ + float rad = (float) Math.toRadians(rotate); + return (FloatMath.cos(rad) * dx + FloatMath.sin(rad) * dy) / getTileSize(); + } @Override public void dragTo(float fromX, float fromY, float toX, float toY){ - float dx = (fromX - toX)/getTileSize(); - float dy = (fromY - toY)/getTileSize(); - this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy); - this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx); + float dx = (fromX - toX) ; + float dy = (fromY - toY); + float fy = calcDiffTileY(dx, dy); + float fx = calcDiffTileX(dx, dy); + + this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + fy); + this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + fx); prepareImage(); if(locationListener != null){ locationListener.locationChanged(latitude, longitude, this); diff --git a/OsmAnd/src/com/osmand/views/PointLocationLayer.java b/OsmAnd/src/com/osmand/views/PointLocationLayer.java index 61fc0355ea..e46c6d9438 100644 --- a/OsmAnd/src/com/osmand/views/PointLocationLayer.java +++ b/OsmAnd/src/com/osmand/views/PointLocationLayer.java @@ -7,6 +7,7 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.Paint.Style; import android.location.Location; +import android.util.FloatMath; import android.view.MotionEvent; import com.osmand.osm.MapUtils; @@ -52,6 +53,7 @@ public class PointLocationLayer implements OsmandMapLayer { } + // TODO simplify calculation if possible @Override public void onDraw(Canvas canvas) { if (isLocationVisible(lastKnownLocation)) { @@ -62,9 +64,7 @@ public class PointLocationLayer implements OsmandMapLayer { int radius = MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(), lastKnownLocation .getAccuracy(), view.getTileSize(), view.getWidth()); - if (locationX >= 0 && locationY >= 0) { - canvas.drawCircle(locationX, locationY, RADIUS, location); - } + canvas.drawCircle(locationX, locationY, RADIUS, location); if (radius > RADIUS) { canvas.drawCircle(locationX, locationY, radius, area); } @@ -103,12 +103,15 @@ public class PointLocationLayer implements OsmandMapLayer { if(l == null || view == null){ return false; } - int newX = MapUtils.getPixelShiftX(view.getZoom(), - l.getLongitude(), view.getLongitude(), view.getTileSize()) + - view.getWidth()/2; - int newY = MapUtils.getPixelShiftY(view.getZoom(), - l.getLatitude(), view.getLatitude() , view.getTileSize()) + - view.getHeight()/2; + int cx = view.getWidth()/2; + int cy = view.getHeight()/2; + int dx = MapUtils.getPixelShiftX(view.getZoom(), + l.getLongitude(), view.getLongitude(), view.getTileSize()); + int dy = MapUtils.getPixelShiftY(view.getZoom(), + l.getLatitude(), view.getLatitude() , view.getTileSize()); + float rad = (float) Math.toRadians(view.getRotate()); + int newX = (int) (dx * FloatMath.cos(rad) - dy * FloatMath.sin(rad) + cx); + int newY = (int) (dx * FloatMath.sin(rad) + dy * FloatMath.cos(rad) + cy); int radius = MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(), l.getAccuracy(), view.getTileSize(), view.getWidth()); if(newX >= 0 && newX <= view.getWidth() && newY >=0 && newY <= view.getHeight()){ @@ -127,11 +130,13 @@ public class PointLocationLayer implements OsmandMapLayer { return lastKnownLocation; } - public void setLastKnownLocation(Location lastKnownLocation) { - boolean redraw = isLocationVisible(this.lastKnownLocation) || isLocationVisible(lastKnownLocation); + public void setLastKnownLocation(Location lastKnownLocation, boolean doNotRedraw) { this.lastKnownLocation = lastKnownLocation; - if(redraw){ - view.prepareImage(); + if (!doNotRedraw) { + boolean redraw = isLocationVisible(this.lastKnownLocation) || isLocationVisible(lastKnownLocation); + if (redraw) { + view.prepareImage(); + } } }