2012-05-04 4 views
8

У меня есть проект JAVA, который можно использовать с помощью Google Static Maps, и после нескольких часов работы я не могу заставить работать, я объясню все, и я надеюсь, что кто-то будет быть в состоянии помочь мне.Получение lon/lat от пиксельных координат в Статической карте Google

Я использую статическую карту (480pixels х 480pixels), центром карты является лат = 47, долгота = 1,5 и уровень масштабирования 5.

Теперь то, что мне нужно будет в состоянии получить широты и долгота когда я нажимаю пиксель на этой статической карте. После некоторых поисков я обнаружил, что должен использовать Mercator Projection (правильно?), Я также обнаружил, что каждый уровень масштабирования удваивает точность как по горизонтали, так и по вертикали, но я не могу найти правильную формулу для связи пикселя, уровня масштабирования и лат/долгота ...

Моя проблема только о получении широты/долготы от пикселя, зная COORDS и пиксельных и уровень масштабирования центра ...

Спасибо заранее!

+0

У вас есть ссылка на страницу, где вы узнали о проспекте Меркатора? –

ответ

1

В Google-картах используются плитки для эффективной деления мира на сетку из 256^21 пиксельных плит. В основном мир состоит из 4-х плиток с минимальным увеличением. Когда вы начинаете увеличивать масштаб, вы получаете 16 плиток, а затем 64 плитки, а затем 256 плиток. Это в основном квадтри. Поскольку такая 1d-структура может только сгладить 2d, вам также нужна проекция меркантора или преобразование в WGS 84. Вот хороший ресурс Convert long/lat to pixel x/y on a given picture. В Google Картах есть функция, которая конвертирует из лат-длинной пары в пиксель. Вот ссылка, но она говорит, что плитки только 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

На самом деле, я не забочусь о плитки, я делаю этот проект на Java, поэтому все, что у меня есть, это изображение, которое я знаю его размер (480 пикселей x 480 пикселей), и я знаю его координаты центра (lat = 47 , lon = 1,5, так что пиксель центра равен 240x240) и его уровень масштабирования (5). Все, что мне нужно, это формула для получения любых координат пикселей ... Заранее спасибо – user1374021

2

использовать проекцию Меркатора.

Если спроецировать в пространство [0, 256) по [0,256]:

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

На уровне масштабирования 5, они приравнивают к пиксельным координатам:

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

Таким образом, в левом верхнем углу вашей карты находится :

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

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

И наконец:

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

Спасибо за ваш ответ, но я думаю, что что-то не так. Действительно, вы говорите, что мой верхний левый угол находится в LatLng (53.72271667491848, -1.142578125), который находится в Великобритании, но на самом деле верхний левый угол моей карты больше в Ирландии, посмотрите: http://i50.tinypic.com /9vb2b7.jpg Вы можете увидеть мое окно, - карта центрируются на LatLng (47,1.5) - размер для этой карты составляет 480x480 - уровень масштабирования карты составляет 5 -> Так что я думаю LatLng (47 , 1.5) == Точка (240 240) нет? (это правда, когда я наводил указатель мыши на точку (240,240). Я очень близко к LatLng (47,1.5)) Заранее спасибо – user1374021

+0

@ user1374021: old thread, я знаю, но я работаю над эта проблема и этот ответ был большой помощью. проблема заключалась в математике для вычисления x; это должно быть x = 4130 - 480/2 = 3890. y = 2641 является правильным. когда вы нажимаете эти цифры, вы получите длинный -9.00, который соответствует вашему изображению. – 4mla1fn

0

Основываясь на математике в ответ Криса Broadfoot в выше и some other code on Stack Overflow for the Mercator Projection, я получил эту

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; 
    } 
} 

Вот тестовый модуль для оригинального ответа

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); 
    } 

} 

Если вы (скажем,), работая с аэрофотосъемкой, я чувствую, что алгоритм не учитывает растягивающий эффект проекции меркатора, поэтому он может потерять точность, если ваша область интереса не является относительно близкой к экватору uator. Думаю, вы могли бы приблизить его, умножив ваши координаты x на cos (широта) центра?

0

Кажется, стоит упомянуть, что вы действительно можете иметь API-интерфейс google, чтобы дать вам широтные продольные координаты & из координат пикселей.

Хотя это немного запутанный в V3, вот пример того, как это сделать.
(ПРИМЕЧАНИЕ: Это предполагает, что у вас уже есть карта и пиксельные вершины быть конвертированы в Лат & LNG координат):

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 

Надеется, что кто-то помогает.

ОБНОВЛЕНИЕ: Я понял, что сделал это двумя способами, и по-прежнему использует тот же способ создания наложения (поэтому я не буду дублировать этот код).

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()); 
Смежные вопросы