ProgramingTip

로컬 타일을 사용하는 TileProvider

bestdevel 2020. 10. 31. 09:55
반응형

로컬 타일을 사용하는 TileProvider


TileProvider최신 Android Maps API (v2) 의 새로운 기능 을 사용 하여 GoogleMap. 그러나 내 사용자가 인터넷을 많이 사용하지 않기 때문에 타일을 장치의 zip 파일 / 폴더 구조에 저장하고 싶습니다. Maptiler와 함께 사용하여 타일을 생성 geotiffs합니다. 내 질문은 다음과 달라집니다.

  1. 장치에 타일을 저장하는 가장 좋은 방법은 무엇입니까?
  2. 로컬 타일을 반환하는 TileProvider를 만드는 방법은 무엇입니까?

  1. 타일을 자산 폴더에 넣거나 (앱 크기에 허용되는 경우) 처음 시작할 때 모두 다운로드하여 장치 저장소 (SD 카드)에 넣을 수 있습니다.

  2. 다음과 같이 TileProvider를 구현할 수 있습니다.


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";
    }
}

이제 GoogleMap 인스턴스와 함께 사용할 수 있습니다.

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);
}

제 경우에는 MapTiler에서 생성 한 타일의 y 좌표에도 문제가 있었지만 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;
}

다음과 같이 getTile () 메서드에서 호출합니다.

@Override
public Tile getTile(int x, int y, int zoom) {
    y = fixYCoordinate(y, zoom);
    ...
}

[업데이트]

사용자 지정지도의 정확한 영역을 알고있는 경우 메서드 NO_TILE에서 누락 된 타일을 반환해야합니다 getTile(...).

이것이 내가 한 방법입니다.

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);
}

새 API (v2)에 사용자 지정 타일 제공 업체를 추가 할 수있는 가능성은 훌륭하지만 사용자가 대부분 오프라인이라고 언급했습니다. 사용자가 응용 프로그램을 처음 시작할 때 오프라인 상태 인 경우 사용자가 온라인 상태 여야하므로 새 API를 사용할 수 없습니다 (캐시를 구축하려면 적어도 한 번은 보임). 그렇지 않으면 검은 색 화면 만 표시됩니다.

2 / 22-14 편집 : 최근에 오프라인으로 작업해야하는 앱에 대한 사용자 지정 타일이있는 동일한 문제가 다시 발생했습니다. 클라이언트가 일부 콘텐츠를 다운로드해야하는 초기보기에 보이지 않는 (w / h 0/0) 맵뷰를 추가하여 문제를 해결했습니다. 이것은 작동하는 것처럼 보이며 나중에 오프라인 모드에서 맵 뷰를 사용할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/14784841/tileprovider-using-local-tiles

반응형