Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"overzoom" tileoverlay google maps

I have an issue where I'm currently trying to build a custom solution for. I'm struggling, maybe I'll be able to get it to work, but maybe there is already another solution for this.

My customer has a backend for getting tile overlays, but it only goes until zoom level 8. After that, no tiles are shown.

For making more detail tiles, I've used https://stackoverflow.com/a/36696291/969016 in the past. It takes 4 tiles from a higher zoom level and constructs it into 1.

But now, I have to take tiles from a lower zoom-level and need to blow it up. I've been trying to take the above one as a basis, but not yet succeeding. If anyone knows a different approach, I would be really grateful.

Or, maybe it is possible to let Google Maps just keep zooming without requesting a new layer above a certain level? I mean, it does this already anyway between zoomlevels

like image 917
Boy Avatar asked Sep 14 '17 14:09

Boy


1 Answers

Taking the solution for enhancing the resolution of tiles (by composing 4 tiles of a higher zoom level into 1) by @RadekJ here as reference, I started working out the opposite: taking a lower zoom level, cut it up in 4 parts and use it to construct a higher zoom level from it.

Let's say the max zoom level you got tiles for is 8, but you want to be able to zoom down to 9, 10, etc by blowing up these tiles.

Every time you zoom in, the tiles are divided by 2. So taking zoom level 9 as an example, I took the tile from zoom level 8 and cut it into 4 pieces. Then I determined which 'quadrant' I needed for the requested tile at level 9.

Next, I use recursion to be able to get the zoom levels for even higher levels. I'm very happy with the result.

Set DRAW_DEBUG_DATA to true if you want to see the tiles with their x, y and zoom level drawn in them.

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import com.google.android.gms.maps.model.Tile;
import com.google.android.gms.maps.model.TileProvider;

import java.io.ByteArrayOutputStream;

public class OverZoomTileProvider implements TileProvider {

    public static final int MAX_ZOOM = 8;

    private static final boolean DRAW_DEBUG_DATA = false;

    private static final int TILE_SIZE = 256;
    private static final int HALF_TILE_SIZE = TILE_SIZE / 2;

    private Paint tilePainter = new Paint();

    // these will only be used when DRAW_DEBUG_DATA is true
    private Paint debugRectPaint;
    private Paint debugTextPaint;

    private TileProvider mTileProvider;

    public OverZoomTileProvider(TileProvider tileProvider) {
        mTileProvider = tileProvider;

        if (DRAW_DEBUG_DATA) {
            debugRectPaint = new Paint();
            debugRectPaint.setColor(Color.RED);
            debugRectPaint.setStrokeWidth(1);
            debugRectPaint.setStyle(Paint.Style.STROKE);

            debugTextPaint = new Paint();
            debugTextPaint.setColor(Color.WHITE);
            debugTextPaint.setStyle(Paint.Style.FILL);
            debugTextPaint.setColor(Color.BLACK);
            debugTextPaint.setTextSize(20);
        }
    }

    @Override
    public Tile getTile(int x, int y, int zoom) {
        Bitmap image = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE,
                Bitmap.Config.ARGB_8888);
        image.eraseColor(Color.TRANSPARENT);

        Canvas canvas = new Canvas(image);
        drawTile(canvas, zoom, x, y);

        byte[] data = bitmapToByteArray(image);
        image.recycle();

        return new Tile(TILE_SIZE, TILE_SIZE, data);
    }

    private void drawTile(Canvas canvas, int zoom, int x, int y) {

        Bitmap bitmap = getTileAsBitmap(x, y, zoom);

        if (bitmap != null) {
            canvas.drawBitmap(bitmap, 0, 0, tilePainter);
            bitmap.recycle();
        }

        if (DRAW_DEBUG_DATA) {
            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), debugRectPaint);
            canvas.drawText("" + x + ", " + x + " (" + zoom + ")", 128, 128, debugTextPaint);
        }
    }

    private Bitmap getTileAsBitmap(int x, int y, int zoom) {
        if (zoom <= MAX_ZOOM) {
            Tile tile = mTileProvider.getTile(x, y, zoom);

            if (tile == NO_TILE) {
                return null;
            }

            return BitmapFactory.decodeByteArray(tile.data, 0, tile.data.length);
        }


        boolean leftColumn = x % 2 == 0;
        boolean topRow = y % 2 == 0;

        Bitmap bitmap = getTileAsBitmap(x / 2, y / 2, zoom - 1);

        int quadrant;
        if (leftColumn && topRow) {
            quadrant = 1;
        } else if (!leftColumn && topRow) {
            quadrant = 2;
        } else if (leftColumn) {
            quadrant = 3;
        } else {
            quadrant = 4;
        }

        switch (quadrant) {
            case 1:
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, HALF_TILE_SIZE, HALF_TILE_SIZE);
                break;
            case 2:
                bitmap = Bitmap.createBitmap(bitmap, HALF_TILE_SIZE, 0, HALF_TILE_SIZE, HALF_TILE_SIZE);
                break;
            case 3:
                bitmap = Bitmap.createBitmap(bitmap, 0, HALF_TILE_SIZE, HALF_TILE_SIZE, HALF_TILE_SIZE);
                break;
            case 4:
                bitmap = Bitmap.createBitmap(bitmap, HALF_TILE_SIZE, HALF_TILE_SIZE, HALF_TILE_SIZE, HALF_TILE_SIZE);
                break;
        }

        return Bitmap.createScaledBitmap(bitmap, TILE_SIZE, TILE_SIZE, false);
    }

    private static byte[] bitmapToByteArray(Bitmap bm) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.PNG, 100, bos);

        byte[] data = bos.toByteArray();
        try {
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }
}
like image 105
Boy Avatar answered Nov 09 '22 18:11

Boy