Search in sources :

Example 11 with Point

use of com.google.maps.android.geometry.Point in project android-maps-utils by googlemaps.

the class HeatmapTileProvider method getTile.

/**
 * Creates tile.
 *
 * @param x    X coordinate of tile.
 * @param y    Y coordinate of tile.
 * @param zoom Zoom level.
 * @return image in Tile format
 */
public Tile getTile(int x, int y, int zoom) {
    // Convert tile coordinates and zoom into Point/Bounds format
    // Know that at zoom level 0, there is one tile: (0, 0) (arbitrary width 512)
    // Each zoom level multiplies number of tiles by 2
    // Width of the world = WORLD_WIDTH = 1
    // x = [0, 1) corresponds to [-180, 180)
    // calculate width of one tile, given there are 2 ^ zoom tiles in that zoom level
    // In terms of world width units
    double tileWidth = WORLD_WIDTH / Math.pow(2, zoom);
    // how much padding to include in search
    // is to tileWidth as mRadius (padding in terms of pixels) is to TILE_DIM
    // In terms of world width units
    double padding = tileWidth * mRadius / TILE_DIM;
    // padded tile width
    // In terms of world width units
    double tileWidthPadded = tileWidth + 2 * padding;
    // padded bucket width - divided by number of buckets
    // In terms of world width units
    double bucketWidth = tileWidthPadded / (TILE_DIM + mRadius * 2);
    // Make bounds: minX, maxX, minY, maxY
    double minX = x * tileWidth - padding;
    double maxX = (x + 1) * tileWidth + padding;
    double minY = y * tileWidth - padding;
    double maxY = (y + 1) * tileWidth + padding;
    // Deal with overlap across lat = 180
    // Need to make it wrap around both ways
    // However, maximum tile size is such that you wont ever have to deal with both, so
    // hence, the else
    // Note: Tile must remain square, so cant optimise by editing bounds
    double xOffset = 0;
    Collection<WeightedLatLng> wrappedPoints = new ArrayList<WeightedLatLng>();
    if (minX < 0) {
        // Need to consider "negative" points
        // (minX to 0) ->  (512+minX to 512) ie +512
        // add 512 to search bounds and subtract 512 from actual points
        Bounds overlapBounds = new Bounds(minX + WORLD_WIDTH, WORLD_WIDTH, minY, maxY);
        xOffset = -WORLD_WIDTH;
        wrappedPoints = mTree.search(overlapBounds);
    } else if (maxX > WORLD_WIDTH) {
        // Cant both be true as then tile covers whole world
        // Need to consider "overflow" points
        // (512 to maxX) -> (0 to maxX-512) ie -512
        // subtract 512 from search bounds and add 512 to actual points
        Bounds overlapBounds = new Bounds(0, maxX - WORLD_WIDTH, minY, maxY);
        xOffset = WORLD_WIDTH;
        wrappedPoints = mTree.search(overlapBounds);
    }
    // Main tile bounds to search
    Bounds tileBounds = new Bounds(minX, maxX, minY, maxY);
    // If outside of *padded* quadtree bounds, return blank tile
    // This is comparing our bounds to the padded bounds of all points in the quadtree
    // ie tiles that don't touch the heatmap at all
    Bounds paddedBounds = new Bounds(mBounds.minX - padding, mBounds.maxX + padding, mBounds.minY - padding, mBounds.maxY + padding);
    if (!tileBounds.intersects(paddedBounds)) {
        return TileProvider.NO_TILE;
    }
    // Search for all points within tile bounds
    Collection<WeightedLatLng> points = mTree.search(tileBounds);
    // If no points, return blank tile
    if (points.isEmpty()) {
        return TileProvider.NO_TILE;
    }
    // Quantize points
    double[][] intensity = new double[TILE_DIM + mRadius * 2][TILE_DIM + mRadius * 2];
    for (WeightedLatLng w : points) {
        Point p = w.getPoint();
        int bucketX = (int) ((p.x - minX) / bucketWidth);
        int bucketY = (int) ((p.y - minY) / bucketWidth);
        intensity[bucketX][bucketY] += w.getIntensity();
    }
    // Quantize wraparound points (taking xOffset into account)
    for (WeightedLatLng w : wrappedPoints) {
        Point p = w.getPoint();
        int bucketX = (int) ((p.x + xOffset - minX) / bucketWidth);
        int bucketY = (int) ((p.y - minY) / bucketWidth);
        intensity[bucketX][bucketY] += w.getIntensity();
    }
    // Convolve it ("smoothen" it out)
    double[][] convolved = convolve(intensity, mKernel);
    // Color it into a bitmap
    Bitmap bitmap = colorize(convolved, mColorMap, mMaxIntensity[zoom]);
    // Convert bitmap to tile and return
    return convertBitmap(bitmap);
}
Also used : Bitmap(android.graphics.Bitmap) Bounds(com.google.maps.android.geometry.Bounds) ArrayList(java.util.ArrayList) Point(com.google.maps.android.geometry.Point) Point(com.google.maps.android.geometry.Point)

