2012-05-04 20 views
8

Ho un progetto JAVA da utilizzare con Google Static Maps e dopo ore e ore di lavoro, non riesco a far funzionare nulla, spiegherò tutto e spero che qualcuno lo faccia essere in grado di aiutarmiOttenere lon/lat da pixel coords in Google Static Map

Sto usando una mappa statica (480pixels x 480Pixel), il centro della mappa è lat = 47, lon = 1,5 e il livello di zoom è 5.

Ora quello che serve è essere in grado di ottenere lat e lon quando clicco su un pixel su questa mappa statica. Dopo alcune ricerche, ho scoperto che dovrei usare Mercator Projection (giusto?), Ho anche scoperto che ogni livello di zoom raddoppia la precisione in entrambe le dimensioni orizzontale e verticale ma non riesco a trovare la formula giusta per collegare pixel, livello di zoom e lat/lon ...

il mio problema è solo di ottenere lat/lon da pixel, sapendo coordinate e pixel e il livello di zoom del centro ...

Grazie in anticipo!

+0

Avete un collegamento alla pagina in cui avete appreso della proiezione di Mercator? –

risposta

1

Google-maps utilizza le tessere per la mappa per dividere efficacemente il mondo in una griglia di tessere da 256^21 pixel. Fondamentalmente il mondo è composto da 4 tessere nello zoom più basso. Quando inizi a ingrandire ottieni 16 tessere, 64 tessere e 256 tessere. È fondamentalmente un quadruplo. Poiché una tale struttura 1d può appiattire solo una 2d, è necessaria anche una proiezione mercantor o una conversione a WGS 84. Ecco una buona risorsa Convert long/lat to pixel x/y on a given picture. C'è una funzione in Google Maps che converte da lat-long pair a pixel. Ecco un link, ma dice che le tessere sono solo 128x128: http://michal.guerquin.com/googlemaps.html.

  1. Google Maps V3 - How to calculate the zoom level for a given bounds
  2. http://www.physicsforums.com/showthread.php?t=455491
+0

In effetti, non mi interessa "le piastrelle, sto facendo questo progetto in Java quindi tutto quello che ho è una foto che conosco le sue dimensioni (480 pixel x 480 pixel) e conosco le coordinate del suo centro (lat = 47 , lon = 1,5 quindi il pixel del centro è 240x240) e il suo livello di zoom (5). Tutto ciò di cui ho bisogno è la formula per ottenere le coordinate dei pixel ... Grazie in anticipo – user1374021

2

Utilizzare la proiezione di Mercatore.

Se si proietta in uno spazio di [0, 256) da [0,256]:

LatLng(47,=1.5) is Point(129.06666666666666, 90.04191318303863) 

A livello di zoom 5, questi equiparare a pixel coordinate:

x = 129.06666666666666 * 2^5 = 4130 
y = 90.04191318303863 * 2^5 = 2881 

Pertanto, in alto a sinistra della mappa è a :

x = 4130 - 480/2 = 4070 
y = 2881 - 480/2 = 2641 

4070/2^5 = 127.1875 
2641/2^5 = 82.53125 

Infine:

Point(127.1875, 82.53125) is LatLng(53.72271667491848, -1.142578125) 
+0

Grazie per la risposta, ma penso che qualcosa non va. In effetti si dice che il mio in alto a sinistra è a LatLng (53.72271667491848, -1.142578125), che è nel Regno Unito, ma in realtà, l'angolo in alto a sinistra della mia mappa è più in Irlanda, date un'occhiata: http://i50.tinypic.com /9vb2b7.jpg si può vedere la mia finestra, - la mappa è stata centrata su LatLng (47,1.5) - dimensione della mappa è 480x480 - della mappa livello di zoom è 5 -> Quindi credo che LatLng (47 , 1.5) == Punto (240.240) no? (sembra vero quando metto il mouse sopra il punto (240,240) Sono davvero vicino al LatLng (47,1,5)) Grazie in anticipo – user1374021

+0

