Android Open Source - CartoCache Q Tile






From Project

Back to project page CartoCache.

License

The source code is released under:

Apache License

If you think the Android project CartoCache listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.codeandmagic.cartocache;
/*  w  ww.j  av  a2 s .  com*/
import android.graphics.Point;

import com.google.android.gms.maps.model.LatLng;

import static com.codeandmagic.cartocache.LocationUtils.*;

/**
 * A {@link com.codeandmagic.cartocache.QTile} is a portion of the world map viewed as a Mercador
 * projection. It can be imagined as a square tile of certain dimensions, for example 256 x 256 pixels.
 *
 * <br/><br/>
 * The world map has different dimensions based on the zoom level:
 *
 * <br/>
 * <p>256 x 256 pixels for zoom level 0</p>
 * <p>512 x 512 pixels for zoom level 1</p>
 * <p>...</p>
 * <p>256 * (2^level - 1) x 256 * (2^level - 1) pixels for zoom level level</p>
 *
 * <br/>
 * Since a tile has 256 x 256 pixels, the map will have a different number of tiles per each zoom level.
 * We can express the map's dimensions in the number of tiles: map width = map height = 2^level tiles.
 *
 * <br/>
 * Each tile is given a pair of (x, y) coordinates ranging from (0, 0) at the top left of the map
 * to (2^level - 1, 2^level - 1) at the bottom right.
 *
 * <br/>
 * For any {@link Place} that has a latitude and a longitude we can
 * compute its (x, y) coordinates on the map at a certain zoom level using the formulae below:
 * <p>sinLatitude = sin(latitude * pi/180)</p>
 * <p>pixelX = ((longitude + 180) / 360) * 256 * 2 level</p>
 * <p>pixelY = (0.5  log((1 + sinLatitude) / (1  sinLatitude)) / (4 * pi)) * 256 * 2 level</p>
 *
 * <br/>
 * We can also compute which tile the {@link Place} belongs to by
 * using tileX = floor(pixelX / 256), tileY = ceiling(pixelY / 256). The reason for using ceiling
 * for the y coordinate is that the latitude grows from the South Pole towards the North Pole
 * while in the coordinate system on Android Y-axis grows from top to bottom.
 *
 * @see <a href="http://en.wikipedia.org/wiki/Mercator_projection">Mercador Projection</a>
 * @see <a href="http://msdn.microsoft.com/en-us/library/bb259689.aspx>Bings Maps Tile System</a>
 */
public class QTile {

    public static QTile[] EMPTY_ARRAY = new QTile[]{};


    /**
     * The x coordinate of the top left corner of the tile.
     */
    public final int x;
    /**
     * The y coordinate of the top left corner of the tile.
     */
    public final int y;
    /**
     * The zoom level for which we compute the coordinates.
     */
    public final ZoomLevel zoom;
    /**
     * The radius of the circle encircling the square tile.
     */
    public final double radius;
    /**
     * The quad key of this tile at the given zoom level.
     */
    public final String quadKey;

    /**
     * The distance between the edge of the world map to the top left corner of the tile.
     */
    public final Point worldLeftTop;
    /**
     * The distance between the edge of the world map and the bottom right corner of the tile.
     */
    public final Point worldRightBottom;
    /**
     * The latitude and longitude of the top left corner of the tile.
     */
    public final LatLng topLeft;
    /**
     * The latitude and longitude of the top right corner of the tile.
     */
    public final LatLng topRight;
    /**
     * The latitude and longitude of the bottom left corner of the tile.
     */
    public final LatLng bottomLeft;
    /**
     * The latitude and longitude of the bottom right corner of the tile.
     */
    public final LatLng bottomRight;
    /**
     * The latitude and longitude of the center of the tile.
     */
    public final LatLng center;

    /**
     * The top left neighbouring tile.
     */
    public QTile topLeftNeighbour;
    /**
     * The top neighbouring tile.
     */
    public QTile topNeighbour;
    /**
     * The top right neighbouring tile.
     */
    public QTile topRightNeighbour;
    /**
     * The left neighbouring tile.
     */
    public QTile leftNeighbour;
    /**
     * The right neighbouring tile.
     */
    public QTile rightNeighbour;
    /**
     * The bottom left neighbouring tile.
     */
    public QTile bottomLeftNeighbour;
    /**
     * The bottom neighbouring tile.
     */
    public QTile bottomNeighbour;
    /**
     * The bottom right neighbouring tile.
     */
    public QTile bottomRightNeighbour;

    /**
     * A flag for remembering whether the neighbouring tiles have been initialized or not.
     */
    private volatile boolean neighboursAreInit = false;

    /**
     * Computes the center {@link com.codeandmagic.cartocache.QTile} for a given geographical position
     * and a certain zoom level.
     * @param latLng
     * @param zoom
     * @return
     */
    public static QTile getTile(LatLng latLng, ZoomLevel zoom) {
        final Point center = latLngToWorldPoint(latLng, zoom);
        final Point tile = worldPointToTileXY(center);
        return new QTile(tile.x, tile.y, zoom);
    }

    public QTile(final int x, final int y, final ZoomLevel zoom) {
        this.x = x;
        this.y = y;
        this.zoom = zoom;

        worldLeftTop = new Point(x * TILE_SIZE, y * TILE_SIZE);
        worldRightBottom = new Point((x + 1) * TILE_SIZE, (y + 1) * TILE_SIZE);

        topLeft = worldPointToLatLng(worldLeftTop, zoom);
        bottomRight = worldPointToLatLng(worldRightBottom, zoom);

        bottomLeft = new LatLng(bottomRight.latitude, topLeft.longitude);
        topRight = new LatLng(topLeft.latitude, bottomRight.longitude);

        // (BR - TL) / 2 + TL
        int centerX = (worldRightBottom.x + worldLeftTop.x) / 2;
        //double halfX = (bottomRight.longitude + topLeft.longitude) / 2.0;
        // (TL - BR) / 2 + BR
        //double halfY = (bottomRight.latitude + topLeft.latitude) / 2.0;
        int centerY = (worldRightBottom.y + worldLeftTop.y) / 2;
        //center = new LatLng(centerX, centerX);
        center = worldPointToLatLng(new Point(centerX, centerY), zoom);

        radius = distanceBetween(center.latitude, center.longitude, topLeft.latitude, topLeft.longitude);
        quadKey = getQuadKey();
    }


    public synchronized void initNeighbourTiles() {
        if (!neighboursAreInit) {
            this.topLeftNeighbour = getNeighbourTile(x - 1, y - 1);
            this.topNeighbour = getNeighbourTile(x, y - 1);
            this.topRightNeighbour = getNeighbourTile(x + 1, y - 1);
            this.leftNeighbour = getNeighbourTile(x - 1, y);
            this.rightNeighbour = getNeighbourTile(x + 1, y);
            this.bottomLeftNeighbour = getNeighbourTile(x - 1, y + 1);
            this.bottomNeighbour = getNeighbourTile(x, y + 1);
            this.bottomRightNeighbour = getNeighbourTile(x + 1, y + 1);
            neighboursAreInit = true;
        }
    }

    /**
     * Compute the closest 3 neighbours based on where the given latitude and longitude are in the current tile.
     *
     * @param latLng
     * @return
     */
    public QTile[] getClosestNeighbourTiles(LatLng latLng) {
        initNeighbourTiles();

        // center
        double x = latLng.longitude;
        double y = latLng.latitude;

        double centerX = center.longitude;
        double centerY = center.latitude;

        // Check in what quarter of this tile is the point situated
        if (x < centerX && y < centerY) {
            return new QTile[]{leftNeighbour, bottomLeftNeighbour, bottomNeighbour};
        } else if (x < centerX && y >= centerY) {
            return new QTile[]{leftNeighbour, topLeftNeighbour, topNeighbour};
        } else if (x >= centerX && y < centerY) {
            return new QTile[]{bottomNeighbour, bottomRightNeighbour, rightNeighbour};
        } else { //if(x >= halfX && y >= halfY) {
            return new QTile[]{topNeighbour, topRightNeighbour, rightNeighbour};
        }
    }

    public String getQuadKey() {
        return LocationUtils.getQuadKey(x, y, zoom.zoom);
    }

    public QTile getNeighbourTile(int x, int y) {
        if (x < 0) {
            x = zoom.maxTiles.x + x;
        } else if (x > zoom.maxTiles.x) {
            x = x - zoom.maxTiles.x;
        }
        if (y < 0) {
            y = zoom.maxTiles.y + y;
        } else if (y > zoom.maxTiles.y) {
            y = y - zoom.maxTiles.y;
        }

        return new QTile(x, y, zoom);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("QTile{");
        sb.append("x=").append(x);
        sb.append(", y=").append(y);
        sb.append(", zoom=").append(zoom);
        sb.append(", worldLeftTop=").append(worldLeftTop);
        sb.append(", worldRightBottom=").append(worldRightBottom);
        sb.append(", topLeft=").append(topLeft);
        sb.append(", bottomRight=").append(bottomRight);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (o == null || QTile.class != o.getClass()) return false;

        final QTile qTile = (QTile) o;

        if (x != qTile.x) return false;
        if (y != qTile.y) return false;
        if (zoom != qTile.zoom) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        result = 31 * result + zoom.hashCode();
        return result;
    }
}




Java Source Code List

com.codeandmagic.cartocache.CartoCacheConfig.java
com.codeandmagic.cartocache.CartoCache.java
com.codeandmagic.cartocache.DataFetcher.java
com.codeandmagic.cartocache.DefaultMarkerConfig.java
com.codeandmagic.cartocache.DefaultPlaceCache.java
com.codeandmagic.cartocache.L.java
com.codeandmagic.cartocache.LocationUtils.java
com.codeandmagic.cartocache.MarkerConfig.java
com.codeandmagic.cartocache.Place.java
com.codeandmagic.cartocache.PlacesCache.java
com.codeandmagic.cartocache.QTileDrawConfig.java
com.codeandmagic.cartocache.QTile.java
com.codeandmagic.cartocache.Utils.java
com.codeandmagic.cartocache.ZoomLevel.java
com.codeandmagic.cartocache.demo.DemoActivity.java
com.codeandmagic.cartocache.demo.DemoMapFragment.java
com.codeandmagic.cartocache.demo.GooglePlace.java
com.codeandmagic.cartocache.demo.GooglePlacesParser.java