fix zoom issues

git-svn-id: https://osmand.googlecode.com/svn/trunk@544 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-10-08 16:30:26 +00:00
parent 9454618ddb
commit 27ed10f078
22 changed files with 694 additions and 631 deletions

View file

@ -15,10 +15,8 @@ public class ToDoConstants {
// ! 81. Add some objects to POI category (1) to add them into OSM 2) to help navigation)
// highway (?), traffic_calming (?), barrier(?), military(?-), landuse (?), office(?), man_made(?), power(?),
// railway( station, subway?) - issue 17
// !_22. Verify all POI has a point_type (in order to search them)
// !_22. Verify all POI has a point_type (in order to search them) - !
// !_30. Fix rotate (_)
// Outside base 0.4 release
// 97. For voice navigation consider current speed of vehicle. Especially when speed > 50 pronounce more than 200 m
// 98. Implement rendering of different app mode. For Car render streets name with large font.

View file

@ -30,7 +30,6 @@ import org.apache.commons.logging.Log;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.os.Environment;
/**
@ -560,14 +559,14 @@ public class ResourceManager {
}
////////////////////////////////////////////// Working with map ////////////////////////////////////////////////
public boolean updateRenderedMapNeeded(RectF tilesRect, int zoom, float rotate){
return renderer.updateMapIsNeeded(tilesRect, zoom, rotate);
public boolean updateRenderedMapNeeded(RotatedTileBox rotatedTileBox){
return renderer.updateMapIsNeeded(rotatedTileBox);
}
public void updateRendererMap(RectF tileRect, RectF boundsTileRect, int zoom, float rotate){
public void updateRendererMap(RotatedTileBox rotatedTileBox){
renderer.interruptLoadingMap();
asyncLoadingTiles.requestToLoadMap(
new MapLoadRequest(tileRect, boundsTileRect, zoom, rotate));
new MapLoadRequest(new RotatedTileBox(rotatedTileBox)));
}
public MapRenderRepositories getRenderer() {
@ -721,17 +720,11 @@ public class ResourceManager {
}
private static class MapLoadRequest {
public final RectF tileRect;
public final RectF boundsTileRect;
public final int zoom;
public final float rotate;
public final RotatedTileBox tileBox;
public MapLoadRequest(RectF tileRect, RectF boundsTileRect, int zoom, float rotate) {
public MapLoadRequest(RotatedTileBox tileBox) {
super();
this.tileRect = tileRect;
this.boundsTileRect = boundsTileRect;
this.zoom = zoom;
this.rotate = rotate;
this.tileBox = tileBox;
}
}
@ -788,7 +781,7 @@ public class ResourceManager {
} else if(req instanceof MapLoadRequest){
if(!mapLoaded){
MapLoadRequest r = (MapLoadRequest) req;
renderer.loadMap(r.tileRect, r.boundsTileRect, r.zoom, r.rotate);
renderer.loadMap(r.tileBox);
mapLoaded = true;
}
}

View file

@ -0,0 +1,158 @@
package net.osmand;
import net.osmand.osm.MapUtils;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.FloatMath;
public class RotatedTileBox {
private float leftTileX;
private float topTileY;
private float tileWidth;
private float tileHeight;
private float rotate;
private int zoom;
private float rotateCos;
private float rotateSin;
public RotatedTileBox(float leftTileX, float topTileY, float tileWidth, float tileHeight, float rotate, int zoom) {
set(leftTileX, topTileY, tileWidth, tileHeight, rotate, zoom);
}
public RotatedTileBox(RotatedTileBox r){
set(r.leftTileX, r.topTileY, r.tileWidth, r.tileHeight, r.rotate, r.zoom);
}
private void init() {
float rad = (float) Math.toRadians(this.rotate);
rotateCos = FloatMath.cos(rad);
rotateSin = FloatMath.sin(rad);
}
public void set(float leftTileX, float topTileY, float tileWidth, float tileHeight, float rotate, int zoom) {
this.leftTileX = leftTileX;
if(rotate < 0){
rotate += 360;
} else if(rotate > 360){
rotate -= 360;
}
this.rotate = rotate;
this.tileHeight = tileHeight;
this.tileWidth = tileWidth;
this.topTileY = topTileY;
this.zoom = zoom;
init();
}
public float getRotateCos() {
return rotateCos;
}
public float getRotateSin() {
return rotateSin;
}
public int getZoom() {
return zoom;
}
public float getRotate() {
return rotate;
}
public float getTileHeight() {
return tileHeight;
}
public float getTileWidth() {
return tileWidth;
}
public float getLeftTileX() {
return leftTileX;
}
public float getTopTileY() {
return topTileY;
}
public boolean containsTileBox(RotatedTileBox box) {
PointF temp = new PointF();
if(box.getZoom() != zoom){
throw new UnsupportedOperationException();
}
box.calcPointTile(0, 0, temp);
if(!containsPoint(temp.x, temp.y)){
return false;
}
box.calcPointTile(box.tileWidth, 0, temp);
if(!containsPoint(temp.x, temp.y)){
return false;
}
box.calcPointTile(0, box.tileHeight, temp);
if(!containsPoint(temp.x, temp.y)){
return false;
}
box.calcPointTile(box.tileWidth, box.tileHeight, temp);
if(!containsPoint(temp.x, temp.y)){
return false;
}
return true;
}
public RectF calculateLatLonBox(RectF rectF) {
float tx = calcPointTileX(tileWidth, 0);
float tx2 = calcPointTileX(tileWidth, tileHeight);
float tx3 = calcPointTileX(0, tileHeight);
float minTileX = Math.min(Math.min(leftTileX, tx), Math.min(tx2, tx3)) ;
float maxTileX = Math.max(Math.max(leftTileX, tx), Math.max(tx2, tx3)) ;
rectF.left = (float) MapUtils.getLongitudeFromTile(zoom, minTileX);
rectF.right = (float) MapUtils.getLongitudeFromTile(zoom, maxTileX);
float ty = calcPointTileY(tileWidth, 0);
float ty2 = calcPointTileY(tileWidth, tileHeight);
float ty3 = calcPointTileY(0, tileHeight);
float minTileY = Math.min(Math.min(topTileY, ty), Math.min(ty2, ty3)) ;
float maxTileY = Math.max(Math.max(topTileY, ty), Math.max(ty2, ty3)) ;
rectF.top = (float) MapUtils.getLatitudeFromTile(zoom, minTileY);
rectF.bottom = (float) MapUtils.getLatitudeFromTile(zoom, maxTileY);
return rectF;
}
public boolean containsPoint(float tileX, float tileY) {
tileX -= leftTileX;
tileY -= topTileY;
double tx = rotateCos * tileX - rotateSin * tileY;
double ty = rotateSin * tileX + rotateCos * tileY;
return tx >= 0 && tx <= tileWidth && ty >= 0 && ty <= tileHeight;
}
protected PointF calcPointTile(float dx, float dy, PointF p){
float tx = rotateCos * dx + rotateSin * dy + leftTileX;
float ty = - rotateSin * dx + rotateCos * dy + topTileY;
p.set(tx, ty);
return p;
}
protected float calcPointTileX(float dx, float dy){
return rotateCos * dx + rotateSin * dy + leftTileX;
}
protected float calcPointTileY(float dx, float dy){
return - rotateSin * dx + rotateCos * dy + topTileY;
}
public float getRightBottomTileX() {
return calcPointTileX(tileWidth, tileHeight);
}
public float getRightBottomTileY() {
return calcPointTileY(tileWidth, tileHeight);
}
}

View file

@ -379,10 +379,6 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
Intent newIntent = new Intent(MapActivity.this, SearchActivity.class);
startActivity(newIntent);
return true;
} else if (keyCode == KeyEvent.KEYCODE_R) {
// Is it needed
mapView.setRotate(mapView.getRotate() + 45);
return true;
}
return super.onKeyDown(keyCode, event);
}

View file

@ -23,6 +23,7 @@ import java.util.Set;
import net.osmand.IProgress;
import net.osmand.LogUtil;
import net.osmand.OsmandSettings;
import net.osmand.RotatedTileBox;
import net.osmand.data.index.IndexConstants;
import net.osmand.osm.MapRenderObject;
import net.osmand.osm.MapRenderingTypes;
@ -35,7 +36,6 @@ import org.apache.commons.logging.Log;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.util.FloatMath;
public class MapRenderRepositories {
@ -47,18 +47,20 @@ public class MapRenderRepositories {
private Map<Connection, PreparedStatement> pZoom1 = new LinkedHashMap<Connection, PreparedStatement>();
private Map<Connection, PreparedStatement> pZoom2 = new LinkedHashMap<Connection, PreparedStatement>();
private OsmandRenderer renderer;
private double cTopY;
private double cBottomY;
private double cLeftX;
private double cRightX;
private int cZoom;
private float cRotate;
// cached objects in order to rotate without
// lat/lon box of requested vector data
private RectF cObjectsBox = new RectF();
// cached objects in order to render rotation without reloading data from db
private List<MapRenderObject> cObjects = new LinkedList<MapRenderObject>();
private RectF cachedWaysLoc = new RectF();
private float cachedRotate = 0;
// currently rendered box (not the same as already rendered)
// this box is checked for interrupted process or
private RotatedTileBox requestedBox = null;
// location of rendered bitmap
private RotatedTileBox bmpLocation = null;
// already rendered bitmap
private Bitmap bmp;
private boolean interrupted = false;
@ -179,14 +181,8 @@ public class MapRenderRepositories {
return bounds;
}
// if cache was changed different instance will be returned
public RectF getCachedWaysLoc() {
return cachedWaysLoc;
}
public float getCachedRotate() {
return cachedRotate;
public RotatedTileBox getBitmapLocation() {
return bmpLocation;
}
protected void closeConnection(Connection c, String file){
@ -208,32 +204,34 @@ public class MapRenderRepositories {
}
}
public boolean updateMapIsNeeded(RectF tileRect, int zoom, float rotate){
if (connections.isEmpty()) {
public boolean updateMapIsNeeded(RotatedTileBox box){
if (connections.isEmpty() || box == null) {
return false;
}
boolean inside = insideBox(tileRect.top, tileRect.left, tileRect.bottom, tileRect.right, zoom);
if(rotate < 0){
rotate += 360;
}
return !inside || Math.abs(rotate - cRotate) > 45; // leave only 15 to find that UI box out of searched
if(requestedBox == null){
return true;
}
if(requestedBox.getZoom() != box.getZoom()){
return true;
}
float deltaRotate = requestedBox.getRotate() - box.getRotate();
if(deltaRotate > 180){
deltaRotate -= 360;
} else if(deltaRotate < -180){
deltaRotate += 360;
}
if(Math.abs(deltaRotate) > 25){
return true;
}
return !requestedBox.containsTileBox(box);
}
public boolean isEmpty(){
return connections.isEmpty();
}
// MapUtils.getLatitudeFromTile(17, topY)
private boolean insideBox(double topY, double leftX, double bottomY, double rightX, int zoom) {
boolean inside = cZoom == zoom && cTopY <= topY && cLeftX <= leftX && cRightX >= rightX
&& cBottomY >= bottomY;
return inside;
}
private static String loadMapQuery = "SELECT "+IndexConstants.IndexMapRenderObject.ID +", " + IndexConstants.IndexMapRenderObject.NODES +", " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IndexConstants.IndexMapRenderObject.NAME + ", " + IndexConstants.IndexMapRenderObject.TYPE + //$NON-NLS-1$
" FROM " + IndexConstants.IndexMapRenderObject.getTable() + " WHERE "+IndexConstants.IndexMapRenderObject.ID+ //$NON-NLS-1$//$NON-NLS-2$
@ -261,151 +259,167 @@ public class MapRenderRepositories {
}
private boolean checkWhetherInterrupted(){
if(interrupted){
// clear zoom to enable refreshing next time
cZoom = 1;
if(interrupted || (currentRenderingContext != null && currentRenderingContext.interrupted)){
requestedBox = bmpLocation;
return true;
}
return false;
}
public synchronized void loadMap(RectF tileRect, RectF boundsTileRect, int zoom, float rotate) {
interrupted = false;
// currently doesn't work properly (every rotate bounds will be outside)
boolean inside = insideBox(boundsTileRect.top, boundsTileRect.left, boundsTileRect.bottom, boundsTileRect.right, zoom);
cRotate = rotate < 0 ? rotate + 360 : rotate;
if (!inside) {
cTopY = boundsTileRect.top;
cLeftX = boundsTileRect.left;
cRightX = boundsTileRect.right;
cBottomY = boundsTileRect.bottom;
double cBottomLatitude = MapUtils.getLatitudeFromTile(zoom, cBottomY);
double cTopLatitude = MapUtils.getLatitudeFromTile(zoom, cTopY);
double cLeftLongitude = MapUtils.getLongitudeFromTile(zoom, cLeftX);
double cRightLongitude = MapUtils.getLongitudeFromTile(zoom, cRightX);
cZoom = zoom;
private boolean loadVectorData(RectF dataBox, int zoom){
double cBottomLatitude = dataBox.bottom;
double cTopLatitude = dataBox.top;
double cLeftLongitude = dataBox.left;
double cRightLongitude = dataBox.right;
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, cZoom));
long now = System.currentTimeMillis();
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom));
long now = System.currentTimeMillis();
if (connections.isEmpty()) {
cObjectsBox = dataBox;
cObjects = new ArrayList<MapRenderObject>();
return true;
}
try {
int count = 0;
ArrayList<MapRenderObject> tempList = new ArrayList<MapRenderObject>();
System.gc(); // to clear previous objects
// Set<Long> ids = new HashSet<Long>(1000);
TLongSet ids = new TLongHashSet();
Map<Integer, List<MapRenderObject>> multiPolygons = new LinkedHashMap<Integer, List<MapRenderObject>>();
for (Connection c : connections.keySet()) {
RectF r = connections.get(c);
boolean intersects = r.top >= cBottomLatitude && r.left <= cRightLongitude && r.right >= cLeftLongitude &&
r.bottom <= cTopLatitude;
if(!intersects){
continue;
}
if (connections.isEmpty()) {
cObjects = new ArrayList<MapRenderObject>();
// keep old results
PreparedStatement statement = null;
if (zoom >= 15) {
statement = pZoom0.get(c);
} else if (zoom >= 10) {
statement = pZoom1.get(c);
} else if (zoom >= 6) {
statement = pZoom2.get(c);
} else {
// TODO show raster tiles ?
continue;
}
statement.setDouble(1, cBottomLatitude);
statement.setDouble(2, cTopLatitude);
statement.setDouble(3, cLeftLongitude);
statement.setDouble(4, cRightLongitude);
ResultSet result = statement.executeQuery();
try {
while (result.next()) {
long id = result.getLong(1);
if (PerformanceFlags.checkForDuplicateObjectIds) {
if (ids.contains(id)) {
// do not add object twice
continue;
}
ids.add(id);
}
int type = result.getInt(4);
MapRenderObject obj = new MapRenderObject(id);
obj.setType(type);
obj.setData(result.getBytes(2));
obj.setName(result.getString(3));
count++;
int mainType = obj.getMainType();
// be attentive we need 16 bits from main type (not 15 bits!)
// the last bit shows direction of multipolygon way
registerMultipolygon(multiPolygons, mainType, obj);
int sec = obj.getSecondType();
if(sec != 0){
registerMultipolygon(multiPolygons, sec, obj);
}
for (int k = 0; k < obj.getMultiTypes(); k++) {
registerMultipolygon(multiPolygons, obj.getAdditionalType(k), obj);
}
if(checkWhetherInterrupted()){
return false;
}
tempList.add(obj);
}
} finally {
result.close();
}
}
int leftX = MapUtils.get31TileNumberX(cLeftLongitude);
int rightX = MapUtils.get31TileNumberX(cRightLongitude);
int bottomY = MapUtils.get31TileNumberY(cBottomLatitude);
int topY = MapUtils.get31TileNumberY(cTopLatitude);
List<MultyPolygon> pMulti = proccessMultiPolygons(multiPolygons, leftX, rightX, bottomY, topY);
tempList.addAll(pMulti);
log.info(String.format("Search has been done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$NON-NLS-1$
cObjects = tempList;
cObjectsBox = dataBox;
} catch (java.sql.SQLException e) {
log.debug("Search failed", e); //$NON-NLS-1$
return false;
}
return true;
}
public synchronized void loadMap(RotatedTileBox tileRect) {
interrupted = false;
if(currentRenderingContext != null){
currentRenderingContext = null;
}
// prevent editing
requestedBox = new RotatedTileBox(tileRect);
// calculate data box
RectF dataBox = requestedBox.calculateLatLonBox(new RectF());
if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top ||
cObjectsBox.right < dataBox.right || cObjectsBox.bottom < dataBox.bottom) {
// increase data box in order for rotate
if ((dataBox.right - dataBox.left) > (dataBox.top - dataBox.bottom)) {
double wi = (dataBox.right - dataBox.left) * .2;
dataBox.left -= wi;
dataBox.right += wi;
} else {
double hi = (dataBox.bottom - dataBox.top) * .2;
dataBox.top -= hi;
dataBox.bottom += hi;
}
boolean loaded = loadVectorData(dataBox, requestedBox.getZoom());
if(!loaded || checkWhetherInterrupted()){
return;
}
try {
int count = 0;
cObjects = new ArrayList<MapRenderObject>();
System.gc(); // to clear previous objects
// Set<Long> ids = new HashSet<Long>(1000);
TLongSet ids = new TLongHashSet();
Map<Integer, List<MapRenderObject>> multiPolygons = new LinkedHashMap<Integer, List<MapRenderObject>>();
for (Connection c : connections.keySet()) {
RectF r = connections.get(c);
boolean intersects = r.top >= cBottomLatitude && r.left <= cRightLongitude && r.right >= cLeftLongitude &&
r.bottom <= cTopLatitude;
if(!intersects){
continue;
}
PreparedStatement statement = null;
if (zoom >= 15) {
statement = pZoom0.get(c);
} else if (zoom >= 10) {
statement = pZoom1.get(c);
} else if (zoom >= 6) {
statement = pZoom2.get(c);
} else {
// TODO show tiles ?
continue;
}
statement.setDouble(1, cBottomLatitude);
statement.setDouble(2, cTopLatitude);
statement.setDouble(3, cLeftLongitude);
statement.setDouble(4, cRightLongitude);
ResultSet result = statement.executeQuery();
try {
while (result.next()) {
long id = result.getLong(1);
if (PerformanceFlags.checkForDuplicateObjectIds) {
if (ids.contains(id)) {
// do not add object twice
continue;
}
ids.add(id);
}
int type = result.getInt(4);
MapRenderObject obj = new MapRenderObject(id);
obj.setType(type);
obj.setData(result.getBytes(2));
obj.setName(result.getString(3));
count++;
int mainType = obj.getMainType();
// be attentive we need 16 bits from main type (not 15 bits!)
// the last bit shows direction of multipolygon way
registerMultipolygon(multiPolygons, mainType, obj);
int sec = obj.getSecondType();
if(sec != 0){
registerMultipolygon(multiPolygons, sec, obj);
}
for (int k = 0; k < obj.getMultiTypes(); k++) {
registerMultipolygon(multiPolygons, obj.getAdditionalType(k), obj);
}
if(checkWhetherInterrupted()){
return;
}
cObjects.add(obj);
}
} finally {
result.close();
}
}
int leftX = MapUtils.get31TileNumberX(cLeftLongitude);
int rightX = MapUtils.get31TileNumberX(cRightLongitude);
int bottomY = MapUtils.get31TileNumberY(cBottomLatitude);
int topY = MapUtils.get31TileNumberY(cTopLatitude);
List<MultyPolygon> pMulti = proccessMultiPolygons(multiPolygons, leftX, rightX, bottomY, topY);
if(checkWhetherInterrupted()){
return;
}
cObjects.addAll(pMulti);
log.info(String
.format("Search has been done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$NON-NLS-1$
} catch (java.sql.SQLException e) {
log.debug("Search failed", e); //$NON-NLS-1$
}
}
// create new instance to distinguish that cache was changed
RectF newLoc = new RectF((float)MapUtils.getLongitudeFromTile(zoom, tileRect.left), (float)MapUtils.getLatitudeFromTile(zoom, tileRect.top),
(float)MapUtils.getLongitudeFromTile(zoom, tileRect.right), (float)MapUtils.getLatitudeFromTile(zoom, tileRect.bottom));
int width = (int) calcDiffPixelX(cRotate, tileRect.right - tileRect.left, tileRect.bottom - tileRect.top);
int height = (int) calcDiffPixelY(cRotate, tileRect.right - tileRect.left, tileRect.bottom - tileRect.top);
currentRenderingContext = new OsmandRenderer.RenderingContext();
currentRenderingContext.leftX = tileRect.left;
currentRenderingContext.topY = tileRect.top;
currentRenderingContext.zoom = cZoom;
currentRenderingContext.rotate = cRotate;
currentRenderingContext.width = width;
currentRenderingContext.height = height;
Bitmap bmp = renderer.generateNewBitmap(currentRenderingContext, cObjects, OsmandSettings.usingEnglishNames(context));
if(currentRenderingContext.interrupted){
cZoom = 1;
currentRenderingContext.leftX = (float) requestedBox.getLeftTileX();
currentRenderingContext.topY = (float) requestedBox.getTopTileY();
currentRenderingContext.zoom = requestedBox.getZoom();
currentRenderingContext.rotate = requestedBox.getRotate();
currentRenderingContext.width = (int) (requestedBox.getTileWidth() * OsmandRenderer.TILE_SIZE);
currentRenderingContext.height = (int) (requestedBox.getTileHeight() * OsmandRenderer.TILE_SIZE);
if(checkWhetherInterrupted()){
return;
}
Bitmap bmp = renderer.generateNewBitmap(currentRenderingContext, cObjects, OsmandSettings.usingEnglishNames(context));
if(checkWhetherInterrupted()){
currentRenderingContext = null;
return;
}
currentRenderingContext = null;
Bitmap oldBmp = this.bmp;
this.bmp = bmp;
cachedWaysLoc = newLoc;
cachedRotate = cRotate;
this.bmpLocation = tileRect;
if(oldBmp != null){
oldBmp.recycle();
}
@ -416,24 +430,15 @@ public class MapRenderRepositories {
return bmp;
}
public float calcDiffPixelX(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * OsmandRenderer.TILE_SIZE;
}
public float calcDiffPixelY(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * OsmandRenderer.TILE_SIZE;
}
public synchronized void clearCache() {
cObjects.clear();
cBottomY = cLeftX = cRightX = cTopY = cRotate = cZoom = 0;
cObjectsBox = new RectF();
if(bmp != null){
bmp.recycle();
bmp = null;
}
cachedWaysLoc = new RectF();
requestedBox = bmpLocation = null;
}

View file

@ -1,6 +1,7 @@
package net.osmand.render;
import net.osmand.ResourceManager;
import net.osmand.RotatedTileBox;
import net.osmand.osm.MapUtils;
import net.osmand.views.OsmandMapLayer;
import net.osmand.views.OsmandMapTileView;
@ -10,14 +11,13 @@ import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.FloatMath;
public class RendererLayer implements OsmandMapLayer {
private OsmandMapTileView view;
private final static int startZoom = 5;
private Rect pixRect = new Rect();
private RectF tileRect = new RectF();
private RotatedTileBox rotatedTileBox = new RotatedTileBox(0, 0, 0, 0, 0, 0);
private ResourceManager resourceManager;
private Paint paintImg;
@ -41,42 +41,55 @@ public class RendererLayer implements OsmandMapLayer {
paintImg = new Paint();
paintImg.setFilterBitmap(true);
}
private void updateRotatedTileBox(){
float ts = view.getTileSize();
float xL = view.calcDiffTileX(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY()) + view.getXTile();
float yT = view.calcDiffTileY(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY()) + view.getYTile();
rotatedTileBox.set(xL, yT, ((float) pixRect.width()) / ts, ((float) pixRect.height()) / ts, view.getRotate(), view.getZoom());
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (view.getZoom() >= startZoom && visible) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
if (view.getFloatZoom() == view.getZoom()
&& resourceManager.updateRenderedMapNeeded(tileRect, view.getZoom(), view.getRotate())) {
pixRect.set(-view.getWidth(), -view.getHeight()/2, 2*view.getWidth(), 3*view.getHeight()/2);
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
float xL = view.calcDiffTileX(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY()) + view.getXTile();
float xR = view.calcDiffTileX(pixRect.right - view.getCenterPointX(), pixRect.bottom - view.getCenterPointY()) + view.getXTile();
float yT = view.calcDiffTileY(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY())+ view.getYTile();
float yB = view.calcDiffTileY(pixRect.right - view.getCenterPointX(), pixRect.bottom - view.getCenterPointY()) + view.getYTile();
RectF verticesRect = new RectF(xL, yT, xR, yB);
resourceManager.updateRendererMap(verticesRect, tileRect, view.getZoom(), view.getRotate());
if (!view.isZooming()){
pixRect.set(0, 0, view.getWidth(), view.getHeight());
updateRotatedTileBox();
if(resourceManager.updateRenderedMapNeeded(rotatedTileBox)){
pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 * view.getHeight() / 2);
updateRotatedTileBox();
resourceManager.updateRendererMap(rotatedTileBox);
}
}
MapRenderRepositories renderer = resourceManager.getRenderer();
Bitmap bmp = renderer.getBitmap();
if (renderer != null && bmp != null) {
RectF newLoc = renderer.getCachedWaysLoc();
float rot = renderer.getCachedRotate();
float leftX1 = (float) MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.left);
float rightX1 = (float) MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.right);
float topY1 = (float) MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.top);
float bottomY1 = (float) MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.bottom);
float x1 = calcDiffPixelX(rot, leftX1 - view.getXTile(), topY1 - view.getYTile()) + view.getCenterPointX();
float y1 = calcDiffPixelY(rot, leftX1 - view.getXTile(), topY1 - view.getYTile()) + view.getCenterPointY();
float x2 = calcDiffPixelX(rot, rightX1 - view.getXTile(), bottomY1 - view.getYTile()) + view.getCenterPointX();
float y2 = calcDiffPixelY(rot, rightX1 - view.getXTile(), bottomY1 - view.getYTile()) + view.getCenterPointY();
RotatedTileBox bmpLoc = renderer.getBitmapLocation();
if (bmp != null && bmpLoc != null) {
float rot = bmpLoc.getRotate();
float mult = (float) MapUtils.getPowZoom(view.getZoom() - bmpLoc.getZoom());
float tx = view.getXTile();
float ty = view.getYTile();
float dleftX1 = (bmpLoc.getLeftTileX() * mult - tx) ;
float dtopY1 = (bmpLoc.getTopTileY() * mult - ty);
float cos = bmpLoc.getRotateCos();
float sin = bmpLoc.getRotateSin();
float x1 = MapUtils.calcDiffPixelX(sin, cos, dleftX1, dtopY1, view.getTileSize()) + view.getCenterPointX();
float y1 = MapUtils.calcDiffPixelY(sin, cos, dleftX1, dtopY1, view.getTileSize()) + view.getCenterPointY();
/*float drightX1 = (bmpLoc.getRightBottomTileX() * mult - tx) ;
float dbottomY1 = (bmpLoc.getRightBottomTileY() * mult - ty);
float x2 = MapUtils.calcDiffPixelX(sin, cos, drightX1, dbottomY1, view.getTileSize()) + view.getCenterPointX();
float y2 = MapUtils.calcDiffPixelY(sin, cos, drightX1, dbottomY1, view.getTileSize()) + view.getCenterPointY();
destImage.set(x1, y1, x2, y2);*/
canvas.rotate(-rot, view.getCenterPointX(), view.getCenterPointY());
destImage.set(x1, y1, x2, y2);
destImage.set(x1, y1, x1 + bmpLoc.getTileWidth() * mult * view.getTileSize(), y1 + bmpLoc.getTileHeight() * mult * view.getTileSize());
if(!bmp.isRecycled()){
canvas.drawBitmap(bmp, null, destImage, paintImg);
}
@ -84,16 +97,6 @@ public class RendererLayer implements OsmandMapLayer {
}
}
public float calcDiffPixelX(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * view.getTileSize();
}
public float calcDiffPixelY(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * view.getTileSize() ;
}
public void setVisible(boolean visible) {
this.visible = visible;
view.refreshMap();

View file

@ -93,7 +93,7 @@ public class ContextMenuLayer implements OsmandMapLayer {
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if(latLon != null){
int x = view.getMapXForPoint(latLon.getLongitude());
int y = view.getMapYForPoint(latLon.getLatitude());

View file

@ -7,7 +7,6 @@ import net.osmand.activities.FavouritesActivity;
import net.osmand.activities.FavouritesActivity.FavouritePoint;
import net.osmand.activities.FavouritesActivity.FavouritesDbHelper;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import android.content.Context;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Canvas;
@ -15,7 +14,6 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.util.DisplayMetrics;
@ -31,8 +29,6 @@ public class FavoritesLayer implements OsmandMapLayer, ContextMenuLayer.IContext
private OsmandMapTileView view;
private List<FavouritePoint> favouritePoints;
private List<FavouritePoint> additionalPoints;
private Rect pixRect = new Rect();
private RectF tileRect = new RectF();
private Path path;
private Path pathDst;
private Paint paint;
@ -76,7 +72,6 @@ public class FavoritesLayer implements OsmandMapLayer, ContextMenuLayer.IContext
paintBlack.setAntiAlias(true);
paintBlack.setStrokeWidth(2);
pixRect.set(0, 0, view.getWidth(), view.getHeight());
reloadFavorites(view.getContext());
}
@ -99,22 +94,17 @@ public class FavoritesLayer implements OsmandMapLayer, ContextMenuLayer.IContext
public boolean drawInScreenPixels() {
return false;
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (view.getZoom() >= startZoom) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(), view.getCenterPointY(), view.getXTile(), view.getYTile(),
tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
// request to load
for (FavouritePoint o : favouritePoints) {
if (o.getLatitude() <= topLatitude && o.getLatitude() >= bottomLatitude && o.getLongitude() >= leftLongitude
&& o.getLongitude() <= rightLongitude) {
if (o.getLatitude() >= latLonBounds.bottom && o.getLatitude() <= latLonBounds.top && o.getLongitude() >= latLonBounds.left
&& o.getLongitude() <= latLonBounds.right ) {
int x = view.getMapXForPoint(o.getLongitude());
int y = view.getMapYForPoint(o.getLatitude());
matrix.setTranslate(x, y);
@ -125,8 +115,8 @@ public class FavoritesLayer implements OsmandMapLayer, ContextMenuLayer.IContext
}
if(additionalPoints != null){
for (FavouritePoint o : additionalPoints) {
if (o.getLatitude() <= topLatitude && o.getLatitude() >= bottomLatitude && o.getLongitude() >= leftLongitude
&& o.getLongitude() <= rightLongitude) {
if (o.getLatitude() >= latLonBounds.bottom && o.getLatitude() <= latLonBounds.top && o.getLongitude() >= latLonBounds.left
&& o.getLongitude() <= latLonBounds.right ) {
int x = view.getMapXForPoint(o.getLongitude());
int y = view.getMapYForPoint(o.getLatitude());
matrix.setTranslate(x, y);

View file

@ -3,13 +3,11 @@ package net.osmand.views;
import java.util.ArrayList;
import java.util.List;
import net.osmand.osm.MapUtils;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
@ -21,8 +19,6 @@ public class GPXLayer implements OsmandMapLayer {
private OsmandMapTileView view;
private Rect boundsRect;
private RectF tileRect;
private List<List<Location>> points = new ArrayList<List<Location>>();
private Paint paint;
@ -34,8 +30,6 @@ public class GPXLayer implements OsmandMapLayer {
private void initUI() {
boundsRect = new Rect(0, 0, view.getWidth(), view.getHeight());
tileRect = new RectF();
paint = new Paint();
paint.setColor(Color.argb(180, 160, 10, 215));
paint.setStyle(Style.STROKE);
@ -56,20 +50,10 @@ public class GPXLayer implements OsmandMapLayer {
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if(points.isEmpty()){
return;
}
int w = view.getWidth();
int h = view.getHeight();
boundsRect = new Rect(0, 0, w, h);
view.calculateTileRectangle(boundsRect, view.getCenterPointX(), view.getCenterPointY(), view.getXTile(), view.getYTile(),
tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
for (List<Location> l : points) {
path.rewind();
@ -79,12 +63,12 @@ public class GPXLayer implements OsmandMapLayer {
for (int i = 0; i < l.size(); i++) {
Location ls = l.get(i);
if (startIndex == -1) {
if (leftLongitude <= ls.getLongitude() && ls.getLongitude() <= rightLongitude && bottomLatitude <= ls.getLatitude()
&& ls.getLatitude() <= topLatitude) {
if (ls.getLatitude() >= latLonBounds.bottom && ls.getLatitude() <= latLonBounds.top && ls.getLongitude() >= latLonBounds.left
&& ls.getLongitude() <= latLonBounds.right ) {
startIndex = i > 0 ? i - 1 : i;
}
} else if (!(leftLongitude <= ls.getLongitude() + 0.01 && ls.getLongitude() - 0.01 <= rightLongitude
&& bottomLatitude <= ls.getLatitude() + 0.01 && ls.getLatitude() - 0.01 <= topLatitude)) {
} else if (!(latLonBounds.left <= ls.getLongitude() + 0.01 && ls.getLongitude() - 0.01 <= latLonBounds.right
&& latLonBounds.bottom <= ls.getLatitude() + 0.01 && ls.getLatitude() - 0.01 <= latLonBounds.top)) {
endIndex = i;
// do not continue make method more efficient (because it calls in UI thread)
// this break also has logical sense !

View file

@ -190,7 +190,7 @@ public class MapInfoLayer implements OsmandMapLayer {
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latlonBounds) {
// prepare data (left distance, speed)
if(map.getPointToNavigate() != null){
int d = 0;
@ -287,18 +287,18 @@ public class MapInfoLayer implements OsmandMapLayer {
// update cache
if (view.getFloatZoom() != (int) view.getFloatZoom()) {
if (view.isZooming()) {
rulerDistName = null;
} else if(view.getFloatZoom() != rulerCZoom ||
} else if(view.getZoom() != rulerCZoom ||
Math.abs(view.getXTile() - rulerCTileX) + Math.abs(view.getYTile() - rulerCTileY) > 1){
rulerCZoom = (int) view.getFloatZoom();
rulerCZoom = view.getZoom();
rulerCTileX = view.getXTile();
rulerCTileY = view.getYTile();
double latitude = view.getLatitude();
double tileNumberLeft = rulerCTileX - ((double) view.getWidth()) / (2d * view.getTileSize());
double tileNumberRight = rulerCTileX + ((double) view.getWidth()) / (2d * view.getTileSize());
double dist = MapUtils.getDistance(latitude, MapUtils.getLongitudeFromTile(view.getFloatZoom(), tileNumberLeft), latitude,
MapUtils.getLongitudeFromTile(view.getFloatZoom(), tileNumberRight));
double dist = MapUtils.getDistance(latitude, MapUtils.getLongitudeFromTile(view.getZoom(), tileNumberLeft), latitude,
MapUtils.getLongitudeFromTile(view.getZoom(), tileNumberRight));
dist *= screenPercent;
int baseDist = 5;

View file

@ -91,7 +91,7 @@ public class MultiTouchSupport {
Float x2 = (Float) getX.invoke(event, 1);
Float y1 = (Float) getY.invoke(event, 0);
Float y2 = (Float) getY.invoke(event, 1);
float distance = FloatMath.sqrt((x2 - x1)*(x2 -x1) + (y2-y1)*(y2-y1));
float distance = FloatMath.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
previousZoom = distance / zoomStartedDistance;
if (actionCode == ACTION_POINTER_DOWN) {
centerPoint = new PointF((x1 + x2) / 2, (y1 + y2) / 2);

View file

@ -15,7 +15,6 @@ import net.osmand.LogUtil;
import net.osmand.OsmandSettings;
import net.osmand.R;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import org.apache.commons.logging.Log;
@ -29,7 +28,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Looper;
@ -49,8 +47,6 @@ public class OsmBugsLayer implements OsmandMapLayer, ContextMenuLayer.IContextMe
private OsmandMapTileView view;
private Handler handlerToLoop;
private Rect pixRect = new Rect();
private RectF tileRect = new RectF();
private List<OpenStreetBug> objects = new ArrayList<OpenStreetBug>();
private Paint pointClosedUI;
@ -98,7 +94,6 @@ public class OsmBugsLayer implements OsmandMapLayer, ContextMenuLayer.IContextMe
pointClosedUI.setColor(Color.GREEN);
pointClosedUI.setAlpha(200);
pointClosedUI.setAntiAlias(true);
pixRect.set(0, 0, view.getWidth(), view.getHeight());
}
@Override
@ -122,19 +117,10 @@ public class OsmBugsLayer implements OsmandMapLayer, ContextMenuLayer.IContextMe
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (view.getZoom() >= startZoom) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
// request to load
requestToLoad(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom());
requestToLoad(latLonBounds.top, latLonBounds.left, latLonBounds.bottom, latLonBounds.right, view.getZoom());
for (OpenStreetBug o : objects) {
int x = view.getMapXForPoint(o.getLongitude());
int y = view.getMapYForPoint(o.getLatitude());

View file

@ -2,13 +2,14 @@ package net.osmand.views;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
public interface OsmandMapLayer {
public void initLayer(OsmandMapTileView view);
public void onDraw(Canvas canvas);
public void onDraw(Canvas canvas, RectF latlonRect);
public void destroyLayer();

View file

@ -1,6 +1,5 @@
package net.osmand.views;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -45,69 +44,72 @@ import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.SurfaceHolder.Callback;
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback,
Callback, AnimateDraggingCallback, OnGestureListener, OnDoubleTapListener, MultiTouchZoomListener {
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback, AnimateDraggingCallback, OnGestureListener,
OnDoubleTapListener, MultiTouchZoomListener {
public static final int OVERZOOM_IN = 2;
protected final int emptyTileDivisor = 16;
public interface OnTrackBallListener{
public interface OnTrackBallListener {
public boolean onTrackBallEvent(MotionEvent e);
}
public interface OnLongClickListener {
public boolean onLongPressEvent(PointF point);
}
public interface OnClickListener {
public boolean onPressEvent(PointF point);
}
protected static final Log log = LogUtil.getLog(OsmandMapTileView.class);
/**
* zoom level - could be float to show zoomed tiles
*/
private float zoom = 3;
private double longitude = 0d;
private double latitude = 0d;
private float rotate = 0;
private float rotateSin = 0;
private float rotateCos = 1;
private int mapPosition;
private boolean showMapPosition = true;
// name of source map
// name of source map
private ITileSource map = null;
private IMapLocationListener locationListener;
private OnLongClickListener onLongClickListener;
private OnClickListener onClickListener;
private OnTrackBallListener trackBallDelegate;
private List<OsmandMapLayer> layers = new ArrayList<OsmandMapLayer>();
private Map<OsmandMapLayer, Float> zOrders = new HashMap<OsmandMapLayer, Float>();
// UI Part
// handler to refresh map (in ui thread - not necessary in ui thread, but msg queue is desirable).
// handler to refresh map (in ui thread - not necessary in ui thread, but msg queue is desirable).
protected Handler handler = new Handler();
private AnimateDraggingMapThread animatedDraggingThread;
private float initialMultiTouchZoom;
private PointF initialMultiTouchCenterPoint;
private LatLon initialMultiTouchLocation;
private GestureDetector gestureDetector;
private MultiTouchSupport multiTouchSupport;
Paint paintGrayFill;
Paint paintWhiteFill;
Paint paintCenter;
@ -116,22 +118,21 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
private DisplayMetrics dm;
private final OsmandApplication application;
public OsmandMapTileView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
application = (OsmandApplication) context.getApplicationContext();
}
public OsmandMapTileView(Context context) {
super(context);
initView();
application = (OsmandApplication) context.getApplicationContext();
}
/////////////////////////////// INITIALIZING UI PART ///////////////////////////////////
public void initView(){
// ///////////////////////////// INITIALIZING UI PART ///////////////////////////////////
public void initView() {
paintGrayFill = new Paint();
paintGrayFill.setColor(Color.GRAY);
paintGrayFill.setStyle(Style.FILL);
@ -143,35 +144,33 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
paintWhiteFill.setStyle(Style.FILL);
// when map rotate
paintWhiteFill.setAntiAlias(true);
paintCenter = new Paint();
paintCenter.setStyle(Style.STROKE);
paintCenter.setColor(Color.rgb(60, 60, 60));
paintCenter.setStrokeWidth(2);
paintCenter.setAntiAlias(true);
paintBitmap = new Paint();
paintBitmap.setFilterBitmap(true);
setClickable(true);
setLongClickable(true);
setFocusable(true);
getHolder().addCallback(this);
animatedDraggingThread = new AnimateDraggingMapThread();
animatedDraggingThread.setCallback(this);
gestureDetector = new GestureDetector(getContext(), this);
multiTouchSupport = new MultiTouchSupport(getContext(), this);
gestureDetector.setOnDoubleTapListener(this);
WindowManager mgr = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
dm = new DisplayMetrics();
mgr.getDefaultDisplay().getMetrics(dm);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
refreshMap();
@ -185,13 +184,11 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void addLayer(OsmandMapLayer layer, float zOrder){
int i=0;
for(i=0; i<layers.size(); i++){
if(zOrders.get(layers.get(i)) > zOrder){
public void addLayer(OsmandMapLayer layer, float zOrder) {
int i = 0;
for (i = 0; i < layers.size(); i++) {
if (zOrders.get(layers.get(i)) > zOrder) {
break;
}
}
@ -199,147 +196,156 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
layers.add(i, layer);
zOrders.put(layer, zOrder);
}
public void removeLayer(OsmandMapLayer layer){
public void removeLayer(OsmandMapLayer layer) {
layers.remove(layer);
zOrders.remove(layer);
layer.destroyLayer();
}
public List<OsmandMapLayer> getLayers() {
return layers;
}
public OsmandApplication getApplication() {
return application;
}
/////////////////////////// NON UI PART (could be extracted in common) /////////////////////////////
// ///////////////////////// NON UI PART (could be extracted in common) /////////////////////////////
/**
* Returns real tile size in pixels for float zoom .
*/
public float getTileSize() {
float res = map == null ? 256 : map.getTileSize();
if(zoom != (int) zoom){
res *= (float) Math.pow(2, zoom - (int) zoom);
}
// TODO introduce settings for these part
if(dm != null && dm.density > 1f){
res *= dm.density;
if (zoom != (int) zoom) {
res *= (float) Math.pow(2, zoom - (int) zoom);
}
// that trigger allows to scale tiles for certain devices
// for example for device with density > 1 draw tiles the same size as with density = 1
// It makes text bigger but blurry, the settings could be introduced for that
// if (dm != null && dm.density > 1f) {
// res *= dm.density;
// }
return res;
}
public int getSourceTileSize() {
return map == null ? 256 : map.getTileSize();
}
public float getXTile(){
return (float) MapUtils.getTileNumberX(zoom, longitude);
/**
* @return x tile based on (int) zoom
*/
public float getXTile() {
return (float) MapUtils.getTileNumberX(getZoom(), longitude);
}
public float getYTile(){
return (float) MapUtils.getTileNumberY(zoom, latitude);
/**
* @return y tile based on (int) zoom
*/
public float getYTile() {
return (float) MapUtils.getTileNumberY(getZoom(), latitude);
}
public void setZoom(float zoom){
if ((map == null && zoom < 22 && zoom > 0) ||
(map != null && (map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
public void setZoom(float zoom) {
if ((map == null && zoom < 22 && zoom > 0)
|| (map != null && (map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
animatedDraggingThread.stopAnimating();
this.zoom = zoom;
refreshMap();
}
}
// for internal usage
@Override
public void zoomTo(float zoom, boolean notify) {
if ((map == null && zoom < 23) ||
(map != null && (map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
if ((map == null && zoom < 23)
|| (map != null && (map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
this.zoom = zoom;
refreshMap();
if(notify && locationListener != null){
if (notify && locationListener != null) {
locationListener.locationChanged(latitude, longitude, this);
}
}
}
public void setRotate(float rotate) {
float dif = this.rotate - rotate;
if (dif > 2 || dif < -2) {
float diff = this.rotate - rotate;
if (diff > 4 || diff < -4) {
this.rotate = rotate;
float rotateRad = (float) Math.toRadians(rotate);
this.rotateCos = FloatMath.cos(rotateRad);
this.rotateSin = FloatMath.sin(rotateRad);
animatedDraggingThread.stopAnimating();
refreshMap();
}
}
public boolean isShowMapPosition() {
return showMapPosition;
}
public void setShowMapPosition(boolean showMapPosition) {
this.showMapPosition = showMapPosition;
}
public float getRotate() {
return rotate;
}
public ITileSource getMap() {
return map;
}
public void setMap(ITileSource map) {
this.map = map;
if(map !=null && map.getMaximumZoomSupported() + OVERZOOM_IN < this.zoom){
if (map != null && map.getMaximumZoomSupported() + OVERZOOM_IN < this.zoom) {
zoom = map.getMaximumZoomSupported() + OVERZOOM_IN;
}
if(map !=null && map.getMinimumZoomSupported() > this.zoom){
if (map != null && map.getMinimumZoomSupported() > this.zoom) {
zoom = map.getMinimumZoomSupported();
}
refreshMap();
}
public void setLatLon(double latitude, double longitude){
public void setLatLon(double latitude, double longitude) {
animatedDraggingThread.stopAnimating();
this.latitude = latitude;
this.longitude = longitude;
refreshMap();
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public int getZoom() {
return (int) zoom;
}
public float getFloatZoom(){
return zoom;
public boolean isZooming(){
return zoom != getZoom();
}
public void setMapLocationListener(IMapLocationListener l){
public void setMapLocationListener(IMapLocationListener l) {
locationListener = l;
}
/**
* Adds listener to control when map is dragging
* Adds listener to control when map is dragging
*/
public IMapLocationListener setMapLocationListener(){
public IMapLocationListener setMapLocationListener() {
return locationListener;
}
//////////////////////////////// DRAWING MAP PART /////////////////////////////////////////////
protected void drawEmptyTile(Canvas cvs, float x, float y, float ftileSize){
// ////////////////////////////// DRAWING MAP PART /////////////////////////////////////////////
protected void drawEmptyTile(Canvas cvs, float x, float y, float ftileSize) {
float tileDiv = (ftileSize / emptyTileDivisor);
for (int k1 = 0; k1 < emptyTileDivisor; k1++) {
for (int k2 = 0; k2 < emptyTileDivisor; k2++) {
@ -354,27 +360,26 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
public int getCenterPointX(){
public int getCenterPointX() {
return getWidth() / 2;
}
public int getCenterPointY(){
if(mapPosition == OsmandSettings.BOTTOM_CONSTANT){
public int getCenterPointY() {
if (mapPosition == OsmandSettings.BOTTOM_CONSTANT) {
return 3 * getHeight() / 4;
}
return getHeight() / 2;
}
public void setMapPosition(int type){
public void setMapPosition(int type) {
this.mapPosition = type;
}
private void drawOverMap(Canvas canvas){
private void drawOverMap(Canvas canvas, RectF latlonRect) {
int w = getCenterPointX();
int h = getCenterPointY();
canvas.restore();
for (int i = 0; i < layers.size(); i++) {
try {
OsmandMapLayer layer = layers.get(i);
@ -382,7 +387,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
if (!layer.drawInScreenPixels()) {
canvas.rotate(rotate, w, h);
}
layer.onDraw(canvas);
layer.onDraw(canvas, latlonRect);
canvas.restore();
} catch (IndexOutOfBoundsException e) {
// skip it
@ -393,8 +398,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
canvas.drawCircle(w, h, 7 * dm.density, paintCenter);
}
}
public void calculateTileRectangle(Rect pixRect, float cx, float cy, float ctilex, float ctiley, RectF tileRect){
public void calculateTileRectangle(Rect pixRect, float cx, float cy, float ctilex, float ctiley, 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);
@ -409,8 +414,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
float b = Math.max(Math.max(y1, y2), Math.max(y3, y4)) + ctiley;
tileRect.set(l, t, r, b);
}
public void calculatePixelRectangle(Rect pixelRect, float cx, float cy, float ctilex, float ctiley, RectF tileRect){
public void calculatePixelRectangle(Rect pixelRect, float cx, float cy, float ctilex, float ctiley, RectF tileRect) {
float x1 = calcDiffPixelX(tileRect.left - ctilex, tileRect.top - ctiley);
float x2 = calcDiffPixelX(tileRect.left - ctilex, tileRect.bottom - ctiley);
float x3 = calcDiffPixelX(tileRect.right - ctilex, tileRect.top - ctiley);
@ -425,49 +430,56 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
int b = Math.round(Math.max(Math.max(y1, y2), Math.max(y3, y4)) + cy);
pixelRect.set(l, t, r, b);
}
// used only to save space & reuse
// used only to save space & reuse
protected RectF tilesRect = new RectF();
protected RectF latlonRect = new RectF();
protected Rect boundsRect = new Rect();
protected RectF bitmapToDraw = new RectF();
protected Rect bitmapToZoom = new Rect();
private void refreshMapInternal(){
if(handler.hasMessages(1)){
private void refreshMapInternal() {
if (handler.hasMessages(1)) {
return;
}
boolean useInternet = OsmandSettings.isUsingInternetToDownloadTiles(getContext());
if (useInternet) {
MapTileDownloader.getInstance().refuseAllPreviousRequests();
MapTileDownloader.getInstance().refuseAllPreviousRequests();
}
float ftileSize = getTileSize();
int tileSize = map == null ? 256 : map.getTileSize();
float tileX = getXTile();
float tileY = getYTile();
float w = getCenterPointX();
float h = getCenterPointY();
int tileSize = getSourceTileSize();
SurfaceHolder holder = getHolder();
synchronized (holder) {
int nzoom = (int) zoom;
int nzoom = getZoom();
float tileX = (float) MapUtils.getTileNumberX(nzoom, longitude);
float tileY = (float) MapUtils.getTileNumberY(nzoom, latitude);
float w = getCenterPointX();
float h = getCenterPointY();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.save();
boundsRect.set(0, 0, getWidth(), getHeight());
canvas.rotate(rotate, w , h);
canvas.rotate(rotate, w, h);
try {
calculateTileRectangle(boundsRect, w, h, tileX, tileY, tilesRect);
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);
latlonRect.top = (float) MapUtils.getLatitudeFromTile(nzoom, tilesRect.top);
latlonRect.left = (float) MapUtils.getLongitudeFromTile(nzoom, tilesRect.left);
latlonRect.bottom = (float) MapUtils.getLatitudeFromTile(nzoom, tilesRect.bottom);
latlonRect.right = (float) MapUtils.getLongitudeFromTile(nzoom, tilesRect.right);
if (map != null) {
ResourceManager mgr = getApplication().getResourceManager();
useInternet = useInternet && OsmandSettings.isInternetConnectionAvailable(getContext())
&& map.couldBeDownloadedFromInternet();
int maxLevel = Math.min(OsmandSettings.getMaximumLevelToDownloadTile(getContext()), map.getMaximumZoomSupported());
calculateTileRectangle(boundsRect, w, h, tileX, tileY, tilesRect);
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 < width; i++) {
for (int j = 0; j < height; j++) {
float x1 = (i + left - tileX) * ftileSize + w;
@ -524,11 +536,6 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
} else {
calculateTileRectangle(boundsRect, w, h, tileX, tileY, tilesRect);
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 < width; i++) {
for (int j = 0; j < height; j++) {
float x1 = (i + left - tileX) * ftileSize + w;
@ -537,28 +544,29 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
}
drawOverMap(canvas);
drawOverMap(canvas, latlonRect);
} finally {
holder.unlockCanvasAndPost(canvas);
}
}
}
}
public boolean mapIsRefreshing(){
public boolean mapIsRefreshing() {
return handler.hasMessages(1);
}
public boolean mapIsAnimating(){
public boolean mapIsAnimating() {
return animatedDraggingThread != null && animatedDraggingThread.isAnimating();
}
// this method could be called in non UI thread
public void refreshMap() {
if(!handler.hasMessages(1)){
Message msg = Message.obtain(handler, new Runnable(){
if (!handler.hasMessages(1)) {
Message msg = Message.obtain(handler, new Runnable() {
@Override
public void run() {
public void run() {
refreshMapInternal();
}
});
@ -566,21 +574,20 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
handler.sendMessageDelayed(msg, 20);
}
}
public void tileDownloaded(DownloadRequest request) {
if (request == null || rotate != 0 ) {
if (request == null || rotate != 0) {
// if image is rotated call refresh the whole canvas
// because we can't find dirty rectangular region but all pixels should be drawn
// because we can't find dirty rectangular region
// we don't know exact images were changed
// if request null then we don't know exact images were changed
refreshMap();
return;
}
if(request.error){
if (request.error) {
return;
}
if (request.zoom != this.zoom) {
if (request.zoom != getZoom()) {
return;
}
float w = getCenterPointX();
@ -592,16 +599,16 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
synchronized (holder) {
tilesRect.set(request.xTile, request.yTile, request.xTile + 1, request.yTile + 1);
calculatePixelRectangle(boundsRect, w, h, tileX, tileY, tilesRect);
if(boundsRect.left > getWidth() || boundsRect.right < 0 || boundsRect.bottom < 0 || boundsRect.top > getHeight()){
if (boundsRect.left > getWidth() || boundsRect.right < 0 || boundsRect.bottom < 0 || boundsRect.top > getHeight()) {
return;
}
Canvas canvas = holder.lockCanvas(boundsRect);
if (canvas != null) {
canvas.save();
canvas.rotate(rotate, w , h);
canvas.rotate(rotate, w, h);
try {
Bitmap bmp = null;
if (map != null) {
@ -619,116 +626,107 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
bitmapToDraw.set(x, y, x + tileSize, y + tileSize);
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
}
drawOverMap(canvas);
drawOverMap(canvas, latlonRect);
} finally {
holder.unlockCanvasAndPost(canvas);
}
}
}
}
/////////////////////////////////// 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() );
// ///////////////////////////////// DRAGGING PART ///////////////////////////////////////
public float calcDiffTileY(float dx, float dy) {
return (-rotateSin * dx + rotateCos * 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() );
public float calcDiffTileX(float dx, float dy) {
return (rotateCos * dx + rotateSin * dy) / getTileSize();
}
public float calcDiffPixelY(float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * getTileSize() ;
public float calcDiffPixelY(float dTileX, float dTileY) {
return (rotateSin * dTileX + rotateCos * dTileY) * getTileSize();
}
public float calcDiffPixelX(float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * getTileSize() ;
public float calcDiffPixelX(float dTileX, float dTileY) {
return (rotateCos * dTileX - rotateSin * dTileY) * getTileSize();
}
/**
* These methods do not consider rotating
*/
public int getMapXForPoint(double longitude){
double tileX = MapUtils.getTileNumberX(zoom, longitude);
public int getMapXForPoint(double longitude) {
double tileX = MapUtils.getTileNumberX(getZoom(), longitude);
return (int) ((tileX - getXTile()) * getTileSize() + getCenterPointX());
}
public int getMapYForPoint(double latitude){
double tileY = MapUtils.getTileNumberY(zoom, latitude);
return (int) ((tileY - getYTile()) * getTileSize() + getCenterPointY());
public int getMapYForPoint(double latitude) {
double tileY = MapUtils.getTileNumberY(getZoom(), latitude);
return (int) ((tileY - getYTile()) * getTileSize() + getCenterPointY());
}
public int getRotatedMapXForPoint(double latitude, double longitude){
public int getRotatedMapXForPoint(double latitude, double longitude) {
int cx = getCenterPointX();
double xTile = MapUtils.getTileNumberX(zoom, longitude);
double yTile = MapUtils.getTileNumberY(zoom, latitude);
double xTile = MapUtils.getTileNumberX(getZoom(), longitude);
double yTile = MapUtils.getTileNumberY(getZoom(), latitude);
return (int) (calcDiffPixelX((float) (xTile - getXTile()), (float) (yTile - getYTile())) + cx);
}
public int getRotatedMapYForPoint(double latitude, double longitude){
public int getRotatedMapYForPoint(double latitude, double longitude) {
int cy = getCenterPointY();
double xTile = MapUtils.getTileNumberX(zoom, longitude);
double yTile = MapUtils.getTileNumberY(zoom, latitude);
double xTile = MapUtils.getTileNumberX(getZoom(), longitude);
double yTile = MapUtils.getTileNumberY(getZoom(), latitude);
return (int) (calcDiffPixelY((float) (xTile - getXTile()), (float) (yTile - getYTile())) + cy);
}
public boolean isPointOnTheRotatedMap(double latitude, double longitude){
public boolean isPointOnTheRotatedMap(double latitude, double longitude) {
int cx = getCenterPointX();
int cy = getCenterPointY();
double xTile = MapUtils.getTileNumberX(zoom, longitude);
double yTile = MapUtils.getTileNumberY(zoom, latitude);
double xTile = MapUtils.getTileNumberX(getZoom(), longitude);
double yTile = MapUtils.getTileNumberY(getZoom(), latitude);
int newX = (int) (calcDiffPixelX((float) (xTile - getXTile()), (float) (yTile - getYTile())) + cx);
int newY = (int) (calcDiffPixelY((float) (xTile - getXTile()), (float) (yTile - getYTile())) + cy);
if(newX >= 0 && newX <= getWidth() && newY >=0 && newY <= getHeight()){
if (newX >= 0 && newX <= getWidth() && newY >= 0 && newY <= getHeight()) {
return true;
}
}
return false;
}
@Override
public void dragTo(float fromX, float fromY, float toX, float toY, boolean notify){
float dx = (fromX - toX) ;
public void dragTo(float fromX, float fromY, float toX, float toY, boolean notify) {
float dx = (fromX - toX);
float dy = (fromY - toY);
moveTo(dx, dy);
if(locationListener != null && notify){
if (locationListener != null && notify) {
locationListener.locationChanged(latitude, longitude, this);
}
}
@Override
public void setLatLon(double latitude, double longitude, boolean notify) {
this.latitude = latitude;
this.longitude = longitude;
refreshMap();
if(locationListener != null && notify){
if (locationListener != null && notify) {
locationListener.locationChanged(latitude, longitude, this);
}
}
public void moveTo(float dx, float dy) {
float fy = calcDiffTileY(dx, dy);
float fx = calcDiffTileX(dx, dy);
this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + fy);
this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + fx);
this.latitude = MapUtils.getLatitudeFromTile(getZoom(), getYTile() + fy);
this.longitude = MapUtils.getLongitudeFromTile(getZoom(), getXTile() + fx);
refreshMap();
// do not notify here listener
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
animatedDraggingThread.stopAnimating();
}
if (!multiTouchSupport.onTouchEvent(event)) {
@ -736,69 +734,67 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
if(trackBallDelegate != null){
if (trackBallDelegate != null) {
trackBallDelegate.onTrackBallEvent(event);
}
return super.onTrackballEvent(event);
}
public void setTrackBallDelegate(OnTrackBallListener trackBallDelegate) {
this.trackBallDelegate = trackBallDelegate;
}
public void setOnLongClickListener(OnLongClickListener l) {
this.onLongClickListener = l;
}
public void setOnClickListener(OnClickListener l) {
this.onClickListener = l;
}
@Override
public boolean onDown(MotionEvent e) {
// enable double tap animation
// animatedDraggingThread.stopAnimating();
// enable double tap animation
// animatedDraggingThread.stopAnimating();
return false;
}
@Override
public void onZoomEnded(float distance, float relativeToStart) {
float dz = (float) (Math.log(relativeToStart) / Math.log(2) * 1.5);
float calcZoom = initialMultiTouchZoom + dz;
setZoom(Math.round(calcZoom));
zoomPositionChanged(getFloatZoom());
zoomPositionChanged(getZoom());
}
@Override
public void onZoomStarted(float distance, PointF centerPoint) {
initialMultiTouchCenterPoint = centerPoint;
initialMultiTouchLocation = getLatLonFromScreenPoint(centerPoint.x, centerPoint.y);
initialMultiTouchZoom = zoom;
}
private void zoomPositionChanged(float calcZoom){
float dtx = calcDiffTileX(getCenterPointX() - initialMultiTouchCenterPoint.x, getCenterPointY() - initialMultiTouchCenterPoint.y);
float dty = calcDiffTileY(getCenterPointX() - initialMultiTouchCenterPoint.x, getCenterPointY() - initialMultiTouchCenterPoint.y);
double tx = MapUtils.getTileNumberX(calcZoom, initialMultiTouchLocation.getLongitude());
double ty = MapUtils.getTileNumberY(calcZoom, initialMultiTouchLocation.getLatitude());
double lat = MapUtils.getLatitudeFromTile(calcZoom, ty + dty);
double lon = MapUtils.getLongitudeFromTile(calcZoom, tx + dtx);
private void zoomPositionChanged(float calcZoom) {
float dx = initialMultiTouchCenterPoint.x - getCenterPointX();
float dy = initialMultiTouchCenterPoint.y - getCenterPointY();
float ex = calcDiffTileX(dx, dy);
float ey = calcDiffTileY(dx, dy);
int z = (int)calcZoom;
double tx = MapUtils.getTileNumberX(z, initialMultiTouchLocation.getLongitude());
double ty = MapUtils.getTileNumberY(z, initialMultiTouchLocation.getLatitude());
double lat = MapUtils.getLatitudeFromTile(z, ty - ey);
double lon = MapUtils.getLongitudeFromTile(z, tx - ex);
setLatLon(lat, lon);
}
@Override
public void onZooming(float distance, float relativeToStart) {
float dz = (float) (Math.log(relativeToStart) / Math.log(2) * 1.5);
float calcZoom = initialMultiTouchZoom + dz;
if(Math.abs(calcZoom - zoom) > 0.05){
if (Math.abs(calcZoom - zoom) > 0.05) {
setZoom(calcZoom);
zoomPositionChanged(calcZoom);
}
@ -806,25 +802,26 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if(Math.abs(e1.getX() - e2.getX()) + Math.abs(e1.getX() - e2.getX()) > 50 * dm.density){
animatedDraggingThread.startDragging(Math.abs(velocityX/1000), Math.abs(velocityY/1000), e1.getX(), e1.getY(), e2.getX(), e2.getY());
if (Math.abs(e1.getX() - e2.getX()) + Math.abs(e1.getX() - e2.getX()) > 50 * dm.density) {
animatedDraggingThread.startDragging(Math.abs(velocityX / 1000), Math.abs(velocityY / 1000), e1.getX(), e1.getY(), e2.getX(),
e2.getY());
} else {
onScroll(e1, e2, e1.getX() - e2.getX(), e1.getY() - e2.getY());
}
return true;
}
public AnimateDraggingMapThread getAnimatedDraggingThread() {
return animatedDraggingThread;
}
@Override
public void onLongPress(MotionEvent e) {
if(multiTouchSupport.isInZoomMode()){
if (multiTouchSupport.isInZoomMode()) {
return;
}
if(log.isDebugEnabled()){
log.debug("On long click event "+ e.getX() + " " + e.getY()); //$NON-NLS-1$ //$NON-NLS-2$
if (log.isDebugEnabled()) {
log.debug("On long click event " + e.getX() + " " + e.getY()); //$NON-NLS-1$ //$NON-NLS-2$
}
PointF point = new PointF(e.getX(), e.getY());
for (int i = layers.size() - 1; i >= 0; i--) {
@ -832,12 +829,10 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
return;
}
}
if(onLongClickListener != null && onLongClickListener.onLongPressEvent(point)){
if (onLongClickListener != null && onLongClickListener.onLongPressEvent(point)) {
return;
}
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
@ -852,37 +847,35 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
@Override
public boolean onSingleTapUp(MotionEvent e) {
PointF point = new PointF(e.getX(), e.getY());
if(log.isDebugEnabled()){
log.debug("On click event "+ point.x + " " + point.y); //$NON-NLS-1$ //$NON-NLS-2$
if (log.isDebugEnabled()) {
log.debug("On click event " + point.x + " " + point.y); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int i = layers.size() - 1; i >= 0; i--) {
if (layers.get(i).onTouchEvent(point)) {
return true;
}
}
if(onClickListener != null && onClickListener.onPressEvent(point)){
if (onClickListener != null && onClickListener.onPressEvent(point)) {
return true;
}
return false;
}
public LatLon getLatLonFromScreenPoint(float x, float y){
public LatLon getLatLonFromScreenPoint(float x, float y) {
float dx = x - getCenterPointX();
float dy = y - getCenterPointY();
float fy = calcDiffTileY(dx, dy);
float fx = calcDiffTileX(dx, dy);
double latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + fx);
double latitude = MapUtils.getLatitudeFromTile(getZoom(), getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(getZoom(), getXTile() + fx);
return new LatLon(latitude, longitude);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
LatLon l = getLatLonFromScreenPoint(e.getX(), e.getY());
getAnimatedDraggingThread().startMoving(getLatitude(), getLongitude(),
l.getLatitude(), l.getLongitude(), getZoom(), getZoom() + 1, getSourceTileSize(), getRotate(), true);
getAnimatedDraggingThread().startMoving(getLatitude(), getLongitude(), l.getLatitude(), l.getLongitude(), getZoom(), getZoom() + 1,
getSourceTileSize(), getRotate(), true);
return true;
}
@ -895,9 +888,5 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
}

View file

@ -10,7 +10,6 @@ import net.osmand.ResourceManager;
import net.osmand.activities.EditingPOIActivity;
import net.osmand.data.Amenity;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@ -18,14 +17,12 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.widget.Toast;
public class POIMapLayer implements OsmandMapLayer, ContextMenuLayer.IContextMenuProvider {
// it is very slow to use with 15 level
private static final int startZoom = 10;
public static final int LIMIT_POI = 200;
@ -102,7 +99,6 @@ public class POIMapLayer implements OsmandMapLayer, ContextMenuLayer.IContextMen
pointAltUI.setAlpha(200);
pointAltUI.setAntiAlias(true);
resourceManager = view.getApplication().getResourceManager();
pixRect.set(0, 0, view.getWidth(), view.getHeight());
}
public int getRadiusPoi(int zoom){
@ -121,22 +117,12 @@ public class POIMapLayer implements OsmandMapLayer, ContextMenuLayer.IContextMen
return (int) (r * dm.density);
}
Rect pixRect = new Rect();
RectF tileRect = new RectF();
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (view.getZoom() >= startZoom) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
objects.clear();
resourceManager.searchAmenitiesAsync(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom(), filter, objects);
resourceManager.searchAmenitiesAsync(latLonBounds.top, latLonBounds.left, latLonBounds.bottom, latLonBounds.right, view.getZoom(), filter, objects);
for (Amenity o : objects) {
int x = view.getMapXForPoint(o.getLocation().getLongitude());
int y = view.getMapYForPoint(o.getLocation().getLatitude());

View file

@ -82,11 +82,11 @@ public class PointLocationLayer implements OsmandMapLayer {
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (isLocationVisible(lastKnownLocation)) {
int locationX = view.getMapXForPoint(lastKnownLocation.getLongitude());
int locationY = view.getMapYForPoint(lastKnownLocation.getLatitude());
int radius = MapUtils.getLengthXFromMeters(view.getFloatZoom(), view.getLatitude(), view.getLongitude(),
int radius = MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(),
lastKnownLocation.getAccuracy(), view.getTileSize(), view.getWidth());
if(appMode == ApplicationMode.CAR){
@ -111,7 +111,7 @@ public class PointLocationLayer implements OsmandMapLayer {
int radiusBearing = (int) (30 * dm.density);
if(lastKnownLocation.hasSpeed() && appMode != ApplicationMode.CAR){
radiusBearing =
Math.max(MapUtils.getLengthXFromMeters(view.getFloatZoom(), view.getLatitude(), view.getLongitude(),
Math.max(MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(),
lastKnownLocation.getSpeed(), view.getTileSize(), view.getWidth()) * 2, radiusBearing);
radiusBearing = Math.min(radiusBearing, view.getHeight() / 4);
}

View file

@ -8,6 +8,7 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.location.Location;
import android.util.DisplayMetrics;
@ -46,7 +47,7 @@ public class PointNavigationLayer implements OsmandMapLayer {
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if(pointToNavigate == null){
return;
}

View file

@ -165,7 +165,7 @@ public class RouteInfoLayer implements OsmandMapLayer, IRouteInformationListener
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if(isVisible()){
border.set(layout.getLeft() - 10 * dm.density, layout.getTop() - 4 * dm.density,
layout.getRight() - 5 * dm.density, layout.getBottom() + 4 * dm.density);

View file

@ -58,7 +58,7 @@ public class RouteLayer implements OsmandMapLayer {
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
path.reset();
if (helper.hasPointsToShow()) {
long time = System.currentTimeMillis();
@ -78,7 +78,7 @@ public class RouteLayer implements OsmandMapLayer {
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
double lat = topLatitude - bottomLatitude + 0.1;
double lon = rightLongitude - leftLongitude + 0.1;
helper.fillLocationsToShow(topLatitude +lat, leftLongitude - lon, bottomLatitude - lat, rightLongitude + lon, points);
helper.fillLocationsToShow(topLatitude + lat, leftLongitude - lon, bottomLatitude - lat, rightLongitude + lon, points);
if((System.currentTimeMillis() - time) > 80){
Log.e(LogUtil.TAG, "Calculate route layer " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
}

View file

@ -8,13 +8,11 @@ import net.osmand.activities.TransportRouteHelper;
import net.osmand.data.TransportRoute;
import net.osmand.data.TransportStop;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.WindowManager;
@ -23,9 +21,7 @@ import android.widget.Toast;
public class TransportInfoLayer implements OsmandMapLayer {
private final TransportRouteHelper routeHelper;
private Rect pixRect;
private OsmandMapTileView view;
private RectF tileRect;
private Paint paintInt;
private Paint paintEnd;
private boolean visible = true;
@ -37,8 +33,6 @@ public class TransportInfoLayer implements OsmandMapLayer {
public void initLayer(OsmandMapTileView view) {
this.view = view;
pixRect = new Rect();
tileRect = new RectF();
dm = new DisplayMetrics();
WindowManager wmgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
wmgr.getDefaultDisplay().getMetrics(dm);
@ -65,16 +59,9 @@ public class TransportInfoLayer implements OsmandMapLayer {
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if(routeHelper.routeIsCalculated() && visible){
List<RouteInfoLocation> list = routeHelper.getRoute();
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
for(RouteInfoLocation l : list){
if(l == null){
// once l is null in list
@ -100,8 +87,8 @@ public class TransportInfoLayer implements OsmandMapLayer {
}
if(start){
LatLon location = st.getLocation();
if(location.getLatitude() <= topLatitude && location.getLatitude() >= bottomLatitude &&
location.getLongitude() >= leftLongitude && location.getLongitude() <= rightLongitude){
if (location.getLatitude() >= latLonBounds.bottom && location.getLatitude() <= latLonBounds.top && location.getLongitude() >= latLonBounds.left
&& location.getLongitude() <= latLonBounds.right ) {
int x = view.getRotatedMapXForPoint(location.getLatitude(), location.getLongitude());
int y = view.getRotatedMapYForPoint(location.getLatitude(), location.getLongitude());
canvas.drawRect(x - getRadius(), y - getRadius(), x + getRadius(), y + getRadius(), toShow);

View file

@ -8,14 +8,12 @@ import net.osmand.R;
import net.osmand.TransportIndexRepository;
import net.osmand.data.TransportStop;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import android.content.Context;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.WindowManager;
@ -41,7 +39,6 @@ public class TransportStopsLayer implements OsmandMapLayer, ContextMenuLayer.ICo
pointAltUI.setColor(Color.rgb(0, 0, 255));
pointAltUI.setAlpha(150);
pointAltUI.setAntiAlias(true);
pixRect.set(0, 0, view.getWidth(), view.getHeight());
}
public TransportStop getFromPoint(PointF point){
@ -116,22 +113,12 @@ public class TransportStopsLayer implements OsmandMapLayer, ContextMenuLayer.ICo
}
}
Rect pixRect = new Rect();
RectF tileRect = new RectF();
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (view.getZoom() >= startZoom) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.top);
double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right);
objects.clear();
view.getApplication().getResourceManager().searchTransportAsync(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom(), objects);
view.getApplication().getResourceManager().searchTransportAsync(latLonBounds.top, latLonBounds.left, latLonBounds.bottom, latLonBounds.right, view.getZoom(), objects);
int r = 3 * getRadiusPoi(view.getZoom()) / 4;
for (TransportStop o : objects) {
int x = view.getMapXForPoint(o.getLocation().getLongitude());

View file

@ -208,16 +208,15 @@ public class YandexTrafficLayer implements OsmandMapLayer {
}
@Override
public void onDraw(Canvas canvas) {
public void onDraw(Canvas canvas, RectF latLonBounds) {
if (visible) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
double lat = MapUtils.getLatitudeFromTile(view.getFloatZoom(), view.getYTile());
float tileY = (float) MapUtils.getTileEllipsoidNumberY(view.getFloatZoom(), lat);
float tileY = (float) MapUtils.getTileEllipsoidNumberY(view.getZoom(), view.getLatitude());
view.calculateTileRectangle(pixRect, view.getCenterPointX(), view.getCenterPointY(), view.getXTile(), tileY, tileRect);
double topLat = MapUtils.getLatitudeFromEllipsoidTileY(view.getFloatZoom(), (int) tileRect.top);
double leftLon = MapUtils.getLongitudeFromTile(view.getFloatZoom(), (int) tileRect.left);
int x = view.getRotatedMapXForPoint(topLat, leftLon);
int y = view.getRotatedMapYForPoint(topLat, leftLon);
double topLat = MapUtils.getLatitudeFromEllipsoidTileY(view.getZoom(), (int) tileRect.top);
double leftLon = MapUtils.getLongitudeFromTile(view.getZoom(), (int) tileRect.left);
int x = view.getMapXForPoint(leftLon);
int y = view.getMapYForPoint(topLat);
checkedCachedImages(view.getZoom());
float right = FloatMath.ceil(tileRect.right);
float bottom = FloatMath.ceil(tileRect.bottom);