package dk.network42.osmfocus; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Locale; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.util.DisplayMetrics; import android.util.Log; public class OsmTile { private static final String TAG = "OsmTile"; public static final int MIN_ZOOM = 0; public static final int MAX_ZOOM = 18; // Standard OSM and mapnik public static final int ZOOM_LEVELS = MAX_ZOOM-MIN_ZOOM; // See http://wiki.openstreetmap.org/wiki/Tile_usage_policy public static final int MAX_DOWNLOAD_THREADS = 2; public int mX, mY, mZoom; int mDownloadErrs = 0; boolean mDownloadOngoing = false; // FIXME: This should not be part of OsmTile, but rather an inherited class private Bitmap mBitmap = null; // Geo coords protected GeoBBox mBox; protected RectF mBox2 = new RectF(); // FIXME: Merge bboxes // Screen coords (scaled and Mercator latitudes) protected RectF mViewBox = new RectF(); public OsmTile(int x, int y, int zoom) { mX = x; mY = y; mZoom = zoom; mBox = tile2BBox(x, y, zoom); mBox2.left = (float)(((float)mBox.left)/1E7); mBox2.right = (float)(((float)mBox.right)/1E7); mBox2.top = (float)(((float)mBox.bottom)/1E7); mBox2.bottom = (float)(((float)mBox.top)/1E7); mViewBox.left = (float) MapView.prescale * mBox2.left; mViewBox.right = (float) MapView.prescale * mBox2.right; mViewBox.top = (float)(MapView.prescale * GeoMath.latToMercator(mBox2.top)); mViewBox.bottom = (float)(MapView.prescale * GeoMath.latToMercator(mBox2.bottom)); } public OsmTile(double lon, double lat, int zoom) { this(lon2tile(lon, zoom), lat2tile(lat, zoom), zoom); } public Bitmap getBitmap() { return mBitmap; } public int getByteSize() { // FIXME: Wrong for vector tiles return 4*256*256; // Fixed tile size for OSM in ARGB_8888 // Log.d(TAG, "Get size of tile "+this); // Bitmap bm = getBitmap(); // if (bm==null) { // Log.d(TAG, " = 0"); // return 0; // } // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // return getBitmap().getAllocationByteCount(); // } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { // return bm.getRowBytes() * bm.getHeight(); // } } public boolean canDraw(Canvas canvas, PaintConfig pcfg) { if (mBitmap != null) { return true; } return false; } public boolean draw(Canvas canvas, PaintConfig pcfg) { if (mBitmap != null) { //Log.d(TAG, "Draw bitmap at "+mBox2+" ("+mViewBox+") zoom="+mZoom); canvas.drawBitmap(mBitmap, null, mViewBox, pcfg.paint); return true; } else if (mDownloadErrs>0) { drawError(canvas, pcfg); } return false; } public void drawX(Canvas canvas, PaintConfig pcfg) { canvas.drawLine(mViewBox.left, mViewBox.bottom, mViewBox.right, mViewBox.top, pcfg.paint); canvas.drawLine(mViewBox.left, mViewBox.top, mViewBox.right, mViewBox.bottom, pcfg.paint); } public void drawP(Canvas canvas, PaintConfig pcfg) { float xc = (mViewBox.left+mViewBox.right)/2; float yc = (mViewBox.bottom+mViewBox.top)/2; canvas.drawLine(mViewBox.left, yc, mViewBox.right, yc, pcfg.paint); canvas.drawLine(xc, mViewBox.top, xc, mViewBox.bottom, pcfg.paint); } public void drawFade(Canvas canvas, PaintConfig pcfg) { canvas.drawRect(mViewBox, pcfg.fade); } public void drawError(Canvas canvas, PaintConfig pcfg) { canvas.drawRect(mViewBox, pcfg.tileerr); } // public void drawText(Canvas canvas, Paint paint, String st) { // float w = paint.measureText(st); // canvas.drawText(st, mViewBox.centerX(), mViewBox.centerY(), paint); // } public void setQueuedForDownload() { assert(mDownloadOngoing==false); mDownloadOngoing = true; } public void clearQueuedForDownload() { assert(mDownloadOngoing==true); mDownloadOngoing = false; } public boolean isQueuedForDownload() { return mDownloadOngoing; } public boolean download(String useragent, String provider) { Bitmap bm = dlFromUrl(tileUrl(provider)); if (bm != null) { mBitmap = flipBitmap(bm); //Log.d(TAG, "Download done"); return true; } else { Log.e(TAG, "Download failed, tile="+this); return false; } } private Bitmap dlFromUrl(String tileurl) { try { //Log.d(TAG, "Loading tile "+tileurl); URL url = new URL(tileurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty("User-Agent", MainActivity.userAgent); conn.setDoInput(true); //Log.d(TAG, "Connect for tile download"); conn.connect(); InputStream input = conn.getInputStream(); //Log.d(TAG, "Decode bitmap"); Bitmap bm = BitmapFactory.decodeStream(input); //Log.d(TAG, "Downloaded tile "+tileurl+", bbox="+mBox.toString()); return bm; } catch (IOException e) { e.printStackTrace(); return null; } } private Bitmap flipBitmap(Bitmap bm) { Matrix m = new Matrix(); m.preScale(1, -1); Bitmap bmf = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, false); if (bmf!=null) bmf.setDensity(DisplayMetrics.DENSITY_DEFAULT); return bmf; } static public int lon2tile(double lon, int zoom) { int xtile = (int)Math.floor((lon + 180.0)/360.0 * (1<= (1<= (1<