reintroduce amenity layer (with layer framework for map)
fixing bugs for map introduce Resource Manager & proper indexing poi trying to fix OutOfMemoryException git-svn-id: https://osmand.googlecode.com/svn/trunk@35 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
parent
15bcbac26a
commit
bbd56254ae
19 changed files with 939 additions and 669 deletions
|
@ -47,6 +47,7 @@ import org.apache.tools.bzip2.CBZip2InputStream;
|
||||||
import org.apache.tools.bzip2.CBZip2OutputStream;
|
import org.apache.tools.bzip2.CBZip2OutputStream;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import com.osmand.data.Amenity;
|
||||||
import com.osmand.data.City;
|
import com.osmand.data.City;
|
||||||
import com.osmand.data.DataTileManager;
|
import com.osmand.data.DataTileManager;
|
||||||
import com.osmand.data.Region;
|
import com.osmand.data.Region;
|
||||||
|
@ -132,7 +133,7 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
// preloaded data
|
// preloaded data
|
||||||
final List<Node> places = new ArrayList<Node>();
|
final List<Node> places = new ArrayList<Node>();
|
||||||
final List<Entity> buildings = new ArrayList<Entity>();
|
final List<Entity> buildings = new ArrayList<Entity>();
|
||||||
final List<Node> amenities = new ArrayList<Node>();
|
final List<Amenity> amenities = new ArrayList<Amenity>();
|
||||||
// highways count
|
// highways count
|
||||||
final List<Way> mapWays = new ArrayList<Way>();
|
final List<Way> mapWays = new ArrayList<Way>();
|
||||||
|
|
||||||
|
@ -150,20 +151,8 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptNodeToLoad(Node n) {
|
public boolean acceptNodeToLoad(Node n) {
|
||||||
if (n.getTag(OSMTagKey.AMENITY) != null) {
|
if(Amenity.isAmenity(n)){
|
||||||
amenities.add(n);
|
amenities.add(new Amenity(n));
|
||||||
} else if (n.getTag(OSMTagKey.SHOP) != null) {
|
|
||||||
// TODO temp solution
|
|
||||||
n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.SHOP.getValue());
|
|
||||||
amenities.add(n);
|
|
||||||
} else if (n.getTag(OSMTagKey.LEISURE) != null) {
|
|
||||||
// TODO temp solution
|
|
||||||
n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.LEISURE.getValue());
|
|
||||||
amenities.add(n);
|
|
||||||
} else if (n.getTag(OSMTagKey.TOURISM) != null) {
|
|
||||||
// TODO temp solution
|
|
||||||
n.putTag(OSMTagKey.AMENITY.getValue(), OSMTagKey.TOURISM.getValue());
|
|
||||||
amenities.add(n);
|
|
||||||
}
|
}
|
||||||
if (n.getTag(OSMTagKey.PLACE) != null) {
|
if (n.getTag(OSMTagKey.PLACE) != null) {
|
||||||
places.add(n);
|
places.add(n);
|
||||||
|
@ -228,9 +217,9 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTileManager<LatLon> amenitiesManager = new DataTileManager<LatLon>();
|
DataTileManager<LatLon> amenitiesManager = new DataTileManager<LatLon>();
|
||||||
for(Node node : amenities){
|
for(Amenity a: amenities){
|
||||||
country.registerAmenity(node);
|
country.registerAmenity(a);
|
||||||
amenitiesManager.registerObject(node.getLatitude(), node.getLongitude(), node.getLatLon());
|
amenitiesManager.registerObject(a.getNode().getLatitude(), a.getNode().getLongitude(), a.getNode().getLatLon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,7 +238,9 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
runUI(country);
|
runUI(country);
|
||||||
List<Long> interestedObjects = new ArrayList<Long>();
|
List<Long> interestedObjects = new ArrayList<Long>();
|
||||||
// MapUtils.addIdsToList(places, interestedObjects);
|
// MapUtils.addIdsToList(places, interestedObjects);
|
||||||
MapUtils.addIdsToList(amenities, interestedObjects);
|
for(Amenity a : amenities){
|
||||||
|
interestedObjects.add(a.getNode().getId());
|
||||||
|
}
|
||||||
// MapUtils.addIdsToList(mapWays, interestedObjects);
|
// MapUtils.addIdsToList(mapWays, interestedObjects);
|
||||||
// MapUtils.addIdsToList(buildings, interestedObjects);
|
// MapUtils.addIdsToList(buildings, interestedObjects);
|
||||||
if (DefaultLauncherConstants.writeTestOsmFile != null) {
|
if (DefaultLauncherConstants.writeTestOsmFile != null) {
|
||||||
|
@ -440,21 +431,21 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
@Override
|
@Override
|
||||||
public void locationChanged(final double newLatitude, final double newLongitude, Object source){
|
public void locationChanged(final double newLatitude, final double newLongitude, Object source){
|
||||||
Region reg = (Region) amenitiesTree.getUserObject();
|
Region reg = (Region) amenitiesTree.getUserObject();
|
||||||
List<Node> closestAmenities = reg.getClosestAmenities(newLatitude, newLongitude);
|
List<Amenity> closestAmenities = reg.getClosestAmenities(newLatitude, newLongitude);
|
||||||
Collections.sort(closestAmenities, new Comparator<Node>(){
|
Collections.sort(closestAmenities, new Comparator<Amenity>(){
|
||||||
@Override
|
@Override
|
||||||
public int compare(Node o1, Node o2) {
|
public int compare(Amenity o1, Amenity o2) {
|
||||||
return Double.compare(MapUtils.getDistance(o1, newLatitude, newLongitude),
|
return Double.compare(MapUtils.getDistance(o1.getNode(), newLatitude, newLongitude),
|
||||||
MapUtils.getDistance(o2, newLatitude, newLongitude));
|
MapUtils.getDistance(o2.getNode(), newLatitude, newLongitude));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, List<Node>> filter = new TreeMap<String, List<Node>>();
|
Map<String, List<Amenity>> filter = new TreeMap<String, List<Amenity>>();
|
||||||
for(Node n : closestAmenities){
|
for(Amenity n : closestAmenities){
|
||||||
String type = n.getTag(OSMTagKey.AMENITY);
|
String type = n.getType().toString();
|
||||||
if(!filter.containsKey(type)){
|
if(!filter.containsKey(type)){
|
||||||
filter.put(type, new ArrayList<Node>());
|
filter.put(type, new ArrayList<Amenity>());
|
||||||
}
|
}
|
||||||
filter.get(type).add(n);
|
filter.get(type).add(n);
|
||||||
}
|
}
|
||||||
|
@ -470,11 +461,9 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
|
|
||||||
|
|
||||||
for(int i=0; i<15 && i < closestAmenities.size(); i++){
|
for(int i=0; i<15 && i < closestAmenities.size(); i++){
|
||||||
Node n = closestAmenities.get(i);
|
Amenity n = closestAmenities.get(i);
|
||||||
String type = n.getTag(OSMTagKey.AMENITY);
|
int dist = (int) (MapUtils.getDistance(n.getNode(), newLatitude, newLongitude));
|
||||||
String name = n.getTag(OSMTagKey.NAME);
|
String str = n.getSimpleFormat() + " [" +dist+" m ]";
|
||||||
int dist = (int) (MapUtils.getDistance(n, newLatitude, newLongitude));
|
|
||||||
String str = type +" "+(name == null ? n.getId() : name) +" [" +dist+" m ]";
|
|
||||||
((DefaultMutableTreeNode)amenitiesTree.getChildAt(0)).add(
|
((DefaultMutableTreeNode)amenitiesTree.getChildAt(0)).add(
|
||||||
new DataExtractionTreeNode(str, n));
|
new DataExtractionTreeNode(str, n));
|
||||||
}
|
}
|
||||||
|
@ -492,10 +481,9 @@ public class DataExtraction implements IMapLocationListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.removeAllChildren();
|
p.removeAllChildren();
|
||||||
for (Node n : filter.get(s)) {
|
for (Amenity n : filter.get(s)) {
|
||||||
String name = n.getTag(OSMTagKey.NAME);
|
int dist = (int) (MapUtils.getDistance(n.getNode(), newLatitude, newLongitude));
|
||||||
int dist = (int) (MapUtils.getDistance(n, newLatitude, newLongitude));
|
String str = n.getSimpleFormat() + " [" + dist + " m ]";
|
||||||
String str = (name == null ? n.getId() : name) + " [" + dist + " m ]";
|
|
||||||
DataExtractionTreeNode node = new DataExtractionTreeNode(str, n);
|
DataExtractionTreeNode node = new DataExtractionTreeNode(str, n);
|
||||||
p.add(node);
|
p.add(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
if(loadIfNeeded && cache.get(file) == null){
|
if(loadIfNeeded && cache.get(file) == null){
|
||||||
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
||||||
if (urlToLoad != null) {
|
if (urlToLoad != null) {
|
||||||
downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom));
|
downloader.requestToDownload(new DownloadRequest(urlToLoad, en, x, y, zoom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tileDownloaded(String dowloadedUrl, DownloadRequest request) {
|
public void tileDownloaded(DownloadRequest request) {
|
||||||
int tileSize = getTileSize();
|
int tileSize = getTileSize();
|
||||||
double xTileLeft = getXTile() - getSize().width / (2d * tileSize);
|
double xTileLeft = getXTile() - getSize().width / (2d * tileSize);
|
||||||
double yTileUp = getYTile() - getSize().height / (2d * tileSize);
|
double yTileUp = getYTile() - getSize().height / (2d * tileSize);
|
||||||
|
|
|
@ -44,7 +44,14 @@ public class MapTileDownloader {
|
||||||
*/
|
*/
|
||||||
public interface IMapDownloaderCallback {
|
public interface IMapDownloaderCallback {
|
||||||
|
|
||||||
public void tileDownloaded(String dowloadedUrl, DownloadRequest fileSaved);
|
/**
|
||||||
|
* Sometimes null cold be passed as request
|
||||||
|
* That means that there were a lot of requests but
|
||||||
|
* once method is called
|
||||||
|
* (in order to not create a collection of request & reduce calling times)
|
||||||
|
* @param fileSaved
|
||||||
|
*/
|
||||||
|
public void tileDownloaded(DownloadRequest request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,15 +62,18 @@ public class MapTileDownloader {
|
||||||
public final int zoom;
|
public final int zoom;
|
||||||
public final int xTile;
|
public final int xTile;
|
||||||
public final int yTile;
|
public final int yTile;
|
||||||
|
public final String url;
|
||||||
|
|
||||||
public DownloadRequest(File fileToSave, int xTile, int yTile, int zoom) {
|
public DownloadRequest(String url, File fileToSave, int xTile, int yTile, int zoom) {
|
||||||
|
this.url = url;
|
||||||
this.fileToSave = fileToSave;
|
this.fileToSave = fileToSave;
|
||||||
this.xTile = xTile;
|
this.xTile = xTile;
|
||||||
this.yTile = yTile;
|
this.yTile = yTile;
|
||||||
this.zoom = zoom;
|
this.zoom = zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadRequest(File fileToSave) {
|
public DownloadRequest(String url, File fileToSave) {
|
||||||
|
this.url = url;
|
||||||
this.fileToSave = fileToSave;
|
this.fileToSave = fileToSave;
|
||||||
xTile = -1;
|
xTile = -1;
|
||||||
yTile = -1;
|
yTile = -1;
|
||||||
|
@ -100,68 +110,69 @@ public class MapTileDownloader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestToDownload(String url, DownloadRequest request){
|
public void requestToDownload(DownloadRequest request){
|
||||||
if(DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS > 0 &&
|
if(DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS > 0 &&
|
||||||
currentErrors > DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS){
|
currentErrors > DefaultLauncherConstants.TILE_DOWNLOAD_MAX_ERRORS){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(request.url == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFileCurrentlyDownloaded(request.fileToSave)) {
|
if (!isFileCurrentlyDownloaded(request.fileToSave)) {
|
||||||
threadPoolExecutor.execute(new DownloadMapWorker(url, request));
|
threadPoolExecutor.execute(new DownloadMapWorker(request));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class DownloadMapWorker implements Runnable, Comparable<DownloadMapWorker> {
|
private class DownloadMapWorker implements Runnable, Comparable<DownloadMapWorker> {
|
||||||
private long time = System.currentTimeMillis();
|
private long time = System.currentTimeMillis();
|
||||||
private final String downloadUrl;
|
|
||||||
private DownloadRequest request;
|
private DownloadRequest request;
|
||||||
|
|
||||||
private DownloadMapWorker(String downloadUrl, DownloadRequest request){
|
private DownloadMapWorker(DownloadRequest request){
|
||||||
this.downloadUrl = downloadUrl;
|
|
||||||
this.request = request;
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
|
||||||
if(log.isDebugEnabled()){
|
if(log.isDebugEnabled()){
|
||||||
log.debug("Start downloading tile : " + downloadUrl);
|
log.debug("Start downloading tile : " + request.url);
|
||||||
}
|
}
|
||||||
URL url = new URL(downloadUrl);
|
if (request != null && request.fileToSave != null && request.url != null) {
|
||||||
URLConnection connection = url.openConnection();
|
|
||||||
connection.setRequestProperty("User-Agent", DefaultLauncherConstants.APP_NAME+"/"+DefaultLauncherConstants.APP_VERSION);
|
|
||||||
BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
|
||||||
try {
|
|
||||||
if (request != null && request.fileToSave != null) {
|
|
||||||
request.fileToSave.getParentFile().mkdirs();
|
|
||||||
|
|
||||||
FileOutputStream stream = new FileOutputStream(request.fileToSave);
|
|
||||||
currentlyDownloaded.add(request.fileToSave);
|
currentlyDownloaded.add(request.fileToSave);
|
||||||
try {
|
try {
|
||||||
|
request.fileToSave.getParentFile().mkdirs();
|
||||||
|
URL url = new URL(request.url);
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
connection.setRequestProperty("User-Agent", DefaultLauncherConstants.APP_NAME + "/"
|
||||||
|
+ DefaultLauncherConstants.APP_VERSION);
|
||||||
|
BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||||
|
FileOutputStream stream = null;
|
||||||
|
try {
|
||||||
|
stream = new FileOutputStream(request.fileToSave);
|
||||||
Algoritms.streamCopy(inputStream, stream);
|
Algoritms.streamCopy(inputStream, stream);
|
||||||
stream.flush();
|
stream.flush();
|
||||||
} finally {
|
} finally {
|
||||||
currentlyDownloaded.remove(request.fileToSave);
|
Algoritms.closeStream(inputStream);
|
||||||
Algoritms.closeStream(stream);
|
Algoritms.closeStream(stream);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
Algoritms.closeStream(inputStream);
|
|
||||||
}
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Downloading tile : " + downloadUrl + " successfull " + (System.currentTimeMillis() - time) + " ms");
|
log.debug("Downloading tile : " + request.url + " successfull " + (System.currentTimeMillis() - time) + " ms");
|
||||||
}
|
|
||||||
if(callback != null){
|
|
||||||
callback.tileDownloaded(downloadUrl, request);
|
|
||||||
}
|
}
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
currentErrors++;
|
currentErrors++;
|
||||||
log.error("UnknownHostException, cannot download tile " + downloadUrl, e);
|
log.error("UnknownHostException, cannot download tile " + request.url, e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
currentErrors++;
|
currentErrors++;
|
||||||
log.warn("Cannot download tile : " + downloadUrl, e);
|
log.warn("Cannot download tile : " + request.url, e);
|
||||||
|
} finally {
|
||||||
|
currentlyDownloaded.remove(request.fileToSave);
|
||||||
}
|
}
|
||||||
|
if (callback != null) {
|
||||||
|
callback.tileDownloaded(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,8 +6,6 @@ public class OsmandSettings {
|
||||||
|
|
||||||
public static boolean useInternetToDownloadTiles = DefaultLauncherConstants.loadMissingImages;
|
public static boolean useInternetToDownloadTiles = DefaultLauncherConstants.loadMissingImages;
|
||||||
|
|
||||||
public static boolean showGPSLocationOnMap = DefaultLauncherConstants.showGPSCoordinates;
|
|
||||||
|
|
||||||
public static ITileSource tileSource = DefaultLauncherConstants.MAP_defaultTileSource;
|
public static ITileSource tileSource = DefaultLauncherConstants.MAP_defaultTileSource;
|
||||||
|
|
||||||
public static boolean showPoiOverMap = true;
|
public static boolean showPoiOverMap = true;
|
||||||
|
|
|
@ -9,18 +9,13 @@ package com.osmand;
|
||||||
*/
|
*/
|
||||||
public class ToDoConstants {
|
public class ToDoConstants {
|
||||||
|
|
||||||
|
|
||||||
// use unknown implementation (not written)? How to see debug msgs?
|
|
||||||
// Explanation of how it works
|
|
||||||
// The task
|
|
||||||
public int CONFIG_COMMONS_LOGGING_IN_ANDROID = 1;
|
|
||||||
|
|
||||||
public int SAVE_SETTINGS_IN_ANDROID_BETWEEN_SESSION = 2;
|
public int SAVE_SETTINGS_IN_ANDROID_BETWEEN_SESSION = 2;
|
||||||
|
|
||||||
|
// First of all switch off gps listener should be implemented
|
||||||
public int IMPLEMENT_ON_STOP_RESUME_ACTIVITY = 3;
|
public int IMPLEMENT_ON_STOP_RESUME_ACTIVITY = 3;
|
||||||
|
|
||||||
// OsmandMapTileView.java have problem with class loading (LogFactory, MapTileDownloader) -
|
// OsmandMapTileView.java have problem with class loading (LogFactory, MapTileDownloader) -
|
||||||
// it is not editable in editor
|
// it is not editable in editor ?
|
||||||
public int MAKE_MAP_PANEL_EDITABLE_IN_EDITOR = 4;
|
public int MAKE_MAP_PANEL_EDITABLE_IN_EDITOR = 4;
|
||||||
|
|
||||||
// common parts : work with cache on file system & in memory
|
// common parts : work with cache on file system & in memory
|
||||||
|
@ -29,12 +24,11 @@ public class ToDoConstants {
|
||||||
|
|
||||||
public int REVISE_MAP_ACTIVITY_HOLD_ALL_ZOOM_LATLON_IN_ONEPLACE = 6;
|
public int REVISE_MAP_ACTIVITY_HOLD_ALL_ZOOM_LATLON_IN_ONEPLACE = 6;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource should cache all resources & free them
|
* Write activity to show something about authors / donation ....
|
||||||
* if there is no enough memory @see tile cache in tile view
|
|
||||||
* @see poi index in map activity
|
|
||||||
*/
|
*/
|
||||||
public int INTRODUCE_RESOURCE_MANAGER = 7;
|
public int DESCRIBE_ABOUT_AUTHORS = 8;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
140
DataExtractionOSM/src/com/osmand/data/Amenity.java
Normal file
140
DataExtractionOSM/src/com/osmand/data/Amenity.java
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
package com.osmand.data;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.osmand.osm.Node;
|
||||||
|
import com.osmand.osm.OSMSettings.OSMTagKey;
|
||||||
|
|
||||||
|
public class Amenity {
|
||||||
|
// http://wiki.openstreetmap.org/wiki/Amenity
|
||||||
|
public enum AmenityType {
|
||||||
|
SUSTENANCE, // restaurant, cafe ...
|
||||||
|
EDUCATION, // school, ...
|
||||||
|
TRANSPORTATION, // car_wash, parking, ...
|
||||||
|
FINANCE, // bank, atm, ...
|
||||||
|
HEALTHCARE, // hospital ...
|
||||||
|
ENTERTAINMENT, // cinema, ... (+! sauna, brothel)
|
||||||
|
TOURISM, // hotel, sights, museum ..
|
||||||
|
SHOP, // convenience (product), clothes...
|
||||||
|
LEISURE, // sport
|
||||||
|
OTHER, // grave-yard, police, post-office
|
||||||
|
}
|
||||||
|
private static Map<String, AmenityType> prebuiltMap = new LinkedHashMap<String, AmenityType>();
|
||||||
|
static {
|
||||||
|
prebuiltMap.put("restaurant", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("food_court", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("fast_food", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("drinking_water", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("bbq", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("pub", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("bar", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("cafe", AmenityType.SUSTENANCE);
|
||||||
|
prebuiltMap.put("biergarten", AmenityType.SUSTENANCE);
|
||||||
|
|
||||||
|
prebuiltMap.put("kindergarten", AmenityType.EDUCATION);
|
||||||
|
prebuiltMap.put("school", AmenityType.EDUCATION);
|
||||||
|
prebuiltMap.put("college", AmenityType.EDUCATION);
|
||||||
|
prebuiltMap.put("library", AmenityType.EDUCATION);
|
||||||
|
prebuiltMap.put("university", AmenityType.EDUCATION);
|
||||||
|
|
||||||
|
prebuiltMap.put("ferry_terminal", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("bicycle_parking", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("bicycle_rental", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("bus_station", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("car_rental", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("car_sharing", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("car_wash", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("grit_bin", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("parking", AmenityType.TRANSPORTATION);
|
||||||
|
prebuiltMap.put("taxi", AmenityType.TRANSPORTATION);
|
||||||
|
|
||||||
|
prebuiltMap.put("atm", AmenityType.FINANCE);
|
||||||
|
prebuiltMap.put("bank", AmenityType.FINANCE);
|
||||||
|
prebuiltMap.put("bureau_de_change", AmenityType.FINANCE);
|
||||||
|
|
||||||
|
prebuiltMap.put("pharmacy", AmenityType.HEALTHCARE);
|
||||||
|
prebuiltMap.put("hospital", AmenityType.HEALTHCARE);
|
||||||
|
prebuiltMap.put("baby_hatch", AmenityType.HEALTHCARE);
|
||||||
|
prebuiltMap.put("dentist", AmenityType.HEALTHCARE);
|
||||||
|
prebuiltMap.put("doctors", AmenityType.HEALTHCARE);
|
||||||
|
prebuiltMap.put("veterinary", AmenityType.HEALTHCARE);
|
||||||
|
|
||||||
|
prebuiltMap.put("architect_office", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("arts_centre", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("cinema", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("community_centre", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("fountain", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("nightclub", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("stripclub", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("studio", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("theatre", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("sauna", AmenityType.ENTERTAINMENT);
|
||||||
|
prebuiltMap.put("brothel", AmenityType.ENTERTAINMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final Node node;
|
||||||
|
|
||||||
|
public Amenity(Node node){
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubType(){
|
||||||
|
if(node.getTag(OSMTagKey.AMENITY) != null){
|
||||||
|
return node.getTag(OSMTagKey.AMENITY);
|
||||||
|
} else if(node.getTag(OSMTagKey.SHOP) != null){
|
||||||
|
return node.getTag(OSMTagKey.SHOP);
|
||||||
|
} else if(node.getTag(OSMTagKey.TOURISM) != null){
|
||||||
|
return node.getTag(OSMTagKey.TOURISM);
|
||||||
|
} else if(node.getTag(OSMTagKey.LEISURE) != null){
|
||||||
|
return node.getTag(OSMTagKey.LEISURE);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public AmenityType getType(){
|
||||||
|
if(node.getTag(OSMTagKey.SHOP) != null){
|
||||||
|
return AmenityType.SHOP;
|
||||||
|
} else if(node.getTag(OSMTagKey.TOURISM) != null){
|
||||||
|
return AmenityType.TOURISM;
|
||||||
|
} else if(node.getTag(OSMTagKey.LEISURE) != null){
|
||||||
|
return AmenityType.LEISURE;
|
||||||
|
} else if(prebuiltMap.containsKey(node.getTag(OSMTagKey.AMENITY))){
|
||||||
|
return prebuiltMap.get(node.getTag(OSMTagKey.AMENITY));
|
||||||
|
}
|
||||||
|
return AmenityType.OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAmenity(Node n){
|
||||||
|
if(n.getTag(OSMTagKey.AMENITY) != null){
|
||||||
|
return true;
|
||||||
|
} else if(n.getTag(OSMTagKey.SHOP) != null){
|
||||||
|
return true;
|
||||||
|
} else if(n.getTag(OSMTagKey.LEISURE) != null){
|
||||||
|
return true;
|
||||||
|
} else if(n.getTag(OSMTagKey.TOURISM) != null){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSimpleFormat(){
|
||||||
|
String name = node.getTag(OSMTagKey.NAME);
|
||||||
|
return getType().toString() +" : " + getSubType() + " " +(name == null ? node.getId() : name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getSimpleFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ import com.osmand.osm.OSMSettings.OSMTagKey;
|
||||||
public class Region {
|
public class Region {
|
||||||
private Entity entity;
|
private Entity entity;
|
||||||
|
|
||||||
private DataTileManager<Node> amenities = new DataTileManager<Node>();
|
private DataTileManager<Amenity> amenities = new DataTileManager<Amenity>();
|
||||||
|
|
||||||
private Map<CityType, Collection<City>> cities = new HashMap<CityType, Collection<City>>();
|
private Map<CityType, Collection<City>> cities = new HashMap<CityType, Collection<City>>();
|
||||||
{
|
{
|
||||||
|
@ -87,12 +87,12 @@ public class Region {
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Node> getClosestAmenities(double latitude, double longitude){
|
public List<Amenity> getClosestAmenities(double latitude, double longitude){
|
||||||
return amenities.getClosestObjects(latitude, longitude, 2);
|
return amenities.getClosestObjects(latitude, longitude, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerAmenity(Node n){
|
public void registerAmenity(Amenity a){
|
||||||
amenities.registerObject(n.getLatitude(), n.getLongitude(), n);
|
amenities.registerObject(a.getNode().getLatitude(), a.getNode().getLongitude(), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
android:layout_height="fill_parent">
|
android:layout_height="fill_parent">
|
||||||
<com.osmand.views.OsmandMapTileView android:id="@+id/MapView" android:layout_width="fill_parent" android:layout_height="fill_parent"></com.osmand.views.OsmandMapTileView>
|
<com.osmand.views.OsmandMapTileView android:id="@+id/MapView" android:layout_width="fill_parent" android:layout_height="fill_parent"></com.osmand.views.OsmandMapTileView>
|
||||||
<com.osmand.views.PointOfView android:id="@+id/PointOfView" android:layout_width="fill_parent" android:layout_height="fill_parent"></com.osmand.views.PointOfView>
|
<com.osmand.views.PointOfView android:id="@+id/PointOfView" android:layout_width="fill_parent" android:layout_height="fill_parent"></com.osmand.views.PointOfView>
|
||||||
<com.osmand.views.POIMapLayer android:id="@+id/PoiMapLayer" android:layout_width="fill_parent" android:layout_height="fill_parent"></com.osmand.views.POIMapLayer>
|
|
||||||
<ZoomControls android:id="@+id/ZoomControls01"
|
<ZoomControls android:id="@+id/ZoomControls01"
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right"></ZoomControls>
|
android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right"></ZoomControls>
|
||||||
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|left" android:id="@+id/BackToMenu" android:background="@drawable/back"></ImageButton>
|
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|left" android:id="@+id/BackToMenu" android:background="@drawable/back"></ImageButton>
|
||||||
|
|
7
OsmAnd/res/menu/map_menu.xml
Normal file
7
OsmAnd/res/menu/map_menu.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<group android:id="@+id/map_context_menu" android:menuCategory="container"><item android:id="@+id/map_show_settings" android:title="@string/settings_Button"></item>
|
||||||
|
<item android:id="@+id/map_show_location" android:title="@string/show_location"></item>
|
||||||
|
</group>
|
||||||
|
</menu>
|
|
@ -2,7 +2,7 @@
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<PreferenceCategory android:title="@string/map_preferences">
|
<PreferenceCategory android:title="@string/map_preferences">
|
||||||
<CheckBoxPreference android:key="show_gps_location_text" android:title="@string/show_location" android:summary="@string/show_gps_coordinates_text"></CheckBoxPreference>
|
|
||||||
<CheckBoxPreference android:key="use_internet_to_download_tiles" android:title="@string/use_internet" android:summary="@string/use_internet_to_download_tile"></CheckBoxPreference>
|
<CheckBoxPreference android:key="use_internet_to_download_tiles" android:title="@string/use_internet" android:summary="@string/use_internet_to_download_tile"></CheckBoxPreference>
|
||||||
<CheckBoxPreference android:key="show_poi_over_map" android:title="@string/show_poi_over_map" android:summary="@string/show_poi_over_map_description"></CheckBoxPreference>
|
<CheckBoxPreference android:key="show_poi_over_map" android:title="@string/show_poi_over_map" android:summary="@string/show_poi_over_map_description"></CheckBoxPreference>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
|
@ -85,7 +85,9 @@ public class LogUtil {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDebugEnabled() {
|
public boolean isDebugEnabled() {
|
||||||
return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
|
// For debur purposes always true
|
||||||
|
// return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
260
OsmAnd/src/com/osmand/ResourceManager.java
Normal file
260
OsmAnd/src/com/osmand/ResourceManager.java
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
package com.osmand;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.tools.bzip2.CBZip2InputStream;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import com.osmand.MapTileDownloader.DownloadRequest;
|
||||||
|
import com.osmand.data.Amenity;
|
||||||
|
import com.osmand.data.DataTileManager;
|
||||||
|
import com.osmand.map.ITileSource;
|
||||||
|
import com.osmand.osm.Entity;
|
||||||
|
import com.osmand.osm.Node;
|
||||||
|
import com.osmand.osm.io.OsmBaseStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource manager is responsible to work with all resources
|
||||||
|
* that could consume memory (especially with file resources).
|
||||||
|
* Such as indexes, tiles.
|
||||||
|
* Also it is responsible to create cache for that resources if they
|
||||||
|
* can't be loaded fully into memory & clear them on request.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceManager {
|
||||||
|
|
||||||
|
private static final String POI_PATH = "osmand/poi/";
|
||||||
|
private static final String TILES_PATH = "osmand/tiles/";
|
||||||
|
|
||||||
|
private static final Log log = LogUtil.getLog(ResourceManager.class);
|
||||||
|
|
||||||
|
protected static ResourceManager manager = null;
|
||||||
|
|
||||||
|
public static ResourceManager getResourceManager(){
|
||||||
|
if(manager == null){
|
||||||
|
manager = new ResourceManager();
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is not good investigated but no more than 64 (satellite images)
|
||||||
|
protected final int maxImgCacheSize = 64;
|
||||||
|
|
||||||
|
private DataTileManager<Amenity> poiIndex = null;
|
||||||
|
|
||||||
|
protected Map<String, Bitmap> cacheOfImages = new LinkedHashMap<String, Bitmap>();
|
||||||
|
|
||||||
|
protected File dirWithTiles ;
|
||||||
|
|
||||||
|
private MapTileDownloader downloader = MapTileDownloader.getInstance();
|
||||||
|
|
||||||
|
public AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public ResourceManager() {
|
||||||
|
// TODO start/stop this thread when needed?
|
||||||
|
asyncLoadingTiles.start();
|
||||||
|
dirWithTiles = new File(Environment.getExternalStorageDirectory(), TILES_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Working with tiles ///
|
||||||
|
public Bitmap getTileImageForMapAsync(ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) {
|
||||||
|
return getTileImageForMap(map, x, y, zoom, loadFromInternetIfNeeded, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getTileImageForMapSync(ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) {
|
||||||
|
return getTileImageForMap(map, x, y, zoom, loadFromInternetIfNeeded, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Bitmap getTileImageForMap(ITileSource map, int x, int y, int zoom,
|
||||||
|
boolean loadFromInternetIfNeeded, boolean sync) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder(40);
|
||||||
|
builder.append(map.getName()).append('/').append(zoom). append('/').append(x).
|
||||||
|
append('/').append(y).append(map.getTileFormat()).append(".tile");
|
||||||
|
String file = builder.toString();
|
||||||
|
if (cacheOfImages.get(file) == null) {
|
||||||
|
String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null;
|
||||||
|
TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, file, url, new File(dirWithTiles, file),
|
||||||
|
x, y, zoom);
|
||||||
|
if(sync){
|
||||||
|
return getRequestedImageTile(req);
|
||||||
|
} else {
|
||||||
|
asyncLoadingTiles.requestToLoadImage(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cacheOfImages.get(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static class TileLoadDownloadRequest extends DownloadRequest {
|
||||||
|
|
||||||
|
public final String fileToLoad;
|
||||||
|
public final File dirWithTiles;
|
||||||
|
|
||||||
|
public TileLoadDownloadRequest(File dirWithTiles,
|
||||||
|
String fileToLoad, String url, File fileToSave, int tileX, int tileY, int zoom) {
|
||||||
|
super(url, fileToSave, tileX, tileY, zoom);
|
||||||
|
this.dirWithTiles = dirWithTiles;
|
||||||
|
this.fileToLoad = fileToLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public class AsyncLoadingThread extends Thread {
|
||||||
|
Stack<TileLoadDownloadRequest> requests = new Stack<TileLoadDownloadRequest>();
|
||||||
|
|
||||||
|
public AsyncLoadingThread(){
|
||||||
|
super("Async loading tiles");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while(true){
|
||||||
|
try {
|
||||||
|
boolean update = false;
|
||||||
|
while(!requests.isEmpty()){
|
||||||
|
TileLoadDownloadRequest r = requests.pop();
|
||||||
|
if(cacheOfImages.get(r.fileToLoad) == null) {
|
||||||
|
update |= getRequestedImageTile(r) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(update){
|
||||||
|
// use downloader callback
|
||||||
|
downloader.getDownloaderCallback().tileDownloaded(null);
|
||||||
|
}
|
||||||
|
sleep(750);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error(e);
|
||||||
|
} catch (RuntimeException e){
|
||||||
|
log.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestToLoadImage(TileLoadDownloadRequest req){
|
||||||
|
requests.push(req);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Bitmap getRequestedImageTile(TileLoadDownloadRequest req){
|
||||||
|
if(req.fileToLoad == null || req.dirWithTiles == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File en = new File(req.dirWithTiles, req.fileToLoad);
|
||||||
|
if (cacheOfImages.size() > maxImgCacheSize) {
|
||||||
|
onLowMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!downloader.isFileCurrentlyDownloaded(en)) {
|
||||||
|
if (en.exists()) {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
cacheOfImages.put(req.fileToLoad, BitmapFactory.decodeFile(en.getAbsolutePath()));
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Loaded file : " + req.fileToLoad + " " + -(time - System.currentTimeMillis()) + " ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cacheOfImages.get(req.fileToLoad) == null && req.url != null){
|
||||||
|
// TODO we could check that network is available (context is required)
|
||||||
|
// ConnectivityManager mgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
// NetworkInfo info = mgr.getActiveNetworkInfo();
|
||||||
|
// if (info != null && info.isConnected()) {
|
||||||
|
// downloader.requestToDownload(req);
|
||||||
|
// }
|
||||||
|
downloader.requestToDownload(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cacheOfImages.get(req.fileToLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// POI INDEX //
|
||||||
|
public void indexingPoi(){
|
||||||
|
if (poiIndex == null) {
|
||||||
|
File file = new File(Environment.getExternalStorageDirectory(), POI_PATH);
|
||||||
|
poiIndex = new DataTileManager<Amenity>();
|
||||||
|
if (file.exists() && file.canRead()) {
|
||||||
|
for (File f : file.listFiles()) {
|
||||||
|
if (f.getName().endsWith(".bz2") || f.getName().endsWith(".osm")) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Starting index POI " + f.getAbsolutePath());
|
||||||
|
}
|
||||||
|
boolean zipped = f.getName().endsWith(".bz2");
|
||||||
|
InputStream stream = null;
|
||||||
|
try {
|
||||||
|
OsmBaseStorage storage = new OsmBaseStorage();
|
||||||
|
stream = new FileInputStream(f);
|
||||||
|
stream = new BufferedInputStream(stream);
|
||||||
|
if (zipped) {
|
||||||
|
if (stream.read() != 'B' || stream.read() != 'Z') {
|
||||||
|
log.error("Can't read poi file " + f.getAbsolutePath()
|
||||||
|
+ "The source stream must start with the characters BZ if it is to be read as a BZip2 stream.");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stream = new CBZip2InputStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage.parseOSM(stream);
|
||||||
|
for (Entity e : storage.getRegisteredEntities().values()) {
|
||||||
|
if (e instanceof Node && Amenity.isAmenity((Node) e)) {
|
||||||
|
poiIndex.registerObject(((Node)e).getLatitude(), ((Node)e).getLongitude(), new Amenity((Node) e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Finishing index POI " + f.getAbsolutePath());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Can't read poi file " + f.getAbsolutePath(), e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
log.error("Can't read poi file " + f.getAbsolutePath(), e);
|
||||||
|
} finally {
|
||||||
|
Algoritms.closeStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTileManager<Amenity> getPoiIndex() {
|
||||||
|
if(poiIndex == null){
|
||||||
|
indexingPoi();
|
||||||
|
}
|
||||||
|
return poiIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// On low memory method ///
|
||||||
|
public void onLowMemory() {
|
||||||
|
log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size());
|
||||||
|
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
|
||||||
|
// remove first images (as we think they are older)
|
||||||
|
for (int i = 0; i < list.size()/2; i ++) {
|
||||||
|
Bitmap bmp = cacheOfImages.remove(list.get(i));
|
||||||
|
if(bmp != null){
|
||||||
|
bmp.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import android.view.View.OnClickListener;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import com.osmand.R;
|
import com.osmand.R;
|
||||||
|
import com.osmand.ResourceManager;
|
||||||
|
|
||||||
public class MainMenuActivity extends Activity {
|
public class MainMenuActivity extends Activity {
|
||||||
|
|
||||||
|
@ -47,5 +48,7 @@ public class MainMenuActivity extends Activity {
|
||||||
MainMenuActivity.this.finish();
|
MainMenuActivity.this.finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ResourceManager.getResourceManager().indexingPoi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
package com.osmand.activities;
|
package com.osmand.activities;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.text.MessageFormat;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.apache.tools.bzip2.CBZip2InputStream;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -15,26 +8,21 @@ import android.location.Location;
|
||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
import android.widget.ZoomControls;
|
import android.widget.ZoomControls;
|
||||||
|
|
||||||
import com.osmand.Algoritms;
|
|
||||||
import com.osmand.IMapLocationListener;
|
import com.osmand.IMapLocationListener;
|
||||||
import com.osmand.LogUtil;
|
|
||||||
import com.osmand.OsmandSettings;
|
import com.osmand.OsmandSettings;
|
||||||
import com.osmand.R;
|
import com.osmand.R;
|
||||||
import com.osmand.data.DataTileManager;
|
import com.osmand.ResourceManager;
|
||||||
import com.osmand.osm.Entity;
|
|
||||||
import com.osmand.osm.LatLon;
|
|
||||||
import com.osmand.osm.MapUtils;
|
import com.osmand.osm.MapUtils;
|
||||||
import com.osmand.osm.Node;
|
|
||||||
import com.osmand.osm.OSMSettings.OSMTagKey;
|
|
||||||
import com.osmand.osm.io.OsmBaseStorage;
|
|
||||||
import com.osmand.views.OsmandMapTileView;
|
import com.osmand.views.OsmandMapTileView;
|
||||||
import com.osmand.views.POIMapLayer;
|
import com.osmand.views.POIMapLayer;
|
||||||
import com.osmand.views.PointOfView;
|
import com.osmand.views.PointOfView;
|
||||||
|
@ -53,12 +41,6 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
|
|
||||||
private PointOfView pointOfView;
|
private PointOfView pointOfView;
|
||||||
|
|
||||||
private static final String TILES_PATH = "osmand/tiles/";
|
|
||||||
private static final String POI_PATH = "osmand/poi/";
|
|
||||||
private static final org.apache.commons.logging.Log log = LogUtil.getLog(MapActivity.class);
|
|
||||||
|
|
||||||
private DataTileManager<Node> indexPOI;
|
|
||||||
|
|
||||||
private POIMapLayer poiMapLayer;
|
private POIMapLayer poiMapLayer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,22 +54,23 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
|
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
mapView = (OsmandMapTileView) findViewById(R.id.MapView);
|
mapView = (OsmandMapTileView) findViewById(R.id.MapView);
|
||||||
mapView.setFileWithTiles(new File(Environment.getExternalStorageDirectory(), TILES_PATH));
|
mapView.setMapLocationListener(this);
|
||||||
mapView.addMapLocationListener(this);
|
poiMapLayer = new POIMapLayer();
|
||||||
|
poiMapLayer.setNodeManager(ResourceManager.getResourceManager().getPoiIndex());
|
||||||
|
mapView.addLayer(poiMapLayer);
|
||||||
|
|
||||||
|
|
||||||
ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls01);
|
ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls01);
|
||||||
zoomControls.setOnZoomInClickListener(new OnClickListener() {
|
zoomControls.setOnZoomInClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
mapView.setZoom(mapView.getZoom() + 1);
|
mapView.setZoom(mapView.getZoom() + 1);
|
||||||
poiMapLayer.setCurrentLocationAndZoom(poiMapLayer.getCurrentLocation(), mapView.getZoom());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
zoomControls.setOnZoomOutClickListener(new OnClickListener() {
|
zoomControls.setOnZoomOutClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
mapView.setZoom(mapView.getZoom() - 1);
|
mapView.setZoom(mapView.getZoom() - 1);
|
||||||
poiMapLayer.setCurrentLocationAndZoom(poiMapLayer.getCurrentLocation(), mapView.getZoom());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -109,6 +92,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
backToMenu = (ImageButton)findViewById(R.id.BackToMenu);
|
backToMenu = (ImageButton)findViewById(R.id.BackToMenu);
|
||||||
backToMenu.setOnClickListener(new OnClickListener(){
|
backToMenu.setOnClickListener(new OnClickListener(){
|
||||||
@Override
|
@Override
|
||||||
|
@ -122,61 +106,9 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
|
|
||||||
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
|
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||||
service.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
|
service.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
|
||||||
indexPOI = indexPOI();
|
|
||||||
|
|
||||||
poiMapLayer = (POIMapLayer)findViewById(R.id.PoiMapLayer);
|
|
||||||
poiMapLayer.setNodeManager(indexPOI);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final boolean indexPOIFlag = false;
|
|
||||||
|
|
||||||
public DataTileManager<Node> indexPOI(){
|
|
||||||
File file = new File(Environment.getExternalStorageDirectory(), POI_PATH);
|
|
||||||
|
|
||||||
DataTileManager<Node> r = new DataTileManager<Node>();
|
|
||||||
if(file.exists() && file.canRead() && indexPOIFlag){
|
|
||||||
for(File f : file.listFiles() ){
|
|
||||||
if(f.getName().endsWith(".bz2") || f.getName().endsWith(".osm") ){
|
|
||||||
if(log.isDebugEnabled()){
|
|
||||||
log.debug("Starting index POI " + f.getAbsolutePath());
|
|
||||||
}
|
|
||||||
boolean zipped = f.getName().endsWith(".bz2");
|
|
||||||
InputStream stream = null;
|
|
||||||
try {
|
|
||||||
OsmBaseStorage storage = new OsmBaseStorage();
|
|
||||||
stream = new FileInputStream(f);
|
|
||||||
stream = new BufferedInputStream(stream);
|
|
||||||
if (zipped) {
|
|
||||||
if (stream.read() != 'B' || stream.read() != 'Z') {
|
|
||||||
log.error("Can't read poi file " + f.getAbsolutePath()
|
|
||||||
+ "The source stream must start with the characters BZ if it is to be read as a BZip2 stream.");
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
stream = new CBZip2InputStream(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
storage.parseOSM(stream);
|
|
||||||
for(Entity e : storage.getRegisteredEntities().values()){
|
|
||||||
if(e instanceof Node && e.getTag(OSMTagKey.AMENITY) != null){
|
|
||||||
Node n = (Node) e;
|
|
||||||
r.registerObject(n.getLatitude(), n.getLongitude(), n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(log.isDebugEnabled()){
|
|
||||||
log.debug("Finishing index POI " + f.getAbsolutePath());
|
|
||||||
}
|
|
||||||
} catch(IOException e){
|
|
||||||
log.error("Can't read poi file " + f.getAbsolutePath(), e);
|
|
||||||
} catch (SAXException e) {
|
|
||||||
log.error("Can't read poi file " + f.getAbsolutePath(), e);
|
|
||||||
} finally {
|
|
||||||
Algoritms.closeStream(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,32 +183,54 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
|
||||||
if(mapView.getMap() != OsmandSettings.tileSource){
|
if(mapView.getMap() != OsmandSettings.tileSource){
|
||||||
mapView.setMap(OsmandSettings.tileSource);
|
mapView.setMap(OsmandSettings.tileSource);
|
||||||
}
|
}
|
||||||
if((poiMapLayer.getVisibility() == View.VISIBLE) != OsmandSettings.showPoiOverMap){
|
if(mapView.getLayers().contains(poiMapLayer) != OsmandSettings.showPoiOverMap){
|
||||||
if(OsmandSettings.showPoiOverMap){
|
if(OsmandSettings.showPoiOverMap){
|
||||||
poiMapLayer.setVisibility(View.VISIBLE);
|
mapView.addLayer(poiMapLayer);
|
||||||
} else {
|
} else {
|
||||||
poiMapLayer.setVisibility(View.INVISIBLE);
|
mapView.removeLayer(poiMapLayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLowMemory() {
|
public void onLowMemory() {
|
||||||
super.onLowMemory();
|
super.onLowMemory();
|
||||||
mapView.onLowMemory();
|
ResourceManager.getResourceManager().onLowMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void locationChanged(double newLatitude, double newLongitude, Object source) {
|
public void locationChanged(double newLatitude, double newLongitude, Object source) {
|
||||||
// when user start dragging
|
// when user start dragging
|
||||||
if(source == mapView && lastKnownLocation != null){
|
if(lastKnownLocation != null){
|
||||||
linkLocationWithMap = false;
|
linkLocationWithMap = false;
|
||||||
backToLocation.setVisibility(View.VISIBLE);
|
backToLocation.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
poiMapLayer.setCurrentLocationAndZoom(new LatLon(newLatitude, newLongitude), mapView.getZoom());
|
|
||||||
|
|
||||||
validatePointOfView();
|
validatePointOfView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.map_menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if(item.getItemId() == R.id.map_show_location){
|
||||||
|
float f= (Runtime.getRuntime().totalMemory())/ 1e6f;
|
||||||
|
String text = MessageFormat.format("Latitude : {0}, longitude : {1}, zoom : {2}, memory : {3}", mapView.getLatitude(),
|
||||||
|
mapView.getLongitude(), mapView.getZoom(), f);
|
||||||
|
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.map_show_settings) {
|
||||||
|
final Intent settings = new Intent(MapActivity.this, SettingsActivity.class);
|
||||||
|
startActivity(settings);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,11 +17,9 @@ import com.osmand.map.TileSourceManager.TileSourceTemplate;
|
||||||
|
|
||||||
public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener {
|
public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener {
|
||||||
private static final String use_internet_to_download_tiles = "use_internet_to_download_tiles";
|
private static final String use_internet_to_download_tiles = "use_internet_to_download_tiles";
|
||||||
private static final String show_gps_location_text = "show_gps_location_text";
|
|
||||||
private static final String map_tile_sources = "map_tile_sources";
|
private static final String map_tile_sources = "map_tile_sources";
|
||||||
private static final String show_poi_over_map = "show_poi_over_map";
|
private static final String show_poi_over_map = "show_poi_over_map";
|
||||||
|
|
||||||
private CheckBoxPreference showGpsLocation;
|
|
||||||
private CheckBoxPreference showPoiOnMap;
|
private CheckBoxPreference showPoiOnMap;
|
||||||
private CheckBoxPreference useInternetToDownloadTiles;
|
private CheckBoxPreference useInternetToDownloadTiles;
|
||||||
private ListPreference tileSourcePreference;
|
private ListPreference tileSourcePreference;
|
||||||
|
@ -31,8 +29,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
addPreferencesFromResource(R.xml.settings_pref);
|
addPreferencesFromResource(R.xml.settings_pref);
|
||||||
PreferenceScreen screen = getPreferenceScreen();
|
PreferenceScreen screen = getPreferenceScreen();
|
||||||
showGpsLocation =(CheckBoxPreference) screen.findPreference(show_gps_location_text);
|
|
||||||
showGpsLocation.setOnPreferenceChangeListener(this);
|
|
||||||
useInternetToDownloadTiles =(CheckBoxPreference) screen.findPreference(use_internet_to_download_tiles);
|
useInternetToDownloadTiles =(CheckBoxPreference) screen.findPreference(use_internet_to_download_tiles);
|
||||||
useInternetToDownloadTiles.setOnPreferenceChangeListener(this);
|
useInternetToDownloadTiles.setOnPreferenceChangeListener(this);
|
||||||
showPoiOnMap =(CheckBoxPreference) screen.findPreference(show_poi_over_map);
|
showPoiOnMap =(CheckBoxPreference) screen.findPreference(show_poi_over_map);
|
||||||
|
@ -48,7 +44,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
useInternetToDownloadTiles.setChecked(OsmandSettings.useInternetToDownloadTiles);
|
useInternetToDownloadTiles.setChecked(OsmandSettings.useInternetToDownloadTiles);
|
||||||
showGpsLocation.setChecked(OsmandSettings.showGPSLocationOnMap);
|
|
||||||
showPoiOnMap.setChecked(OsmandSettings.showPoiOverMap);
|
showPoiOnMap.setChecked(OsmandSettings.showPoiOverMap);
|
||||||
|
|
||||||
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
|
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
|
||||||
|
@ -59,15 +54,14 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
|
||||||
tileSourcePreference.setEntries(entries);
|
tileSourcePreference.setEntries(entries);
|
||||||
tileSourcePreference.setEntryValues(entries);
|
tileSourcePreference.setEntryValues(entries);
|
||||||
tileSourcePreference.setValue(OsmandSettings.tileSource.getName());
|
tileSourcePreference.setValue(OsmandSettings.tileSource.getName());
|
||||||
|
tileSourcePreference.setSummary(tileSourcePreference.getSummary() + "\t\t[" + OsmandSettings.tileSource.getName()+"]");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
if(preference == showGpsLocation){
|
if(preference == showPoiOnMap){
|
||||||
OsmandSettings.showGPSLocationOnMap = (Boolean) newValue;
|
|
||||||
} else if(preference == showPoiOnMap){
|
|
||||||
OsmandSettings.showPoiOverMap = (Boolean) newValue;
|
OsmandSettings.showPoiOverMap = (Boolean) newValue;
|
||||||
} else if(preference == useInternetToDownloadTiles){
|
} else if(preference == useInternetToDownloadTiles){
|
||||||
OsmandSettings.useInternetToDownloadTiles = (Boolean) newValue;
|
OsmandSettings.useInternetToDownloadTiles = (Boolean) newValue;
|
||||||
|
|
92
OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java
Normal file
92
OsmAnd/src/com/osmand/views/AnimateDraggingMapThread.java
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package com.osmand.views;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread for animated dragging.
|
||||||
|
* Defines accelerator to stop dragging screen.
|
||||||
|
*/
|
||||||
|
public class AnimateDraggingMapThread implements Runnable {
|
||||||
|
public interface AnimateDraggingCallback {
|
||||||
|
public void dragTo(float curX, float curY, float newX, float newY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float curX;
|
||||||
|
private float curY;
|
||||||
|
private float vx;
|
||||||
|
private float vy;
|
||||||
|
private float ax;
|
||||||
|
private float ay;
|
||||||
|
private byte dirX;
|
||||||
|
private byte dirY;
|
||||||
|
private long time;
|
||||||
|
private volatile boolean stopped;
|
||||||
|
private final float a = 0.001f;
|
||||||
|
|
||||||
|
private volatile Thread currentThread = null;
|
||||||
|
private AnimateDraggingCallback callback = null;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
currentThread = Thread.currentThread();
|
||||||
|
try {
|
||||||
|
while (!stopped && (vx > 0 || vy > 0)) {
|
||||||
|
Thread.sleep((long) (40d / (Math.max(vx, vy) + 0.45)));
|
||||||
|
long curT = System.currentTimeMillis();
|
||||||
|
int dt = (int) (curT - time);
|
||||||
|
float newX = vx > 0 ? curX + dirX * vx * dt : curX;
|
||||||
|
float newY = vy > 0 ? curY + dirY * vy * dt : curY;
|
||||||
|
if (!stopped && callback != null) {
|
||||||
|
callback.dragTo(curX, curY, newX, newY);
|
||||||
|
}
|
||||||
|
vx -= ax * dt;
|
||||||
|
vy -= ay * dt;
|
||||||
|
time = curT;
|
||||||
|
curX = newX;
|
||||||
|
curY = newY;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
currentThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop dragging async
|
||||||
|
*/
|
||||||
|
public void stopDragging(){
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop dragging sync
|
||||||
|
*/
|
||||||
|
public void stopDraggingSync(){
|
||||||
|
// wait until current thread != null
|
||||||
|
// TODO implement better method for waintg
|
||||||
|
stopped = true;
|
||||||
|
while(currentThread != null){}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startDragging(float dTime, float startX, float startY, float endX, float endY){
|
||||||
|
stopDraggingSync();
|
||||||
|
vx = Math.abs((endX - startX)/dTime);
|
||||||
|
vy = Math.abs((endY - startY)/dTime);
|
||||||
|
dirX = (byte) (endX > startX ? 1 : -1);
|
||||||
|
dirY = (byte) (endY > startY ? 1 : -1);
|
||||||
|
ax = vx * a;
|
||||||
|
ay = vy * a;
|
||||||
|
time = System.currentTimeMillis();
|
||||||
|
stopped = false;
|
||||||
|
Thread thread = new Thread(this,"Animatable dragging");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimateDraggingCallback getCallback() {
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(AnimateDraggingCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
17
OsmAnd/src/com/osmand/views/OsmandMapLayer.java
Normal file
17
OsmAnd/src/com/osmand/views/OsmandMapLayer.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package com.osmand.views;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
public interface OsmandMapLayer {
|
||||||
|
|
||||||
|
|
||||||
|
public void initLayer(OsmandMapTileView view);
|
||||||
|
|
||||||
|
public void onDraw(Canvas canvas);
|
||||||
|
|
||||||
|
public void destroyLayer();
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent event);
|
||||||
|
|
||||||
|
}
|
|
@ -1,30 +1,19 @@
|
||||||
package com.osmand.views;
|
package com.osmand.views;
|
||||||
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Formatter;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
@ -36,28 +25,21 @@ import com.osmand.IMapLocationListener;
|
||||||
import com.osmand.LogUtil;
|
import com.osmand.LogUtil;
|
||||||
import com.osmand.MapTileDownloader;
|
import com.osmand.MapTileDownloader;
|
||||||
import com.osmand.OsmandSettings;
|
import com.osmand.OsmandSettings;
|
||||||
|
import com.osmand.ResourceManager;
|
||||||
import com.osmand.MapTileDownloader.DownloadRequest;
|
import com.osmand.MapTileDownloader.DownloadRequest;
|
||||||
import com.osmand.MapTileDownloader.IMapDownloaderCallback;
|
import com.osmand.MapTileDownloader.IMapDownloaderCallback;
|
||||||
import com.osmand.map.ITileSource;
|
import com.osmand.map.ITileSource;
|
||||||
import com.osmand.osm.MapUtils;
|
import com.osmand.osm.MapUtils;
|
||||||
|
import com.osmand.views.AnimateDraggingMapThread.AnimateDraggingCallback;
|
||||||
|
|
||||||
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback{
|
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback, AnimateDraggingCallback{
|
||||||
|
|
||||||
protected final int emptyTileDivisor = DefaultLauncherConstants.MAP_divNonLoadedImage;
|
protected final int emptyTileDivisor = DefaultLauncherConstants.MAP_divNonLoadedImage;
|
||||||
protected final int maxImgCacheSize = 96;
|
|
||||||
protected int drawCoordinatesX = 0;
|
|
||||||
protected int drawCoordinatesY = 55;
|
|
||||||
|
|
||||||
protected final int timeForDraggingAnimation = 300;
|
protected final int timeForDraggingAnimation = 300;
|
||||||
protected final int minimumDistanceForDraggingAnimation = 40;
|
protected final int minimumDistanceForDraggingAnimation = 40;
|
||||||
|
|
||||||
|
|
||||||
protected static final Log log = LogUtil.getLog(OsmandMapTileView.class);
|
protected static final Log log = LogUtil.getLog(OsmandMapTileView.class);
|
||||||
/**
|
|
||||||
* file or directory with tiles
|
|
||||||
*/
|
|
||||||
private File fileWithTiles;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zoom level
|
* zoom level
|
||||||
*/
|
*/
|
||||||
|
@ -70,24 +52,24 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
// name of source map
|
// name of source map
|
||||||
private ITileSource map = null;
|
private ITileSource map = null;
|
||||||
|
|
||||||
/**
|
private IMapLocationListener locationListener;
|
||||||
* listeners
|
|
||||||
*/
|
|
||||||
private List<IMapLocationListener> listeners = new ArrayList<IMapLocationListener>();
|
|
||||||
|
|
||||||
private MapTileDownloader downloader = MapTileDownloader.getInstance();
|
private MapTileDownloader downloader = MapTileDownloader.getInstance();
|
||||||
|
|
||||||
Map<String, Bitmap> cacheOfImages = new HashMap<String, Bitmap>();
|
private List<OsmandMapLayer> layers = new ArrayList<OsmandMapLayer>();
|
||||||
|
|
||||||
private boolean isStartedDragging = false;
|
// UI Part
|
||||||
private double startDraggingX = 0d;
|
|
||||||
private double startDraggingY = 0d;
|
private AnimateDraggingMapThread animatedDraggingThread;
|
||||||
private PointF initStartDragging = null;
|
|
||||||
|
private PointF startDragging = null;
|
||||||
|
private PointF autoStartDragging = null;
|
||||||
|
private long autoStartDraggingTime = 0;
|
||||||
|
|
||||||
Paint paintGrayFill;
|
Paint paintGrayFill;
|
||||||
Paint paintWhiteFill;
|
Paint paintWhiteFill;
|
||||||
Paint paintBlack;
|
Paint paintBlack;
|
||||||
private AnimatedDragging animatedDraggingThread;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,6 +83,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
initView();
|
initView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////// INITIALIZING UI PART ///////////////////////////////////
|
||||||
public void initView(){
|
public void initView(){
|
||||||
paintGrayFill = new Paint();
|
paintGrayFill = new Paint();
|
||||||
paintGrayFill.setColor(Color.GRAY);
|
paintGrayFill.setColor(Color.GRAY);
|
||||||
|
@ -117,117 +100,46 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
setClickable(true);
|
setClickable(true);
|
||||||
getHolder().addCallback(this);
|
getHolder().addCallback(this);
|
||||||
downloader.setDownloaderCallback(this);
|
downloader.setDownloaderCallback(this);
|
||||||
asyncLoadingTiles.start();
|
animatedDraggingThread = new AnimateDraggingMapThread();
|
||||||
|
animatedDraggingThread.setCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
|
// TODO clear cache ?
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLayer(OsmandMapLayer layer){
|
||||||
|
layers.add(layer);
|
||||||
|
layer.initLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeLayer(OsmandMapLayer layer){
|
||||||
|
layers.remove(layer);
|
||||||
|
layer.destroyLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OsmandMapLayer> getLayers() {
|
||||||
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////// NON UI PART (could be extracted in common) /////////////////////////////
|
||||||
public int getTileSize() {
|
public int getTileSize() {
|
||||||
return map == null ? 256 : map.getTileSize();
|
return map == null ? 256 : map.getTileSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void dragTo(double fromX, double fromY, double toX, double toY){
|
|
||||||
double dx = (fromX - toX)/getTileSize();
|
|
||||||
double dy = (fromY - toY)/getTileSize();
|
|
||||||
this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy);
|
|
||||||
this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx);
|
|
||||||
prepareImage();
|
|
||||||
// TODO
|
|
||||||
// fireMapLocationListeners(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AnimatedDragging extends Thread {
|
|
||||||
private float curX;
|
|
||||||
private float curY;
|
|
||||||
private float vx;
|
|
||||||
private float vy;
|
|
||||||
private float ax;
|
|
||||||
private float ay;
|
|
||||||
private byte dirX;
|
|
||||||
private byte dirY;
|
|
||||||
private long time = System.currentTimeMillis();
|
|
||||||
private boolean stopped;
|
|
||||||
private final float a = 0.0005f;
|
|
||||||
|
|
||||||
public AnimatedDragging(float dTime, float startX, float startY, float endX, float endY) {
|
|
||||||
vx = Math.abs((endX - startX)/dTime);
|
|
||||||
vy = Math.abs((endY - startY)/dTime);
|
|
||||||
dirX = (byte) (endX > startX ? 1 : -1);
|
|
||||||
dirY = (byte) (endY > startY ? 1 : -1);
|
|
||||||
ax = vx * a;
|
|
||||||
ay = vy * a;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
while ((vx > 0 || vy > 0) && !isStartedDragging && !stopped) {
|
|
||||||
sleep((long) (40d/(Math.max(vx, vy)+0.45)));
|
|
||||||
long curT = System.currentTimeMillis();
|
|
||||||
int dt = (int) (curT - time);
|
|
||||||
float newX = vx > 0 ? curX + dirX * vx * dt : curX;
|
|
||||||
float newY = vy > 0 ? curY + dirY * vy * dt : curY;
|
|
||||||
if(!isStartedDragging){
|
|
||||||
dragTo(curX, curY, newX, newY);
|
|
||||||
}
|
|
||||||
vx -= ax * dt;
|
|
||||||
vy -= ay * dt;
|
|
||||||
time = curT;
|
|
||||||
curX = newX;
|
|
||||||
curY = newY;
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
animatedDraggingThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopEvaluation(){
|
|
||||||
stopped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
|
||||||
if(event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
||||||
if(animatedDraggingThread != null){
|
|
||||||
animatedDraggingThread.stopEvaluation();
|
|
||||||
}
|
|
||||||
if(!isStartedDragging){
|
|
||||||
startDraggingX = event.getX();
|
|
||||||
startDraggingY = event.getY();
|
|
||||||
isStartedDragging = true;
|
|
||||||
initStartDragging = new PointF(event.getX(), event.getY());
|
|
||||||
}
|
|
||||||
} else if(event.getAction() == MotionEvent.ACTION_UP) {
|
|
||||||
if(isStartedDragging){
|
|
||||||
dragTo(startDraggingX, startDraggingY, event.getX(), event.getY());
|
|
||||||
if(event.getEventTime() - event.getDownTime() < timeForDraggingAnimation &&
|
|
||||||
Math.abs(event.getX() - initStartDragging.x) + Math.abs(event.getY() - initStartDragging.y) > minimumDistanceForDraggingAnimation){
|
|
||||||
float timeDist = (int) (event.getEventTime() - event.getDownTime());
|
|
||||||
if(timeDist < 20){
|
|
||||||
timeDist = 20;
|
|
||||||
}
|
|
||||||
animatedDraggingThread = new AnimatedDragging(timeDist, initStartDragging.x, initStartDragging.y,
|
|
||||||
event.getX(), event.getY());
|
|
||||||
isStartedDragging = false;
|
|
||||||
animatedDraggingThread.start();
|
|
||||||
}
|
|
||||||
isStartedDragging = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if(event.getAction() == MotionEvent.ACTION_MOVE) {
|
|
||||||
if(isStartedDragging){
|
|
||||||
dragTo(startDraggingX, startDraggingY, event.getX(), event.getY());
|
|
||||||
startDraggingX = event.getX();
|
|
||||||
startDraggingY = event.getY();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getXTile(){
|
public double getXTile(){
|
||||||
return MapUtils.getTileNumberX(zoom, longitude);
|
return MapUtils.getTileNumberX(zoom, longitude);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +148,63 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
return MapUtils.getTileNumberY(zoom, latitude);
|
return MapUtils.getTileNumberY(zoom, latitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setZoom(int zoom){
|
||||||
|
if (map == null || (map.getMaximumZoomSupported() >= zoom && map.getMinimumZoomSupported() <= zoom)) {
|
||||||
|
animatedDraggingThread.stopDragging();
|
||||||
|
this.zoom = zoom;
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 setLatLon(double latitude, double longitude){
|
||||||
|
animatedDraggingThread.stopDragging();
|
||||||
|
this.latitude = latitude;
|
||||||
|
this.longitude = longitude;
|
||||||
|
prepareImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLatitude() {
|
||||||
|
return latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLongitude() {
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZoom() {
|
||||||
|
return zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapLocationListener(IMapLocationListener l){
|
||||||
|
locationListener = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds listener to control when map is dragging
|
||||||
|
*/
|
||||||
|
public IMapLocationListener setMapLocationListener(){
|
||||||
|
return locationListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////// DRAWING MAP PART /////////////////////////////////////////////
|
||||||
|
|
||||||
protected void drawEmptyTile(Canvas cvs, int x, int y){
|
protected void drawEmptyTile(Canvas cvs, int x, int y){
|
||||||
int tileDiv = getTileSize() / emptyTileDivisor;
|
int tileDiv = getTileSize() / emptyTileDivisor;
|
||||||
for (int k1 = 0; k1 < emptyTileDivisor; k1++) {
|
for (int k1 = 0; k1 < emptyTileDivisor; k1++) {
|
||||||
|
@ -252,144 +221,12 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread();
|
|
||||||
|
|
||||||
public class AsyncLoadingThread extends Thread {
|
|
||||||
Map<String, DownloadRequest> requests = Collections.synchronizedMap(new LinkedHashMap<String, DownloadRequest>());
|
|
||||||
|
|
||||||
public AsyncLoadingThread(){
|
|
||||||
super("Async loading tiles");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while(true){
|
|
||||||
try {
|
|
||||||
boolean update = false;
|
|
||||||
while(!requests.isEmpty()){
|
|
||||||
String f = requests.keySet().iterator().next();
|
|
||||||
DownloadRequest r = requests.remove(f);
|
|
||||||
// TODO last param
|
|
||||||
getImageForTile(r.xTile, r.yTile, r.zoom, OsmandSettings.useInternetToDownloadTiles);
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
if(update){
|
|
||||||
prepareImage();
|
|
||||||
}
|
|
||||||
sleep(350);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error(e);
|
|
||||||
} catch (RuntimeException e){
|
|
||||||
log.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestToLoadImage(String s, DownloadRequest req){
|
|
||||||
requests.put(s, req);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Bitmap getImageForTile(int x, int y, int zoom, boolean loadIfNeeded){
|
|
||||||
String file = getFileForImage(x, y, zoom, map.getTileFormat());
|
|
||||||
if(fileWithTiles == null || !fileWithTiles.canRead()){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
File en = new File(fileWithTiles, file);
|
|
||||||
if (cacheOfImages.size() > maxImgCacheSize) {
|
|
||||||
onLowMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!downloader.isFileCurrentlyDownloaded(en)) {
|
|
||||||
if (en.exists()) {
|
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
cacheOfImages.put(file, BitmapFactory.decodeFile(en.getAbsolutePath()));
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Loaded file : " + file + " " + -(time - System.currentTimeMillis()) + " ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(loadIfNeeded && cacheOfImages.get(file) == null){
|
|
||||||
ConnectivityManager mgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
NetworkInfo info = mgr.getActiveNetworkInfo();
|
|
||||||
if (info != null && info.isConnected()) {
|
|
||||||
String urlToLoad = map.getUrlToLoad(x, y, zoom);
|
|
||||||
if (urlToLoad != null) {
|
|
||||||
downloader.requestToDownload(urlToLoad, new DownloadRequest(en, x, y, zoom));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cacheOfImages.get(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getImageFor(int x, int y, int zoom, boolean loadIfNeeded) {
|
|
||||||
if (map == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String file = getFileForImage(x, y, zoom, map.getTileFormat());
|
|
||||||
if (cacheOfImages.get(file) == null && loadIfNeeded) {
|
|
||||||
// TODO use loadIfNeeded
|
|
||||||
asyncLoadingTiles.requestToLoadImage(file, new DownloadRequest(null, x, y, zoom));
|
|
||||||
}
|
|
||||||
return cacheOfImages.get(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void tileDownloaded(String dowloadedUrl, DownloadRequest request) {
|
|
||||||
int xTileLeft = (int) Math.floor(getXTile() - getWidth() / (2d * getTileSize()));
|
|
||||||
int yTileUp = (int) Math.floor(getYTile() - getHeight() / (2d * getTileSize()));
|
|
||||||
int startingX = (int) ((xTileLeft - getXTile()) * getTileSize() + getWidth() / 2);
|
|
||||||
int startingY = (int) ((yTileUp - getYTile()) * getTileSize() + getHeight() / 2);
|
|
||||||
int i = (request.xTile - xTileLeft) * getTileSize() + startingX;
|
|
||||||
int j = (request.yTile - yTileUp) * getTileSize() + startingY;
|
|
||||||
if (request.zoom == this.zoom &&
|
|
||||||
(i + getTileSize() >= 0 && i < getWidth()) && (j + getTileSize() >= 0 && j < getHeight())) {
|
|
||||||
SurfaceHolder holder = getHolder();
|
|
||||||
synchronized (holder) {
|
|
||||||
Canvas canvas = holder.lockCanvas(new Rect(i, j, getTileSize() + i, getTileSize() + j));
|
|
||||||
if (canvas != null) {
|
|
||||||
try {
|
|
||||||
Bitmap bmp = getImageFor(request.xTile, request.yTile, zoom, true);
|
|
||||||
if (bmp == null) {
|
|
||||||
drawEmptyTile(canvas, i, j);
|
|
||||||
} else {
|
|
||||||
canvas.drawBitmap(bmp, i, j, null);
|
|
||||||
}
|
|
||||||
drawOverMap(canvas);
|
|
||||||
} finally {
|
|
||||||
holder.unlockCanvasAndPost(canvas);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private MessageFormat formatOverMap = new MessageFormat("Lat : {0}, lon : {1}, zoom : {2}, mem : {3}");
|
|
||||||
java.util.Formatter formatterOMap = new java.util.Formatter();
|
|
||||||
private ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
private void drawOverMap(Canvas canvas){
|
private void drawOverMap(Canvas canvas){
|
||||||
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 (OsmandSettings.showGPSLocationOnMap) {
|
for(OsmandMapLayer layer : layers){
|
||||||
float f= (Runtime.getRuntime().totalMemory())/ 1e6f;
|
layer.onDraw(canvas);
|
||||||
formatterOMap = new Formatter();
|
|
||||||
canvas.drawText(formatterOMap.format("Lat : %.3f, lon : %.3f, zoom : %d, mem : %.3f", latitude, longitude, zoom, f).toString(),
|
|
||||||
drawCoordinatesX, drawCoordinatesY, paintBlack);
|
|
||||||
// canvas.drawText(formatOverMap.format(new Object[]{latitude, longitude, zoom, f}), drawCoordinatesX,
|
|
||||||
// drawCoordinatesY, paintBlack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +250,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i * tileSize + startingX < width; i++) {
|
for (int i = 0; i * tileSize + startingX < width; i++) {
|
||||||
for (int j = 0; j * tileSize + startingY < height; j++) {
|
for (int j = 0; j * tileSize + startingY < height; j++) {
|
||||||
Bitmap bmp = getImageFor(xTileLeft + i, yTileUp + j, zoom, true);
|
ResourceManager mgr = ResourceManager.getResourceManager();
|
||||||
|
Bitmap bmp = mgr.getTileImageForMapAsync(map, xTileLeft + i, yTileUp + j, zoom, OsmandSettings.useInternetToDownloadTiles);
|
||||||
if (bmp == null) {
|
if (bmp == null) {
|
||||||
drawEmptyTile(canvas, i * tileSize + startingX, j * tileSize + startingY);
|
drawEmptyTile(canvas, i * tileSize + startingX, j * tileSize + startingY);
|
||||||
} else {
|
} else {
|
||||||
|
@ -430,104 +268,119 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void tileDownloaded(DownloadRequest request) {
|
||||||
public void setZoom(int zoom){
|
if(request == null){
|
||||||
if (map == null || (map.getMaximumZoomSupported() >= zoom && map.getMinimumZoomSupported() <= zoom)) {
|
// we don't know exact images were changed
|
||||||
if(animatedDraggingThread != null){
|
|
||||||
animatedDraggingThread.stopEvaluation();
|
|
||||||
}
|
|
||||||
this.zoom = zoom;
|
|
||||||
prepareImage();
|
prepareImage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int xTileLeft = (int) Math.floor(getXTile() - getWidth() / (2d * getTileSize()));
|
||||||
|
int yTileUp = (int) Math.floor(getYTile() - getHeight() / (2d * getTileSize()));
|
||||||
|
int startingX = (int) ((xTileLeft - getXTile()) * getTileSize() + getWidth() / 2);
|
||||||
|
int startingY = (int) ((yTileUp - getYTile()) * getTileSize() + getHeight() / 2);
|
||||||
|
int i = (request.xTile - xTileLeft) * getTileSize() + startingX;
|
||||||
|
int j = (request.yTile - yTileUp) * getTileSize() + startingY;
|
||||||
|
if (request.zoom == this.zoom &&
|
||||||
|
(i + getTileSize() >= 0 && i < getWidth()) && (j + getTileSize() >= 0 && j < getHeight())) {
|
||||||
|
SurfaceHolder holder = getHolder();
|
||||||
|
synchronized (holder) {
|
||||||
|
Canvas canvas = holder.lockCanvas(new Rect(i, j, getTileSize() + i, getTileSize() + j));
|
||||||
|
if (canvas != null) {
|
||||||
|
try {
|
||||||
|
ResourceManager mgr = ResourceManager.getResourceManager();
|
||||||
|
Bitmap bmp = mgr.getTileImageForMapSync(map, request.xTile, request.yTile, zoom, false);
|
||||||
|
if (bmp == null) {
|
||||||
|
drawEmptyTile(canvas, i, j);
|
||||||
|
} else {
|
||||||
|
canvas.drawBitmap(bmp, i, j, null);
|
||||||
|
}
|
||||||
|
drawOverMap(canvas);
|
||||||
|
} finally {
|
||||||
|
holder.unlockCanvasAndPost(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getFileWithTiles() {
|
|
||||||
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) {
|
|
||||||
this.fileWithTiles = fileWithTiles;
|
|
||||||
prepareImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLatLon(double latitude, double longitude){
|
|
||||||
this.latitude = latitude;
|
|
||||||
this.longitude = longitude;
|
|
||||||
prepareImage();
|
|
||||||
fireMapLocationListeners(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude() {
|
|
||||||
return latitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude() {
|
|
||||||
return longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getZoom() {
|
|
||||||
return zoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void onLowMemory(){
|
/////////////////////////////////// DRAGGING PART ///////////////////////////////////////
|
||||||
log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size());
|
|
||||||
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
|
|
||||||
// remove first images (as we think they are older)
|
|
||||||
for (int i = 0; i < list.size()/2; i ++) {
|
|
||||||
Bitmap bmp = cacheOfImages.remove(list.get(i));
|
|
||||||
if(bmp != null){
|
|
||||||
bmp.recycle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.gc();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addMapLocationListener(IMapLocationListener l){
|
|
||||||
listeners.add(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeMapLocationListener(IMapLocationListener l){
|
|
||||||
listeners.remove(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void fireMapLocationListeners(Object source){
|
|
||||||
for(IMapLocationListener l : listeners){
|
|
||||||
l.locationChanged(latitude, longitude, source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void dragTo(float fromX, float fromY, float toX, float toY){
|
||||||
|
float dx = (fromX - toX)/getTileSize();
|
||||||
|
float dy = (fromY - toY)/getTileSize();
|
||||||
|
this.latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + dy);
|
||||||
|
this.longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + dx);
|
||||||
prepareImage();
|
prepareImage();
|
||||||
|
if(locationListener != null){
|
||||||
|
locationListener.locationChanged(latitude, longitude, this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean wasMapDraggingAccelerated(MotionEvent event){
|
||||||
|
if(autoStartDragging == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(event.getEventTime() - autoStartDraggingTime < timeForDraggingAnimation){
|
||||||
|
float dist = Math.abs(event.getX() - autoStartDragging.x) + Math.abs(event.getY() - autoStartDragging.y);
|
||||||
|
if(dist > minimumDistanceForDraggingAnimation){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
prepareImage();
|
for (int i = layers.size() - 1; i >= 0; i--) {
|
||||||
|
if (layers.get(i).onTouchEvent(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if(event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
animatedDraggingThread.stopDragging();
|
||||||
// TODO clear cache ?
|
if(startDragging == null){
|
||||||
|
autoStartDragging = new PointF(event.getX(), event.getY());
|
||||||
|
autoStartDraggingTime = event.getEventTime();
|
||||||
|
startDragging = new PointF(event.getX(), event.getY());
|
||||||
|
}
|
||||||
|
} else if(event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
if(startDragging != null){
|
||||||
|
dragTo(startDragging.x, startDragging.y, event.getX(), event.getY());
|
||||||
|
startDragging = null;
|
||||||
|
if(wasMapDraggingAccelerated(event)){
|
||||||
|
float timeDist = (int) (event.getEventTime() - autoStartDraggingTime);
|
||||||
|
if(timeDist < 20){
|
||||||
|
timeDist = 20;
|
||||||
|
}
|
||||||
|
animatedDraggingThread.startDragging(timeDist, autoStartDragging.x, autoStartDragging.y,
|
||||||
|
event.getX(), event.getY());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if(event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||||
|
if(startDragging != null){
|
||||||
|
dragTo(startDragging.x, startDragging.y, event.getX(), event.getY());
|
||||||
|
// save memory do not create new PointF
|
||||||
|
startDragging.x = event.getX();
|
||||||
|
startDragging.y = event.getY();
|
||||||
|
if(event.getEventTime() - autoStartDraggingTime > timeForDraggingAnimation){
|
||||||
|
autoStartDraggingTime = event.getEventTime();
|
||||||
|
autoStartDragging.x = event.getX();
|
||||||
|
autoStartDragging.y = event.getY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,154 +1,111 @@
|
||||||
package com.osmand.views;
|
package com.osmand.views;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Point;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.osmand.DefaultLauncherConstants;
|
import com.osmand.data.Amenity;
|
||||||
import com.osmand.LogUtil;
|
|
||||||
import com.osmand.OsmandSettings;
|
|
||||||
import com.osmand.data.DataTileManager;
|
import com.osmand.data.DataTileManager;
|
||||||
import com.osmand.map.ITileSource;
|
|
||||||
import com.osmand.osm.LatLon;
|
|
||||||
import com.osmand.osm.MapUtils;
|
import com.osmand.osm.MapUtils;
|
||||||
import com.osmand.osm.Node;
|
|
||||||
import com.osmand.osm.OSMSettings.OSMTagKey;
|
|
||||||
|
|
||||||
public class POIMapLayer extends View {
|
public class POIMapLayer implements OsmandMapLayer {
|
||||||
private DataTileManager<Node> nodeManager = null;
|
private static final int radiusClick = 2; // for 15 level zoom
|
||||||
private LatLon currentLocation = null;
|
|
||||||
private int zoomLevel = DefaultLauncherConstants.MAP_startMapZoom;
|
private DataTileManager<Amenity> nodeManager = null;
|
||||||
private Map<Node, Point> points = new LinkedHashMap<Node, Point>();
|
|
||||||
private Paint pointUI;
|
private Paint pointUI;
|
||||||
private static final int radiusClick = 16;
|
private OsmandMapTileView view;
|
||||||
private Toast previousShownToast =null;
|
private List<Amenity> objects;
|
||||||
private final static Log log = LogUtil.getLog(POIMapLayer.class);
|
|
||||||
|
|
||||||
|
|
||||||
public POIMapLayer(Context context, AttributeSet attrs) {
|
// TODO optimize all evaluations
|
||||||
super(context, attrs);
|
|
||||||
initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
public POIMapLayer(Context context) {
|
|
||||||
super(context);
|
|
||||||
initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initUI() {
|
|
||||||
pointUI = new Paint();
|
|
||||||
pointUI.setColor(Color.CYAN);
|
|
||||||
pointUI.setAlpha(150);
|
|
||||||
pointUI.setAntiAlias(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
super.onDraw(canvas);
|
|
||||||
for(Node n : points.keySet()){
|
|
||||||
Point p = points.get(n);
|
|
||||||
canvas.drawCircle(p.x, p.y, radiusClick/2, pointUI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void preparePoints() {
|
|
||||||
points.clear();
|
|
||||||
if (nodeManager != null && currentLocation != null) {
|
|
||||||
double tileNumberX = MapUtils.getTileNumberX(zoomLevel, currentLocation.getLongitude());
|
|
||||||
double tileNumberY = MapUtils.getTileNumberY(zoomLevel, currentLocation.getLatitude());
|
|
||||||
double xTileLeft = tileNumberX - getWidth() / (2d * getTileSize());
|
|
||||||
double xTileRight = tileNumberX + getWidth() / (2d * getTileSize());
|
|
||||||
double yTileUp = tileNumberY - getHeight() / (2d * getTileSize());
|
|
||||||
double yTileDown = tileNumberY + getHeight() / (2d * getTileSize());
|
|
||||||
|
|
||||||
List<Node> objects = nodeManager.getObjects(MapUtils.getLatitudeFromTile(zoomLevel, yTileUp),
|
|
||||||
MapUtils.getLongitudeFromTile(zoomLevel, xTileLeft),
|
|
||||||
MapUtils.getLatitudeFromTile(zoomLevel, yTileDown),
|
|
||||||
MapUtils.getLongitudeFromTile(zoomLevel, xTileRight));
|
|
||||||
for (Node o : objects) {
|
|
||||||
double tileX = MapUtils.getTileNumberX(zoomLevel, o.getLongitude());
|
|
||||||
int x = (int) ((tileX - xTileLeft) * getTileSize());
|
|
||||||
double tileY = MapUtils.getTileNumberY(zoomLevel, o.getLatitude());
|
|
||||||
int y = (int) ((tileY - yTileUp) * getTileSize());
|
|
||||||
points.put(o, new Point(x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
if(event.getAction() == MotionEvent.ACTION_DOWN) {
|
if(event.getAction() == MotionEvent.ACTION_DOWN && objects != null) {
|
||||||
|
double tileNumberX = MapUtils.getTileNumberX(view.getZoom(), view.getLongitude());
|
||||||
if(previousShownToast != null){
|
double tileNumberY = MapUtils.getTileNumberY(view.getZoom(), view.getLatitude());
|
||||||
previousShownToast.cancel();
|
double xTileLeft = tileNumberX - view.getWidth() / (2d * getTileSize());
|
||||||
previousShownToast = null;
|
double yTileUp = tileNumberY - view.getHeight() / (2d * getTileSize());
|
||||||
}
|
int ex = (int) event.getX();
|
||||||
int x = (int) event.getX();
|
int ey = (int) event.getY();
|
||||||
int y = (int) event.getY();
|
int radius = getRadiusPoi(view.getZoom()) * 3 / 2;
|
||||||
|
for(Amenity n : objects){
|
||||||
for(Node n : points.keySet()){
|
double tileX = MapUtils.getTileNumberX(view.getZoom(), n.getNode().getLongitude());
|
||||||
Point p = points.get(n);
|
int x = (int) ((tileX - xTileLeft) * getTileSize());
|
||||||
if(Math.abs(p.x - x) <= radiusClick && Math.abs(p.y - y) <= radiusClick){
|
double tileY = MapUtils.getTileNumberY(view.getZoom(), n.getNode().getLatitude());
|
||||||
StringBuilder b = new StringBuilder();
|
int y = (int) ((tileY - yTileUp) * getTileSize());
|
||||||
b.append("This is an amenity : \n");
|
if(Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius){
|
||||||
b.append("type - ").append(n.getTag(OSMTagKey.AMENITY)).append("\n");
|
Toast.makeText(view.getContext(), n.getSimpleFormat(), Toast.LENGTH_SHORT).show();
|
||||||
if(n.getTag(OSMTagKey.NAME) != null){
|
|
||||||
b.append("name - ").append(n.getTag(OSMTagKey.NAME)).append("\n");
|
|
||||||
}
|
|
||||||
b.append("id - ").append(n.getId());
|
|
||||||
|
|
||||||
previousShownToast = Toast.makeText(getContext(), b.toString(), Toast.LENGTH_SHORT);
|
|
||||||
previousShownToast.show();
|
|
||||||
// TODO use precision
|
|
||||||
log.debug("Precision is " + event.getXPrecision());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onTouchEvent(event);
|
// return super.onTouchEvent(event);
|
||||||
}
|
return false;
|
||||||
|
|
||||||
public void setCurrentLocationAndZoom(LatLon currentLocation, int zoom) {
|
|
||||||
this.currentLocation = currentLocation;
|
|
||||||
this.zoomLevel = zoom;
|
|
||||||
preparePoints();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTileSize(){
|
public int getTileSize(){
|
||||||
ITileSource source = OsmandSettings.tileSource;
|
return view.getTileSize();
|
||||||
return source == null ? 256 : source.getTileSize();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNodeManager(DataTileManager<Node> nodeManager) {
|
public void setNodeManager(DataTileManager<Amenity> nodeManager) {
|
||||||
this.nodeManager = nodeManager;
|
this.nodeManager = nodeManager;
|
||||||
preparePoints();
|
if(view != null){
|
||||||
|
view.prepareImage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LatLon getCurrentLocation() {
|
public DataTileManager<Amenity> getNodeManager() {
|
||||||
return currentLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DataTileManager<Node> getNodeManager() {
|
|
||||||
return nodeManager;
|
return nodeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileView view) {
|
||||||
|
this.view = view;
|
||||||
|
pointUI = new Paint();
|
||||||
|
pointUI.setColor(Color.BLUE);
|
||||||
|
pointUI.setAlpha(150);
|
||||||
|
pointUI.setAntiAlias(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRadiusPoi(int zoom){
|
||||||
|
if(zoom < 15){
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return radiusClick << (zoom - 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas) {
|
||||||
|
if (nodeManager != null && view.getZoom() >= 15) {
|
||||||
|
double tileNumberX = MapUtils.getTileNumberX(view.getZoom(), view.getLongitude());
|
||||||
|
double tileNumberY = MapUtils.getTileNumberY(view.getZoom(), view.getLatitude());
|
||||||
|
double xTileLeft = tileNumberX - view.getWidth() / (2d * getTileSize());
|
||||||
|
double xTileRight = tileNumberX + view.getWidth() / (2d * getTileSize());
|
||||||
|
double yTileUp = tileNumberY - view.getHeight() / (2d * getTileSize());
|
||||||
|
double yTileDown = tileNumberY + view.getHeight() / (2d * getTileSize());
|
||||||
|
|
||||||
|
objects = nodeManager.getObjects(MapUtils.getLatitudeFromTile(view.getZoom(), yTileUp), MapUtils
|
||||||
|
.getLongitudeFromTile(view.getZoom(), xTileLeft), MapUtils.getLatitudeFromTile(view.getZoom(), yTileDown), MapUtils
|
||||||
|
.getLongitudeFromTile(view.getZoom(), xTileRight));
|
||||||
|
for (Amenity o : objects) {
|
||||||
|
double tileX = MapUtils.getTileNumberX(view.getZoom(), o.getNode().getLongitude());
|
||||||
|
int x = (int) ((tileX - xTileLeft) * getTileSize());
|
||||||
|
double tileY = MapUtils.getTileNumberY(view.getZoom(), o.getNode().getLatitude());
|
||||||
|
int y = (int) ((tileY - yTileUp) * getTileSize());
|
||||||
|
canvas.drawCircle(x, y, getRadiusPoi(view.getZoom()), pointUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
|
||||||
public int getZoomLevel() {
|
|
||||||
return zoomLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue