TileProvider使用本地的瓷砖 [英] TileProvider using local tiles

查看:104
本文介绍了TileProvider使用本地的瓷砖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用最新的Andr​​oid地图API的新 TileProvider 的功能(V2)来覆盖一些自定义的瓷砖上的 GoogleMap的。然而,由于我的用户不会有互联网很多的时候,我想保持存储在设备上的压缩文件/文件夹结构的瓷砖。我会使用 Maptiler将产生我的瓷砖 geotiffs 。我的问题是:

  1. 什么是存储砖设备上的最佳方法是什么?
  2. 我如何去创造一个TileProvider返回本地的瓷砖?
解决方案
  1. 您可以把瓷砖到资产的文件夹(如果它是可以接受的应用程序的大小),或者它们全部下载上首次启动并投入设备存储(SD卡)。

  2. 您可以实现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:

  1. What would be the best way to store the tiles on the device?
  2. How would I go about creating a TileProvider that returns local tiles?

解决方案

  1. 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).

  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