TileProvider使用本地的瓷砖 [英] TileProvider using local tiles
问题描述
我想用最新的Android地图API的新 TileProvider
的功能(V2)来覆盖一些自定义的瓷砖上的 GoogleMap的
。然而,由于我的用户不会有互联网很多的时候,我想保持存储在设备上的压缩文件/文件夹结构的瓷砖。我会使用 Maptiler将产生我的瓷砖
与 geotiffs
。我的问题是:
- 什么是存储砖设备上的最佳方法是什么?
- 我如何去创造一个TileProvider返回本地的瓷砖?
-
您可以把瓷砖到资产的文件夹(如果它是可以接受的应用程序的大小),或者它们全部下载上首次启动并投入设备存储(SD卡)。
-
您可以实现TileProvider是这样的:
公共类CustomMapTileProvider实现TileProvider {
私有静态最终诠释TILE_WIDTH = 256;
私有静态最终诠释TILE_HEIGHT = 256;
私有静态最终诠释BUFFER_SIZE = 16 * 1024;
私人AssetManager mAssets;
公共CustomMapTileProvider(AssetManager资产){
mAssets =资产;
}
@覆盖
公共瓷砖getTile(INT X,INT Y,INT变焦){
byte []的图像= readTileImage(X,Y,缩放);
返回图像== NULL?空:新的瓷砖(TILE_WIDTH,TILE_HEIGHT,图像);
}
私人字节[] readTileImage(INT X,INT Y,INT变焦){
在的InputStream = NULL;
ByteArrayOutputStream缓冲区= NULL;
尝试 {
在= mAssets.open(getTileFilename(X,Y,变焦));
缓冲=新ByteArrayOutputStream();
INT NREAD;
byte []的数据=新的字节[BUFFER_SIZE];
而((NREAD = in.read(数据,0,BUFFER_SIZE))!= - 1){
buffer.write(数据,0,NREAD);
}
buffer.flush();
返回buffer.toByteArray();
}赶上(IOException异常E){
e.printStackTrace();
返回null;
}赶上(OutOfMemoryError异常E){
e.printStackTrace();
返回null;
} 最后 {
如果(在!= NULL){尝试in.close(); }赶上(异常忽略){}
如果(!缓冲= NULL){尝试buffer.close(); }赶上(异常忽略){}
}
}
私人字符串getTileFilename(INT X,INT Y,INT变焦){
回归图/+变焦+/+ X +/+ Y +巴纽;
}
}
现在你可以使用它与您的GoogleMap的实例:
私人无效setUpMap(){
mMap.setMapType(GoogleMap.MAP_TYPE_NONE);
mMap.addTileOverlay(新TileOverlayOptions()tileProvider(新CustomMapTileProvider(getResources()getAssets())));
CameraUpdate UPD = CameraUpdateFactory.newLatLngZoom(新经纬度(LAT,LON),缩放);
mMap.moveCamera(UPD);
}
在我来说,我还与Y A问题,通过MapTiler产生的瓦片坐标,但是我加入这个方法到CustomMapTileProvider管理它:
/ **
*固定瓷砖的y轴指数(反向顺序)
* /
私人诠释fixYCoordinate(INT Y,INT变焦){
INT尺寸= 1<<放大; //大小= 2 ^变焦
返回尺寸 - 1 - Ÿ;
}
和来自getTile()这样的方法callig是:
@覆盖
公共瓷砖getTile(INT X,INT Y,INT变焦){
Y = fixYCoordinate(Y,缩放);
...
}
[UPD]
如果你知道你的自定义地图EXAC区,你应该返回 NO_TILE
从 getTile(...)失踪瓷砖
方法。
这是我是如何做的:
私有静态最后SparseArray<矩形> TILE_ZOOMS =新SparseArray<矩形>(){{
放(8,新的矩形(135,180,135,181));
放(9,新的矩形(270,361,271,363));
把(10,新的矩形(541,723,543,726));
把(11,新的矩形(1082,1447,1086,1452));
把(12,新的矩形(2165,2894,2172 2905));
把(13,新的矩形(4330,5789,4345,5810));
把(14,新的矩形(8661,11578,8691,11621));
}};
@覆盖
公共瓷砖getTile(INT X,INT Y,INT变焦){
Y = fixYCoordinate(Y,缩放);
如果(hasTile(X,Y,变焦)){
byte []的图像= readTileImage(X,Y,缩放);
返回图像== NULL?空:新的瓷砖(TILE_WIDTH,TILE_HEIGHT,图像);
} 其他 {
返回NO_TILE;
}
}
私人布尔hasTile(INT X,INT Y,INT变焦){
矩形B = TILE_ZOOMS.get(变焦);
返回b == NULL?假:(b.left< = X&功放;&放大器,X< = b.right和放大器;&安培; b.top< = Y&功放;&安培; Y< = b.bottom);
}
I would like to use the new TileProvider
functionality of the latest Android Maps API (v2) to overlay some custom tiles on the GoogleMap
. However as my users will not have internet a lot of the time, I want to keep the tiles stored in a zipfile/folder structure on the device. I will be generating my tiles using Maptiler
with geotiffs
. My questions are:
- What would be the best way to store the tiles on the device?
- How would I go about creating a TileProvider that returns local tiles?
You can put tiles into assets folder (if it is acceptable for the app size) or download them all on first start and put them into device storage (SD card).
You can implement TileProvider like this:
public class CustomMapTileProvider implements TileProvider {
private static final int TILE_WIDTH = 256;
private static final int TILE_HEIGHT = 256;
private static final int BUFFER_SIZE = 16 * 1024;
private AssetManager mAssets;
public CustomMapTileProvider(AssetManager assets) {
mAssets = assets;
}
@Override
public Tile getTile(int x, int y, int zoom) {
byte[] image = readTileImage(x, y, zoom);
return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image);
}
private byte[] readTileImage(int x, int y, int zoom) {
InputStream in = null;
ByteArrayOutputStream buffer = null;
try {
in = mAssets.open(getTileFilename(x, y, zoom));
buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[BUFFER_SIZE];
while ((nRead = in.read(data, 0, BUFFER_SIZE)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (OutOfMemoryError e) {
e.printStackTrace();
return null;
} finally {
if (in != null) try { in.close(); } catch (Exception ignored) {}
if (buffer != null) try { buffer.close(); } catch (Exception ignored) {}
}
}
private String getTileFilename(int x, int y, int zoom) {
return "map/" + zoom + '/' + x + '/' + y + ".png";
}
}
And now you can use it with your GoogleMap instance:
private void setUpMap() {
mMap.setMapType(GoogleMap.MAP_TYPE_NONE);
mMap.addTileOverlay(new TileOverlayOptions().tileProvider(new CustomMapTileProvider(getResources().getAssets())));
CameraUpdate upd = CameraUpdateFactory.newLatLngZoom(new LatLng(LAT, LON), ZOOM);
mMap.moveCamera(upd);
}
In my case I also had a problem with y coordinate of tiles generated by MapTiler, but I managed it by adding this method into CustomMapTileProvider:
/**
* Fixing tile's y index (reversing order)
*/
private int fixYCoordinate(int y, int zoom) {
int size = 1 << zoom; // size = 2^zoom
return size - 1 - y;
}
and callig it from getTile() method like this:
@Override
public Tile getTile(int x, int y, int zoom) {
y = fixYCoordinate(y, zoom);
...
}
[Upd]
If you know exac area of your custom map, you should return NO_TILE
for missing tiles from getTile(...)
method.
This is how I did it:
private static final SparseArray<Rect> TILE_ZOOMS = new SparseArray<Rect>() {{
put(8, new Rect(135, 180, 135, 181 ));
put(9, new Rect(270, 361, 271, 363 ));
put(10, new Rect(541, 723, 543, 726 ));
put(11, new Rect(1082, 1447, 1086, 1452));
put(12, new Rect(2165, 2894, 2172, 2905));
put(13, new Rect(4330, 5789, 4345, 5810));
put(14, new Rect(8661, 11578, 8691, 11621));
}};
@Override
public Tile getTile(int x, int y, int zoom) {
y = fixYCoordinate(y, zoom);
if (hasTile(x, y, zoom)) {
byte[] image = readTileImage(x, y, zoom);
return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image);
} else {
return NO_TILE;
}
}
private boolean hasTile(int x, int y, int zoom) {
Rect b = TILE_ZOOMS.get(zoom);
return b == null ? false : (b.left <= x && x <= b.right && b.top <= y && y <= b.bottom);
}
这篇关于TileProvider使用本地的瓷砖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!