Example 12 with Point

use of com.google.maps.android.geometry.Point in project android-maps-utils by googlemaps.

the class PointQuadTreeTest method testVeryDeepTree.

/**
 * Tests 30,000 items at the same point. Timing results are averaged.
 */
@Test
public void testVeryDeepTree() {
    System.gc();
    for (int i = 0; i < 30000; i++) {
        mTree.add(new Item(0, 0));
    }
    Assert.assertEquals(30000, searchAll().size());
    Assert.assertEquals(30000, mTree.search(new Bounds(0, .1, 0, .1)).size());
    Assert.assertEquals(0, mTree.search(new Bounds(.1, 1, .1, 1)).size());
    mTree.clear();
    System.gc();
}
Also used : Bounds(com.google.maps.android.geometry.Bounds) Point(com.google.maps.android.geometry.Point) Test(org.junit.Test)

Example 13 with Point

use of com.google.maps.android.geometry.Point in project wigle-wifi-wardriving by wiglenet.

the class GridBasedAlgorithm method getClusters.

@Override
public Set<? extends Cluster<T>> getClusters(double zoom) {
    long numCells = (long) Math.ceil(256 * Math.pow(2, zoom) / GRID_SIZE);
    SphericalMercatorProjection proj = new SphericalMercatorProjection(numCells);
    HashSet<Cluster<T>> clusters = new HashSet<Cluster<T>>();
    LongSparseArray<StaticCluster<T>> sparseArray = new LongSparseArray<StaticCluster<T>>();
    synchronized (mItems) {
        for (T item : mItems) {
            Point p = proj.toPoint(item.getPosition());
            long coord = getCoord(numCells, p.x, p.y);
            StaticCluster<T> cluster = sparseArray.get(coord);
            if (cluster == null) {
                cluster = new StaticCluster<T>(proj.toLatLng(new Point(Math.floor(p.x) + .5, Math.floor(p.y) + .5)));
                sparseArray.put(coord, cluster);
                clusters.add(cluster);
            }
            cluster.add(item);
        }
    }
    return clusters;
}
Also used : LongSparseArray(android.support.v4.util.LongSparseArray) Cluster(com.google.maps.android.clustering.Cluster) Point(com.google.maps.android.geometry.Point) SphericalMercatorProjection(com.google.maps.android.projection.SphericalMercatorProjection) HashSet(java.util.HashSet)

Example 14 with Point

use of com.google.maps.android.geometry.Point in project wigle-wifi-wardriving by wiglenet.

the class HeatmapTileProvider method getMaxValue.

/**
 * Calculate a reasonable maximum intensity value to map to maximum color intensity
 *
 * @param points    Collection of LatLngs to put into buckets
 * @param bounds    Bucket boundaries
 * @param radius    radius of convolution
 * @param screenDim larger dimension of screen in pixels (for scale)
 * @return Approximate max value
 */