@ user1374021: thread vecchio, lo so, ma sto lavorando su questo problema e questa risposta è stata di grande aiuto. il problema era con la matematica calcolare x; dovrebbe essere x = 4130 - 480/2 = 3890. y = 2641 è corretto. quando spingi questi numeri, otterrai un massimo di -9.00 che corrisponde alla tua immagine. – 4mla1fn

0

Sulla base della matematica nella risposta di Chris Broadfoot sopra e some other code on Stack Overflow for the Mercator Projection, ho ottenuto questo

public class MercatorProjection implements Projection { 

    private static final double DEFAULT_PROJECTION_WIDTH = 256; 
    private static final double DEFAULT_PROJECTION_HEIGHT = 256; 

    private double centerLatitude; 
    private double centerLongitude; 
    private int areaWidthPx; 
    private int areaHeightPx; 
    // the scale that we would need for the a projection to fit the given area into a world view (1 = global, expect it to be > 1) 
    private double areaScale; 

    private double projectionWidth; 
    private double projectionHeight; 
    private double pixelsPerLonDegree; 
    private double pixelsPerLonRadian; 

    private double projectionCenterPx; 
    private double projectionCenterPy; 

    public MercatorProjection(
      double centerLatitude, 
      double centerLongitude, 
      int areaWidthPx, 
      int areaHeightPx, 
      double areaScale 
    ) { 
     this.centerLatitude = centerLatitude; 
     this.centerLongitude = centerLongitude; 
     this.areaWidthPx = areaWidthPx; 
     this.areaHeightPx = areaHeightPx; 
     this.areaScale = areaScale; 

     // TODO stretch the projection to match to deformity at the center lat/lon? 
     this.projectionWidth = DEFAULT_PROJECTION_WIDTH; 
     this.projectionHeight = DEFAULT_PROJECTION_HEIGHT; 
     this.pixelsPerLonDegree = this.projectionWidth/360; 
     this.pixelsPerLonRadian = this.projectionWidth/(2 * Math.PI); 

     Point centerPoint = projectLocation(this.centerLatitude, this.centerLongitude); 
     this.projectionCenterPx = centerPoint.x * this.areaScale; 
     this.projectionCenterPy = centerPoint.y * this.areaScale; 
    } 

    @Override 
    public Location getLocation(int px, int py) { 
     double x = this.projectionCenterPx + (px - this.areaWidthPx/2); 
     double y = this.projectionCenterPy + (py - this.areaHeightPx/2); 

     return projectPx(x/this.areaScale, y/this.areaScale); 
    } 

    @Override 
    public Point getPoint(double latitude, double longitude) { 
     Point point = projectLocation(latitude, longitude); 

     double x = (point.x * this.areaScale - this.projectionCenterPx) + this.areaWidthPx/2; 
     double y = (point.y * this.areaScale - this.projectionCenterPy) + this.areaHeightPx/2; 

     return new Point(x, y); 
    } 

    // from https://stackoverflow.com/questions/12507274/how-to-get-bounds-of-a-google-static-map 

    Location projectPx(double px, double py) { 
     final double longitude = (px - this.projectionWidth/2)/this.pixelsPerLonDegree; 
     final double latitudeRadians = (py - this.projectionHeight/2)/-this.pixelsPerLonRadian; 
     final double latitude = rad2deg(2 * Math.atan(Math.exp(latitudeRadians)) - Math.PI/2); 
     return new Location() { 
      @Override 
      public double getLatitude() { 
       return latitude; 
      } 

      @Override 
      public double getLongitude() { 
       return longitude; 
      } 
     }; 
    } 

    Point projectLocation(double latitude, double longitude) { 
     double px = this.projectionWidth/2 + longitude * this.pixelsPerLonDegree; 
     double siny = Math.sin(deg2rad(latitude)); 
     double py = this.projectionHeight/2 + 0.5 * Math.log((1 + siny)/(1 - siny)) * -this.pixelsPerLonRadian; 
     Point result = new org.opencv.core.Point(px, py); 
     return result; 
    } 

