0
votes

I have a google static map that I have stored in a 2d array. When the user clicks on a pixel I know the row / col [ 0 - 1024 ].

I need to convert that row col back into a lat lng. I have been trying to use the code below to do the conversions from pixel to lat lng and back.

What I have done is to take the center lat lng and the zoom level.

  1. Convert the center lat lng to pixel using fromLatLngToPoint.
  2. Using the row / col from the image and the width and height of the image get
private static PointF getPointFromRowCol(int row, int col, int width, int  height, PointF center) {

    double adjustedStartCol = center.x - ((double)width / 2);
    double adjustedStartRow = center.y - ((double)height / 2);

    double adjustedCol = adjustedStartCol + col;
    double adjustedRow = adjustedStartRow + row;

    PointF adjustedWorldPoint = new PointF(adjustedCol, adjustedRow);

    return GoogleMapsProjection2.fromPointToLatLng(adjustedWorldPoint, 17);
}

The problem is when I put the resulting lat lng back into google maps it is off by 100's of meters.

Any ideas?

public final class GoogleMapsProjection2 {
    private final int TILE_SIZE = 256;
    private PointF _pixelOrigin;
    public double _pixelsPerLonDegree;
    public double _pixelsPerLonRadian;

    public GoogleMapsProjection2() {
        this._pixelOrigin = new PointF(TILE_SIZE / 2.0, TILE_SIZE / 2.0);
        this._pixelsPerLonDegree = TILE_SIZE / 360.0;
        this._pixelsPerLonRadian = TILE_SIZE / (2 * Math.PI);
    }

    double bound(double val, double valMin, double valMax) {
        double res;
        res = Math.max(val, valMin);
        res = Math.min(val, valMax);
        return res;
    }

    double degreesToRadians(double deg) {
        return deg * (Math.PI / 180);
    }

    double radiansToDegrees(double rad) {
        return rad / (Math.PI / 180);
    }

    public PointF fromLatLngToPoint(double lat, double lng, int zoom) {
        PointF point = new PointF(0, 0);

        point.x = _pixelOrigin.x + lng * _pixelsPerLonDegree;

        // Truncating to 0.9999 effectively limits latitude to 89.189. This is
        // about a third of a tile past the edge of the world tile.
        double siny = bound(Math.sin(degreesToRadians(lat)), -0.9999, 0.9999);
        point.y = _pixelOrigin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -_pixelsPerLonRadian;

        int numTiles = 1 << zoom;
        point.x = point.x * numTiles;
        point.y = point.y * numTiles;
        return point;
    }

    public PointF fromPointToLatLng(PointF point, int zoom) {
        int numTiles = 1 << zoom;
        point.x = point.x / numTiles;
        point.y = point.y / numTiles;

        double lng = (point.x - _pixelOrigin.x) / _pixelsPerLonDegree;
        double latRadians = (point.y - _pixelOrigin.y) / -_pixelsPerLonRadian;
        double lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
        return new PointF(lat, lng);
    }

    public static PointF fromWorldToPixel(PointF world){
        PointF pixelPoint = new PointF(world.x * (1 << 17), world.y * (1 << 17));
        return pixelPoint;
    }

    public static PointF pixelToWorld(PointF world){
        PointF pixelPoint = new PointF(world.x / (1 << 17), world.y / (1 << 17));
        return pixelPoint;
    }

}
2

2 Answers

0
votes

This page seems to suggest that you can use the other APIs with the static maps.

It seems worth mentioning that you can actually have the Google Maps Javascript API give you the latitudinal & longitudinal coordinates from pixel coordinates.

While it's a little convoluted in V3 here's an example of how to do it.
(NOTE: This is assuming you already have a map and the pixel vertices to be converted to a lat&lng coordinate):

let overlay  = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.onAdd = function() {};
overlay.onRemove = function() {};
overlay.setMap(map);

let latlngObj = overlay.fromContainerPixelToLatLng(new google.maps.Point(pixelVertex.x, pixelVertex.y);

overlay.setMap(null); //removes the overlay

Hope that helps someone.

-1
votes

You can try this Java function:

 function convertPixelToGeo(tx:Number, ty)
{
  $LatBottomSin=min(max(sin($this->mapLatBottom*(M_PI/180)),-0.9999),0.9999);
  $worldMapWidth=(($this->mapWidth/$mapLonDelta)*360)/(2*M_PI);

  $worldMapRadius = $mapWidth / $mapLonDelta * 360/(2*M_PI);     
  $mapOffsetY = ($worldMapRadius/2 *log((1+sin($LatBottomSin))/(1-sin($LatBottomSin))));
  $equatorY = $this->mapHeight + mapOffsetY;   
  $a = ($equatorY-$ty)/$worldMapRadius;

  $lat = 180/Math.PI * (2 * Math.atan(Math.exp($a)) - Math.PI/2);
  $long = $this->mapLonLeft+$tx/$mapWidth*$mapLonDelta;
  return new Point($lat,$long);
 }

If it doesn't work try this:

    int numTiles = 1 << zoom;
    tx = tx / numTiles;
    ty = ty / numTiles;