static double getMaxValue(Collection<WeightedLatLng> points, Bounds bounds, int radius, int screenDim) {
    // Approximate scale as if entire heatmap is on the screen
    // ie scale dimensions to larger of width or height (screenDim)
    double minX = bounds.minX;
    double maxX = bounds.maxX;
    double minY = bounds.minY;
    double maxY = bounds.maxY;
    double boundsDim = (maxX - minX > maxY - minY) ? maxX - minX : maxY - minY;
    // Number of buckets: have diameter sized buckets
    int nBuckets = (int) (screenDim / (2 * radius) + 0.5);
    // Scaling factor to convert width in terms of point distance, to which bucket
    double scale = nBuckets / boundsDim;
    // Make buckets
    // Use a sparse array - use LongSparseArray just in case
    LongSparseArray<LongSparseArray<Double>> buckets = new LongSparseArray<LongSparseArray<Double>>();
    // double[][] buckets = new double[nBuckets][nBuckets];
    // Assign into buckets + find max value as we go along
    double x, y;
    double max = 0;
    for (WeightedLatLng l : points) {
        x = l.getPoint().x;
        y = l.getPoint().y;
        int xBucket = (int) ((x - minX) * scale);
        int yBucket = (int) ((y - minY) * scale);
        // Check if x bucket exists, if not make it
        LongSparseArray<Double> column = buckets.get(xBucket);
        if (column == null) {
            column = new LongSparseArray<Double>();
            buckets.put(xBucket, column);
        }
        // Check if there is already a y value there
        Double value = column.get(yBucket);
        if (value == null) {
            value = 0.0;
        }
        value += l.getIntensity();
        // Yes, do need to update it, despite it being a Double.
        column.put(yBucket, value);
        if (value > max)
            max = value;
    }
    return max;
}
Also used : LongSparseArray(android.support.v4.util.LongSparseArray) Point(com.google.maps.android.geometry.Point)

Example 15 with Point

use of com.google.maps.android.geometry.Point in project wigle-wifi-wardriving by wiglenet.

the class HeatmapTileProvider method getTile.

/**
 * Creates tile.
 *
 * @param x    X coordinate of tile.
 * @param y    Y coordinate of tile.
 * @param zoom Zoom level.
 * @return image in Tile format
 */
