change format of tile/ enable downloading from internet tiles (for android)
git-svn-id: https://osmand.googlecode.com/svn/trunk@27 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
parent
57475433ec
commit
d786dcdd60
11 changed files with 283 additions and 80 deletions
|
@ -1,4 +1,4 @@
|
||||||
.level = ERROR
|
.level = SEVERE
|
||||||
handlers=java.util.logging.ConsoleHandler
|
handlers=java.util.logging.ConsoleHandler
|
||||||
|
|
||||||
# Set the default logging level for the logger named com.mycompany
|
# Set the default logging level for the logger named com.mycompany
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.osmand;
|
package com.osmand;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -46,4 +47,17 @@ public class Algoritms {
|
||||||
log.warn("Closing stream warn", e);
|
log.warn("Closing stream warn", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateAllExistingImgTilesToOsmandFormat(File f){
|
||||||
|
if(f.isDirectory()){
|
||||||
|
for(File c : f.listFiles()){
|
||||||
|
updateAllExistingImgTilesToOsmandFormat(c);
|
||||||
|
}
|
||||||
|
} else if(f.getName().endsWith(".png") || f.getName().endsWith(".jpg")){
|
||||||
|
f.renameTo(new File(f.getAbsolutePath() + ".tile"));
|
||||||
|
} else if(f.getName().endsWith(".andnav2")) {
|
||||||
|
f.renameTo(new File(f.getAbsolutePath().substring(0, f.getAbsolutePath().length() - ".andnav2".length()) + ".tile"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,8 +352,10 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
final JTextField textField = new JTextField();
|
final JTextField textField = new JTextField();
|
||||||
final JButton button = new JButton();
|
final JButton button = new JButton();
|
||||||
button.setText("Set town");
|
button.setText("Set town");
|
||||||
|
|
||||||
|
|
||||||
panel.add(textField, BorderLayout.CENTER);
|
panel.add(textField, BorderLayout.CENTER);
|
||||||
panel.add(button, BorderLayout.EAST);
|
panel.add(button, BorderLayout.WEST);
|
||||||
|
|
||||||
content.add(panel, BorderLayout.NORTH);
|
content.add(panel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ public abstract class DefaultLauncherConstants {
|
||||||
public static int MAP_divNonLoadedImage = 8;
|
public static int MAP_divNonLoadedImage = 8;
|
||||||
public static boolean loadMissingImages = true;
|
public static boolean loadMissingImages = true;
|
||||||
public static ITileSource MAP_defaultTileSource = TileSourceManager.getMapnikSource();
|
public static ITileSource MAP_defaultTileSource = TileSourceManager.getMapnikSource();
|
||||||
|
public static boolean showGPSCoordinates = true;
|
||||||
|
|
||||||
|
|
||||||
// Application constants
|
// Application constants
|
||||||
|
@ -34,7 +35,7 @@ public abstract class DefaultLauncherConstants {
|
||||||
// Download manager tile settings
|
// Download manager tile settings
|
||||||
public static int TILE_DOWNLOAD_THREADS = 4;
|
public static int TILE_DOWNLOAD_THREADS = 4;
|
||||||
public static int TILE_DOWNLOAD_SECONTS_TO_WORK = 25;
|
public static int TILE_DOWNLOAD_SECONTS_TO_WORK = 25;
|
||||||
|
public static final int TILE_DOWNLOAD_MAX_ERRORS = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -196,16 +196,27 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String getFileForImage (int x, int y, int zoom){
|
|
||||||
return map.getName() +"/"+zoom+"/"+(x) +"/"+y+".png";
|
public File getTilesLocation() {
|
||||||
|
return tilesLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Image getImageFor(int x, int y, int zoom) throws IOException{
|
public void setTilesLocation(File tilesLocation) {
|
||||||
|
this.tilesLocation = tilesLocation;
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getFileForImage (int x, int y, int zoom, String ext){
|
||||||
|
return map.getName() +"/"+zoom+"/"+(x) +"/"+y+ext+".tile";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getImageFor(int x, int y, int zoom, boolean loadIfNeeded) throws IOException{
|
||||||
if(map == null){
|
if(map == null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String file = getFileForImage(x, y, zoom);
|
String file = getFileForImage(x, y, zoom, map.getTileFormat());
|
||||||
if(!cache.containsKey(file)){
|
if(cache.get(file) == null){
|
||||||
File en = new File(tilesLocation, file);
|
File en = new File(tilesLocation, file);
|
||||||
if(cache.size() > 1000){
|
if(cache.size() > 1000){
|
||||||
ArrayList<String> list = new ArrayList<String>(cache.keySet());
|
ArrayList<String> list = new ArrayList<String>(cache.keySet());
|
||||||
|
@ -213,7 +224,8 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
cache.remove(list.get(i));
|
cache.remove(list.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(en.exists() && !downloader.isFileCurrentlyDownloaded(en)){
|
if (!downloader.isFileCurrentlyDownloaded(en)) {
|
||||||
|
if (en.exists()) {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
cache.put(file, ImageIO.read(en));
|
cache.put(file, ImageIO.read(en));
|
||||||
|
@ -224,6 +236,13 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
log.error("Eror reading png " + x + " " + y + " zoom : " + zoom, e);
|
log.error("Eror reading png " + x + " " + y + " zoom : " + zoom, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(loadIfNeeded && cache.get(file) == null){
|
||||||
|
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
||||||
|
if (urlToLoad != null) {
|
||||||
|
downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache.get(file);
|
return cache.get(file);
|
||||||
|
@ -239,7 +258,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
if(request.zoom == this.zoom &&
|
if(request.zoom == this.zoom &&
|
||||||
(i >=0 && i<images.length) && (j>=0 && j< images[i].length)){
|
(i >=0 && i<images.length) && (j>=0 && j< images[i].length)){
|
||||||
try {
|
try {
|
||||||
images[i][j] = getImageFor(request.xTile, request.yTile, zoom);
|
images[i][j] = getImageFor(request.xTile, request.yTile, zoom, false);
|
||||||
repaint();
|
repaint();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Eror reading png " + request.xTile +" " + request.yTile + " zoom : " + zoom, e);
|
log.error("Eror reading png " + request.xTile +" " + request.yTile + " zoom : " + zoom, e);
|
||||||
|
@ -281,15 +300,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
for (int j = 0; j < images[i].length; j++) {
|
for (int j = 0; j < images[i].length; j++) {
|
||||||
int x= (int) xTileLeft + i;
|
int x= (int) xTileLeft + i;
|
||||||
int y = (int) yTileUp + j;
|
int y = (int) yTileUp + j;
|
||||||
images[i][j] = getImageFor(x, y, zoom);
|
images[i][j] = getImageFor(x, y, zoom, loadNecessaryImages);
|
||||||
if(loadNecessaryImages && images[i][j] == null && map != null){
|
|
||||||
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
|
||||||
if(urlToLoad != null){
|
|
||||||
downloader.requestToDownload(urlToLoad,
|
|
||||||
new DownloadRequest(new File(tilesLocation, getFileForImage(x, y, zoom)),
|
|
||||||
x, y, zoom));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,6 +358,12 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
|
|
||||||
public void setMapName(ITileSource map){
|
public void setMapName(ITileSource map){
|
||||||
this.map = map;
|
this.map = map;
|
||||||
|
if(map.getMaximumZoomSupported() < this.zoom){
|
||||||
|
zoom = map.getMaximumZoomSupported();
|
||||||
|
}
|
||||||
|
if(map.getMinimumZoomSupported() > this.zoom){
|
||||||
|
zoom = map.getMinimumZoomSupported();
|
||||||
|
}
|
||||||
prepareImage();
|
prepareImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,16 @@ public class MapTileDownloader {
|
||||||
private static MapTileDownloader downloader = null;
|
private static MapTileDownloader downloader = null;
|
||||||
private static Log log = LogFactory.getLog(MapTileDownloader.class);
|
private static Log log = LogFactory.getLog(MapTileDownloader.class);
|
||||||
|
|
||||||
|
|
||||||
private ThreadPoolExecutor threadPoolExecutor;
|
private ThreadPoolExecutor threadPoolExecutor;
|
||||||
private IMapDownloaderCallback callback;
|
private IMapDownloaderCallback callback;
|
||||||
|
|
||||||
private Set<File> currentlyDownloaded;
|
private Set<File> currentlyDownloaded;
|
||||||
|
|
||||||
|
private int currentErrors = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static MapTileDownloader getInstance(){
|
public static MapTileDownloader getInstance(){
|
||||||
if(downloader == null){
|
if(downloader == null){
|
||||||
|
@ -97,6 +102,11 @@ public class MapTileDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestToDownload(String url, DownloadRequest request){
|
public void requestToDownload(String url, DownloadRequest request){
|
||||||
|
if(DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS > 0 &&
|
||||||
|
currentErrors > DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFileCurrentlyDownloaded(request.fileToSave)) {
|
if (!isFileCurrentlyDownloaded(request.fileToSave)) {
|
||||||
threadPoolExecutor.execute(new DownloadMapWorker(url, request));
|
threadPoolExecutor.execute(new DownloadMapWorker(url, request));
|
||||||
}
|
}
|
||||||
|
@ -147,8 +157,10 @@ public class MapTileDownloader {
|
||||||
callback.tileDownloaded(downloadUrl, request);
|
callback.tileDownloaded(downloadUrl, request);
|
||||||
}
|
}
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
|
currentErrors++;
|
||||||
log.error("UnknownHostException, cannot download tile " + downloadUrl, e);
|
log.error("UnknownHostException, cannot download tile " + downloadUrl, e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
currentErrors++;
|
||||||
log.warn("Cannot download tile : " + downloadUrl, e);
|
log.warn("Cannot download tile : " + downloadUrl, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
DataExtractionOSM/src/com/osmand/ToDoConstants.java
Normal file
14
DataExtractionOSM/src/com/osmand/ToDoConstants.java
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package com.osmand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is designed to put all to do's and link them with code.
|
||||||
|
* The whole methods could be paste or just constants.
|
||||||
|
* Do not worry to put ugly code here (just a little piece)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ToDoConstants {
|
||||||
|
|
||||||
|
|
||||||
|
public int CONFIG_COMMONS_LOGGING_IN_ANDROID = 1;
|
||||||
|
|
||||||
|
}
|
|
@ -72,9 +72,12 @@ public class TileSourceManager {
|
||||||
list.add(getCloudMadeSource());
|
list.add(getCloudMadeSource());
|
||||||
list.add(getOpenPisteMapSource());
|
list.add(getOpenPisteMapSource());
|
||||||
list.add(getGoogleMapsSource());
|
list.add(getGoogleMapsSource());
|
||||||
// TODO ?
|
list.add(getGoogleMapsSatelliteSource());
|
||||||
// list.add(getGoogleMapsSatelliteSource());
|
list.add(getGoogleMapsTerrainSource());
|
||||||
// list.add(getGoogleMapsTerrainSource());
|
list.add(getMicrosoftMapsSource());
|
||||||
|
list.add(getMicrosoftEarthSource());
|
||||||
|
list.add(getMicrosoftHybridSource());
|
||||||
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
|
@ -112,11 +115,74 @@ public class TileSourceManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TileSourceTemplate getGoogleMapsSatelliteSource(){
|
public static TileSourceTemplate getGoogleMapsSatelliteSource(){
|
||||||
return new TileSourceTemplate("GoogleMaps Satellite", "http://khm1.google.com/kh/v=37&x={1}&y={2}&z={0}", ".png", 19, 0, 256, 18000);
|
return new TileSourceTemplate("GoogleMaps Satellite", "http://khm1.google.com/kh/v=59&x={1}&y={2}&z={0}", ".jpg", 20, 0, 256, 18000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TileSourceTemplate getGoogleMapsTerrainSource(){
|
public static TileSourceTemplate getGoogleMapsTerrainSource(){
|
||||||
return new TileSourceTemplate("GoogleMaps Terrain", "http://mt3.google.com/mt/v=w2.87&x={1}&y={2}&z={0}", ".png", 15, 0, 256, 18000);
|
return new TileSourceTemplate("GoogleMaps Terrain", "http://mt3.google.com/vt/v=w2p.111&hl=en&x={1}&y={2}&z={0}", ".jpg", 15, 0, 256, 18000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TileSourceTemplate getMicrosoftMapsSource(){
|
||||||
|
return new MicrosoftTileSourceTemplate("Microsoft Maps", 'r', "png", ".png", 19, 1, 256, 18000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TileSourceTemplate getMicrosoftEarthSource(){
|
||||||
|
return new MicrosoftTileSourceTemplate("Microsoft Earth", 'a', "jpg", ".jpg", 19, 1, 256, 18000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TileSourceTemplate getMicrosoftHybridSource(){
|
||||||
|
return new MicrosoftTileSourceTemplate("Microsoft Hybrid", 'h', "jpg", ".jpg", 19, 1, 256, 18000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static final char[] NUM_CHAR = { '0', '1', '2', '3' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See: http://msdn.microsoft.com/en-us/library/bb259689.aspx
|
||||||
|
* @param zoom
|
||||||
|
* @param tilex
|
||||||
|
* @param tiley
|
||||||
|
* @return quadtree encoded tile number
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static String encodeQuadTree(int zoom, int tilex, int tiley) {
|
||||||
|
char[] tileNum = new char[zoom];
|
||||||
|
for (int i = zoom - 1; i >= 0; i--) {
|
||||||
|
// Binary encoding using ones for tilex and twos for tiley. if a bit
|
||||||
|
// is set in tilex and tiley we get a three.
|
||||||
|
int num = (tilex % 2) | ((tiley % 2) << 1);
|
||||||
|
tileNum[i] = NUM_CHAR[num];
|
||||||
|
tilex >>= 1;
|
||||||
|
tiley >>= 1;
|
||||||
|
}
|
||||||
|
return new String(tileNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MicrosoftTileSourceTemplate extends TileSourceTemplate {
|
||||||
|
|
||||||
|
private final char mapTypeChar;
|
||||||
|
int serverNum = 0; // 0..3
|
||||||
|
protected String urlBase = ".ortho.tiles.virtualearth.net/tiles/";
|
||||||
|
protected String urlAppend = "?g=45";
|
||||||
|
private final String tileType;
|
||||||
|
|
||||||
|
public MicrosoftTileSourceTemplate(String name, char mapTypeChar , String type,
|
||||||
|
String ext, int maxZoom, int minZoom, int tileSize, int avgSize) {
|
||||||
|
super(name, null, ext, maxZoom, minZoom, tileSize, avgSize);
|
||||||
|
this.mapTypeChar = mapTypeChar;
|
||||||
|
this.tileType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUrlToLoad(int x, int y, int zoom) {
|
||||||
|
String tileNum = encodeQuadTree(zoom, x, y);
|
||||||
|
// serverNum = (serverNum + 1) % serverNumMax;
|
||||||
|
return "http://" + mapTypeChar + serverNum + urlBase + mapTypeChar + tileNum + "."
|
||||||
|
+ tileType + urlAppend;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,6 @@
|
||||||
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"></uses-permission>
|
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"></uses-permission>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
|
||||||
</manifest>
|
</manifest>
|
|
@ -40,7 +40,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
|
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
mapView = (OsmandMapTileView) findViewById(R.id.View01);
|
mapView = (OsmandMapTileView) findViewById(R.id.View01);
|
||||||
mapView.setFileWithTiles(new File(Environment.getExternalStorageDirectory(), "osmand/tiles/Mapnik"));
|
mapView.setFileWithTiles(new File(Environment.getExternalStorageDirectory(), "osmand/tiles/"));
|
||||||
mapView.addMapLocationListener(this);
|
mapView.addMapLocationListener(this);
|
||||||
|
|
||||||
ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls01);
|
ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls01);
|
||||||
|
|
|
@ -2,11 +2,15 @@ package com.osmand;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
@ -15,23 +19,22 @@ import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
|
import android.os.Handler;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.osmand.MapTileDownloader.DownloadRequest;
|
||||||
|
import com.osmand.MapTileDownloader.IMapDownloaderCallback;
|
||||||
|
import com.osmand.map.ITileSource;
|
||||||
import com.osmand.osm.MapUtils;
|
import com.osmand.osm.MapUtils;
|
||||||
|
|
||||||
public class OsmandMapTileView extends View {
|
public class OsmandMapTileView extends View implements IMapDownloaderCallback {
|
||||||
|
|
||||||
protected final int emptyTileDivisor = 4;
|
protected final int emptyTileDivisor = DefaultLauncherConstants.MAP_divNonLoadedImage;
|
||||||
protected final int maxImgCacheSize = 512;
|
protected final int maxImgCacheSize = 512;
|
||||||
|
|
||||||
|
protected static final Log log = LogFactory.getLog(OsmandMapTileView.class);
|
||||||
/**
|
|
||||||
* tile size of map
|
|
||||||
*/
|
|
||||||
private int tileSize = 256;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* file or directory with tiles
|
* file or directory with tiles
|
||||||
*/
|
*/
|
||||||
|
@ -40,20 +43,22 @@ public class OsmandMapTileView extends View {
|
||||||
/**
|
/**
|
||||||
* zoom level
|
* zoom level
|
||||||
*/
|
*/
|
||||||
private int zoom = 15;
|
private int zoom = DefaultLauncherConstants.MAP_startMapZoom;
|
||||||
|
|
||||||
// degree measurements (-180, 180)
|
private double longitude = DefaultLauncherConstants.MAP_startMapLongitude;
|
||||||
// долгота
|
|
||||||
private double longitude = 27.56;
|
private double latitude = DefaultLauncherConstants.MAP_startMapLatitude;
|
||||||
// широта
|
|
||||||
// degree measurements (90, -90)
|
// name of source map
|
||||||
private double latitude = 53.9;
|
private ITileSource map = DefaultLauncherConstants.MAP_defaultTileSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listeners
|
* listeners
|
||||||
*/
|
*/
|
||||||
private List<IMapLocationListener> listeners = new ArrayList<IMapLocationListener>();
|
private List<IMapLocationListener> listeners = new ArrayList<IMapLocationListener>();
|
||||||
|
|
||||||
|
private MapTileDownloader downloader = MapTileDownloader.getInstance();
|
||||||
|
|
||||||
|
|
||||||
// cached data to draw images
|
// cached data to draw images
|
||||||
private Bitmap[][] images;
|
private Bitmap[][] images;
|
||||||
|
@ -63,10 +68,19 @@ public class OsmandMapTileView extends View {
|
||||||
private int yStartingImage = 0;
|
private int yStartingImage = 0;
|
||||||
|
|
||||||
Map<String, Bitmap> cacheOfImages = new WeakHashMap<String, Bitmap>();
|
Map<String, Bitmap> cacheOfImages = new WeakHashMap<String, Bitmap>();
|
||||||
|
private PointF startDragging = null;
|
||||||
|
|
||||||
Paint paintGrayFill;
|
Paint paintGrayFill;
|
||||||
Paint paintWhiteFill;
|
Paint paintWhiteFill;
|
||||||
Paint paintBlack;
|
Paint paintBlack;
|
||||||
|
final Handler mHandler = new Handler();
|
||||||
|
|
||||||
|
// Create runnable for posting
|
||||||
|
final Runnable invalidateView = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public OsmandMapTileView(Context context, AttributeSet attrs) {
|
public OsmandMapTileView(Context context, AttributeSet attrs) {
|
||||||
|
@ -94,14 +108,18 @@ public class OsmandMapTileView extends View {
|
||||||
|
|
||||||
prepareImage();
|
prepareImage();
|
||||||
setClickable(true);
|
setClickable(true);
|
||||||
|
downloader.setDownloaderCallback(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private PointF startDragging = null;
|
public int getTileSize() {
|
||||||
|
return map == null ? 256 : map.getTileSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void dragTo(PointF p){
|
public void dragTo(PointF p){
|
||||||
double dx = (startDragging.x - (double)p.x)/tileSize;
|
double dx = (startDragging.x - (double)p.x)/getTileSize();
|
||||||
double dy = (startDragging.y - (double)p.y)/tileSize;
|
double dy = (startDragging.y - (double)p.y)/getTileSize();
|
||||||
this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy);
|
this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy);
|
||||||
this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx);
|
this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx);
|
||||||
prepareImage();
|
prepareImage();
|
||||||
|
@ -138,7 +156,7 @@ public class OsmandMapTileView extends View {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawEmptyTile(Canvas cvs, int x, int y){
|
protected void drawEmptyTile(Canvas cvs, int x, int y){
|
||||||
int tileDiv = tileSize / emptyTileDivisor;
|
int tileDiv = getTileSize() / emptyTileDivisor;
|
||||||
for (int k1 = 0; k1 < emptyTileDivisor; k1++) {
|
for (int k1 = 0; k1 < emptyTileDivisor; k1++) {
|
||||||
|
|
||||||
for (int k2 = 0; k2 < emptyTileDivisor; k2++) {
|
for (int k2 = 0; k2 < emptyTileDivisor; k2++) {
|
||||||
|
@ -160,21 +178,41 @@ public class OsmandMapTileView extends View {
|
||||||
for (int i = 0; i < images.length; i++) {
|
for (int i = 0; i < images.length; i++) {
|
||||||
for (int j = 0; j < images[i].length; j++) {
|
for (int j = 0; j < images[i].length; j++) {
|
||||||
if (images[i][j] == null) {
|
if (images[i][j] == null) {
|
||||||
drawEmptyTile(canvas, i*tileSize+xStartingImage, j * tileSize + yStartingImage);
|
drawEmptyTile(canvas, i*getTileSize()+xStartingImage, j * getTileSize() + yStartingImage);
|
||||||
} else {
|
} else {
|
||||||
canvas.drawBitmap(images[i][j], i * tileSize + xStartingImage, j * tileSize + yStartingImage, null);
|
canvas.drawBitmap(images[i][j], i * getTileSize() + xStartingImage, j * getTileSize() + yStartingImage, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canvas.drawCircle(getWidth()/2, getHeight()/2, 3, paintBlack);
|
canvas.drawCircle(getWidth()/2, getHeight()/2, 3, paintBlack);
|
||||||
canvas.drawCircle(getWidth()/2, getHeight()/2, 6, paintBlack);
|
canvas.drawCircle(getWidth()/2, getHeight()/2, 6, paintBlack);
|
||||||
|
if (DefaultLauncherConstants.showGPSCoordinates) {
|
||||||
|
canvas.drawText(MessageFormat.format("Lat : {0}, lon : {1}, zoom : {2}", latitude, longitude, zoom), 0, 15, paintBlack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Bitmap getImageFor(int x, int y) {
|
|
||||||
String file = "/" + zoom + "/" + (x) + "/" + y + ".png";
|
|
||||||
if (!cacheOfImages.containsKey(file) && fileWithTiles != null) {
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
|
prepareImage();
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getFileForImage (int x, int y, int zoom, String ext){
|
||||||
|
return map.getName() +"/"+zoom+"/"+(x) +"/"+y+ext+".tile";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getImageFor(int x, int y, int zoom, boolean loadIfNeeded) {
|
||||||
|
if (map == null || fileWithTiles == null || !fileWithTiles.canRead()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String file = getFileForImage(x, y, zoom, map.getTileFormat());
|
||||||
|
if (cacheOfImages.get(file) == null) {
|
||||||
File en = new File(fileWithTiles, file);
|
File en = new File(fileWithTiles, file);
|
||||||
if (cacheOfImages.size() > maxImgCacheSize) {
|
if (cacheOfImages.size() > maxImgCacheSize) {
|
||||||
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
|
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
|
||||||
|
@ -184,39 +222,62 @@ public class OsmandMapTileView extends View {
|
||||||
}
|
}
|
||||||
System.gc();
|
System.gc();
|
||||||
}
|
}
|
||||||
if (en.exists() && en.canRead()) {
|
if (!downloader.isFileCurrentlyDownloaded(en)) {
|
||||||
|
if (en.exists()) {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
cacheOfImages.put(file, BitmapFactory.decodeFile(en.getAbsolutePath()));
|
cacheOfImages.put(file, BitmapFactory.decodeFile(en.getAbsolutePath()));
|
||||||
} else {
|
if (log.isDebugEnabled()) {
|
||||||
cacheOfImages.put(file, null);
|
log.debug("Loaded file : " + file + " " + -(time - System.currentTimeMillis()) + " ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(loadIfNeeded && cacheOfImages.get(file) == null){
|
||||||
|
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
||||||
|
if (urlToLoad != null) {
|
||||||
|
downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cacheOfImages.get(file);
|
return cacheOfImages.get(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
public void tileDownloaded(String dowloadedUrl, DownloadRequest request) {
|
||||||
prepareImage();
|
int tileSize = getTileSize();
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
double xTileLeft = getXTile() - getWidth() / (2d * tileSize);
|
||||||
|
double yTileUp = getYTile() - getHeight() / (2d * tileSize);
|
||||||
|
int i = request.xTile - (int)xTileLeft;
|
||||||
|
int j = request.yTile - (int)yTileUp;
|
||||||
|
if(request.zoom == this.zoom &&
|
||||||
|
(i >= 0 && i < images.length) && (j >= 0 && j < images[i].length)) {
|
||||||
|
images[i][j] = getImageFor(request.xTile, request.yTile, zoom, false);
|
||||||
|
mHandler.post(invalidateView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO async loading images (show busy cursor while it is loaded)
|
|
||||||
public void prepareImage(){
|
public void prepareImage(){
|
||||||
double xTileLeft = getXTile() - getWidth() / (2d * tileSize);
|
prepareImage(DefaultLauncherConstants.loadMissingImages);
|
||||||
double xTileRight = getXTile() + getWidth() / (2d * tileSize);
|
}
|
||||||
double yTileUp = getYTile() - getHeight() / (2d * tileSize);
|
|
||||||
double yTileDown = getYTile() + getHeight() / (2d * tileSize);
|
|
||||||
|
|
||||||
xStartingImage = -(int) ((xTileLeft - Math.floor(xTileLeft)) * tileSize);
|
public void prepareImage(boolean loadNecessaryImages) {
|
||||||
yStartingImage = -(int) ((yTileUp - Math.floor(yTileUp)) * tileSize);
|
if (loadNecessaryImages) {
|
||||||
|
downloader.refuseAllPreviousRequests();
|
||||||
|
}
|
||||||
|
double xTileLeft = getXTile() - getWidth() / (2d * getTileSize());
|
||||||
|
double xTileRight = getXTile() + getWidth() / (2d * getTileSize());
|
||||||
|
double yTileUp = getYTile() - getHeight() / (2d * getTileSize());
|
||||||
|
double yTileDown = getYTile() + getHeight() / (2d * getTileSize());
|
||||||
|
|
||||||
|
xStartingImage = -(int) ((xTileLeft - Math.floor(xTileLeft)) * getTileSize());
|
||||||
|
yStartingImage = -(int) ((yTileUp - Math.floor(yTileUp)) * getTileSize());
|
||||||
|
|
||||||
int tileXCount = ((int) xTileRight - (int) xTileLeft + 1);
|
int tileXCount = ((int) xTileRight - (int) xTileLeft + 1);
|
||||||
int tileYCount = ((int) yTileDown - (int) yTileUp + 1);
|
int tileYCount = ((int) yTileDown - (int) yTileUp + 1);
|
||||||
images = new Bitmap[tileXCount][tileYCount];
|
images = new Bitmap[tileXCount][tileYCount];
|
||||||
for (int i = 0; i < images.length; i++) {
|
for (int i = 0; i < images.length; i++) {
|
||||||
for (int j = 0; j < images[i].length; j++) {
|
for (int j = 0; j < images[i].length; j++) {
|
||||||
images[i][j] = getImageFor((int) xTileLeft + i, (int) yTileUp + j);
|
images[i][j] = getImageFor((int) xTileLeft + i, (int) yTileUp + j, zoom, loadNecessaryImages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
|
@ -225,14 +286,31 @@ public class OsmandMapTileView extends View {
|
||||||
|
|
||||||
|
|
||||||
public void setZoom(int zoom){
|
public void setZoom(int zoom){
|
||||||
|
if (map == null || (map.getMaximumZoomSupported() >= zoom && map.getMinimumZoomSupported() <= zoom)) {
|
||||||
this.zoom = zoom;
|
this.zoom = zoom;
|
||||||
prepareImage();
|
prepareImage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public File getFileWithTiles() {
|
public File getFileWithTiles() {
|
||||||
return fileWithTiles;
|
return fileWithTiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ITileSource getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(ITileSource map) {
|
||||||
|
this.map = map;
|
||||||
|
if(map.getMaximumZoomSupported() < this.zoom){
|
||||||
|
zoom = map.getMaximumZoomSupported();
|
||||||
|
}
|
||||||
|
if(map.getMinimumZoomSupported() > this.zoom){
|
||||||
|
zoom = map.getMinimumZoomSupported();
|
||||||
|
}
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
|
||||||
public void setFileWithTiles(File fileWithTiles) {
|
public void setFileWithTiles(File fileWithTiles) {
|
||||||
this.fileWithTiles = fileWithTiles;
|
this.fileWithTiles = fileWithTiles;
|
||||||
prepareImage();
|
prepareImage();
|
||||||
|
@ -257,9 +335,6 @@ public class OsmandMapTileView extends View {
|
||||||
return zoom;
|
return zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTileSize() {
|
|
||||||
return tileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addMapLocationListener(IMapLocationListener l){
|
public void addMapLocationListener(IMapLocationListener l){
|
||||||
|
|
Loading…
Reference in a new issue