    private double rad2deg(double rad) { 
     return (rad * 180)/Math.PI; 
    } 

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

Ecco un test di unità per la risposta originale

public class MercatorProjectionTest { 

    @Test 
    public void testExample() { 

     // tests against values in https://stackoverflow.com/questions/10442066/getting-lon-lat-from-pixel-coords-in-google-static-map 

     double centerLatitude = 47; 
     double centerLongitude = 1.5; 

     int areaWidth = 480; 
     int areaHeight = 480; 

     // google (static) maps zoom level 
     int zoom = 5; 

     MercatorProjection projection = new MercatorProjection(
       centerLatitude, 
       centerLongitude, 
       areaWidth, 
       areaHeight, 
       Math.pow(2, zoom) 
     ); 

     Point centerPoint = projection.projectLocation(centerLatitude, centerLongitude); 
     Assert.assertEquals(129.06666666666666, centerPoint.x, 0.001); 
     Assert.assertEquals(90.04191318303863, centerPoint.y, 0.001); 

     Location topLeftByProjection = projection.projectPx(127.1875, 82.53125); 
     Assert.assertEquals(53.72271667491848, topLeftByProjection.getLatitude(), 0.001); 
     Assert.assertEquals(-1.142578125, topLeftByProjection.getLongitude(), 0.001); 

     // NOTE sample has some pretty serious rounding errors 
     Location topLeftByPixel = projection.getLocation(0, 0); 
     Assert.assertEquals(53.72271667491848, topLeftByPixel.getLatitude(), 0.05); 
     // the math for this is wrong in the sample (see comments) 
     Assert.assertEquals(-9, topLeftByPixel.getLongitude(), 0.05); 

     Point reverseTopLeftBase = projection.projectLocation(topLeftByPixel.getLatitude(), topLeftByPixel.getLongitude()); 
     Assert.assertEquals(121.5625, reverseTopLeftBase.x, 0.1); 
     Assert.assertEquals(82.53125, reverseTopLeftBase.y, 0.1); 

     Point reverseTopLeft = projection.getPoint(topLeftByPixel.getLatitude(), topLeftByPixel.getLongitude()); 
     Assert.assertEquals(0, reverseTopLeft.x, 0.001); 
     Assert.assertEquals(0, reverseTopLeft.y, 0.001); 

     Location bottomRightLocation = projection.getLocation(areaWidth, areaHeight); 
     Point bottomRight = projection.getPoint(bottomRightLocation.getLatitude(), bottomRightLocation.getLongitude()); 
     Assert.assertEquals(areaWidth, bottomRight.x, 0.001); 
     Assert.assertEquals(areaHeight, bottomRight.y, 0.001); 
    } 

} 

Se sei (diciamo) lavorando con la fotografia aerea, mi sembra che l'algoritmo non tenga conto dell'effetto di stiramento della proiezione mercator, quindi potrebbe perdere la precisione se la vostra regione di interesse non è relativamente vicina all'eq uator. Immagino tu possa approssimarlo moltiplicando le tue coordinate x per cos (latitudine) del centro?

0

Vale la pena ricordare che puoi effettivamente avere l'API di google maps che ti fornisce le coordinate longitudinali & longitudinale dalle coordinate dei pixel.

Mentre è un po 'contorto in V3 ecco un esempio di come farlo.
(NOTA: Ciò presuppone che si dispone già di una mappa e le vertici pixel per essere convertiti in un 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 

Speranza che aiuta qualcuno.

AGGIORNAMENTO: Mi sono reso conto che ho fatto questo in due modi, entrambi utilizzando ancora lo stesso modo di creare l'overlay (quindi non duplicherò quel codice).

let point = new google.maps.Point(628.4160703464878, 244.02779437950872); 
console.log(point); 
let overlayProj = overlay.getProjection(); 
console.log(overlayProj); 
let latLngVar = overlayProj.fromContainerPixelToLatLng(point); 
console.log('the latitude is: '+latLngVar.lat()+' the longitude is: '+latLngVar.lng());