public Tile getTile(int x, int y, int zoom) {
    // Convert tile coordinates and zoom into Point/Bounds format
    // Know that at zoom level 0, there is one tile: (0, 0) (arbitrary width 512)
    // Each zoom level multiplies number of tiles by 2
    // Width of the world = WORLD_WIDTH = 1
    // x = [0, 1) corresponds to [-180, 180)
    // calculate width of one tile, given there are 2 ^ zoom tiles in that zoom level
    // In terms of world width units
    double tileWidth = WORLD_WIDTH / Math.pow(2, zoom);
    // how much padding to include in search
    // is to tileWidth as mRadius (padding in terms of pixels) is to TILE_DIM
    // In terms of world width units
    double padding = tileWidth * mRadius / TILE_DIM;
    // padded tile width
    // In terms of world width units
    double tileWidthPadded = tileWidth + 2 * padding;
    // padded bucket width - divided by number of buckets
    // In terms of world width units
    double bucketWidth = tileWidthPadded / (TILE_DIM + mRadius * 2);
    // Make bounds: minX, maxX, minY, maxY
    double minX = x * tileWidth - padding;
    double maxX = (x + 1) * tileWidth + padding;
    double minY = y * tileWidth - padding;
    double maxY = (y + 1) * tileWidth + padding;
    // Deal with overlap across lat = 180
    // Need to make it wrap around both ways
    // However, maximum tile size is such that you wont ever have to deal with both, so
    // hence, the else
    // Note: Tile must remain square, so cant optimise by editing bounds
    double xOffset = 0;
    Collection<WeightedLatLng> wrappedPoints = new ArrayList<WeightedLatLng>();
    if (minX < 0) {
        // Need to consider "negative" points
        // (minX to 0) ->  (512+minX to 512) ie +512
        // add 512 to search bounds and subtract 512 from actual points
        Bounds overlapBounds = new Bounds(minX + WORLD_WIDTH, WORLD_WIDTH, minY, maxY);
        xOffset = -WORLD_WIDTH;
        wrappedPoints = mTree.search(overlapBounds);
    } else if (maxX > WORLD_WIDTH) {
        // Cant both be true as then tile covers whole world
        // Need to consider "overflow" points
        // (512 to maxX) -> (0 to maxX-512) ie -512
        // subtract 512 from search bounds and add 512 to actual points
        Bounds overlapBounds = new Bounds(0, maxX - WORLD_WIDTH, minY, maxY);
        xOffset = WORLD_WIDTH;
        wrappedPoints = mTree.search(overlapBounds);
    }
    // Main tile bounds to search
    Bounds tileBounds = new Bounds(minX, maxX, minY, maxY);
    // If outside of *padded* quadtree bounds, return blank tile
    // This is comparing our bounds to the padded bounds of all points in the quadtree
    // ie tiles that don't touch the heatmap at all
    Bounds paddedBounds = new Bounds(mBounds.minX - padding, mBounds.maxX + padding, mBounds.minY - padding, mBounds.maxY + padding);
    if (!tileBounds.intersects(paddedBounds)) {
        return TileProvider.NO_TILE;
    }
    // Search for all points within tile bounds
    Collection<WeightedLatLng> points = mTree.search(tileBounds);
    // If no points, return blank tile
    if (points.isEmpty()) {
        return TileProvider.NO_TILE;
    }
    // Quantize points
    double[][] intensity = new double[TILE_DIM + mRadius * 2][TILE_DIM + mRadius * 2];
    for (WeightedLatLng w : points) {
        Point p = w.getPoint();
        int bucketX = (int) ((p.x - minX) / bucketWidth);
        int bucketY = (int) ((p.y - minY) / bucketWidth);
        intensity[bucketX][bucketY] += w.getIntensity();
    }
    // Quantize wraparound points (taking xOffset into account)
    for (WeightedLatLng w : wrappedPoints) {
        Point p = w.getPoint();
        int bucketX = (int) ((p.x + xOffset - minX) / bucketWidth);
        int bucketY = (int) ((p.y - minY) / bucketWidth);
        intensity[bucketX][bucketY] += w.getIntensity();
    }
    // Convolve it ("smoothen" it out)
    double[][] convolved = convolve(intensity, mKernel);
    // Color it into a bitmap
    Bitmap bitmap = colorize(convolved, mColorMap, mMaxIntensity[zoom]);
    // Convert bitmap to tile and return
    return convertBitmap(bitmap);
}
Also used : Bitmap(android.graphics.Bitmap) Bounds(com.google.maps.android.geometry.Bounds) ArrayList(java.util.ArrayList) Point(com.google.maps.android.geometry.Point) Point(com.google.maps.android.geometry.Point)

Aggregations

Point (com.google.maps.android.geometry.Point)16 Bounds (com.google.maps.android.geometry.Bounds)5 LongSparseArray (android.support.v4.util.LongSparseArray)3 Cluster (com.google.maps.android.clustering.Cluster)3 SphericalMercatorProjection (com.google.maps.android.projection.SphericalMercatorProjection)3 HashSet (java.util.HashSet)3 Bitmap (android.graphics.Bitmap)2 LongSparseArray (androidx.collection.LongSparseArray)2 ArrayList (java.util.ArrayList)2 SuppressLint (android.annotation.SuppressLint)1 Test (org.junit.Test)1