2012-05-04 24 views
8

Tôi có một dự án JAVA sử dụng Google Static Maps và sau giờ làm việc, tôi không thể làm việc, tôi sẽ giải thích mọi thứ và hy vọng ai đó sẽ có thể giúp tôi.Nhận lon/lat từ pixel coords trong Google Static Map

Tôi đang sử dụng một bản đồ tĩnh (480pixels x 480pixels), trung tâm của bản đồ là lat = 47, lon = 1,5 và mức độ zoom là 5.

Bây giờ những gì tôi cần là việc có thể để có được lat và lon khi tôi nhấp vào một pixel trên bản đồ tĩnh này. Sau một số tìm kiếm, tôi thấy rằng tôi nên sử dụng Mercator Projection (phải không?), Tôi cũng nhận thấy rằng mỗi mức thu phóng tăng gấp đôi độ chính xác ở cả chiều ngang và chiều dọc nhưng tôi không thể tìm được công thức phù hợp để liên kết pixel, mức thu phóng và lat/lon ...

vấn đề của tôi là chỉ về việc lat/lon từ pixel, biết coords và pixel và mức độ zoom của trung tâm ...

Cảm ơn bạn trước!

+0

Bạn có liên kết đến trang nơi bạn đã học về Phép chiếu Mercator không? –

Trả lời

1

Google-maps sử dụng các lát cho bản đồ để phân chia thế giới thành lưới có kích thước 256^21 pixel. Về cơ bản, thế giới được làm bằng 4 viên gạch ở mức thu phóng thấp nhất. Khi bạn bắt đầu thu phóng, bạn nhận được 16 ô và sau đó là 64 ô và sau đó là 256 ô. Về cơ bản nó là một quadtree. Bởi vì cấu trúc 1d như vậy chỉ có thể làm phẳng 2d bạn cũng cần một phép chiếu thương xót hoặc chuyển đổi thành WGS 84. Đây là một tài nguyên tốt Convert long/lat to pixel x/y on a given picture. Có chức năng trong Google Maps chuyển đổi từ cặp độ dài thành điểm ảnh thành vĩ độ. Đây là một liên kết nhưng nó cho biết các ô chỉ có 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

Trên thực tế, tôi không "quan tâm" về gạch, tôi đang làm dự án này trong Java vì vậy tất cả những gì tôi có là một bức ảnh mà tôi biết kích thước của nó (480pixels x 480pixels) và tôi biết tọa độ của trung tâm (lat = 47) , lon = 1,5 để pixel của trung tâm là 240x240) và mức thu phóng (5). Tất cả những gì tôi cần là công thức để có được bất kỳ tọa độ pixel nào ... Cảm ơn trước – user1374021

2

Sử dụng phép chiếu Mercator.

Nếu bạn dự vào một không gian của [0, 256) bởi [0,256]:

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

Ở mức thu phóng 5, những tương đương với điểm ảnh phối:

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

Do đó, phía trên bên trái của bản đồ của bạn đang ở :

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

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

Cuối cùng:

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

Cảm ơn bạn đã trả lời nhưng tôi nghĩ có điều gì đó sai. Thật vậy, bạn nói ở trên cùng bên trái của tôi là LatLng (53.72271667491848, -1.142578125) ở Vương quốc Anh nhưng trên thực tế, góc trên cùng bên trái của bản đồ của tôi là nhiều hơn ở Ireland, hãy xem: http://i50.tinypic.com /9vb2b7.jpg Bạn có thể thấy cửa sổ của tôi, - bản đồ được tập trung vào LatLng (47,1.5) - kích thước của bản đồ là 480x480 - mức độ phóng của bản đồ là 5 -> Vì vậy, tôi đoán LatLng (47 , 1,5) == Điểm (240,240) không? (có vẻ như đúng khi tôi đặt con chuột lên Điểm (240.240) Tôi thực sự gần với LatLng (47,1.5)) Cảm ơn trước – user1374021

+0

@ user1374021: chủ đề cũ, tôi biết, nhưng tôi đang làm việc vấn đề này và câu trả lời này là một trợ giúp lớn. vấn đề là với toán để tính toán x; nó phải là x = 4130 - 480/2 = 3890. y = 2641 là chính xác. khi bạn đẩy những con số đó qua, bạn sẽ nhận được một lon -9,00 phù hợp với hình ảnh của bạn. – 4mla1fn

0

Dựa trên toán học trong câu trả lời Chris Broadfoot của trên và some other code on Stack Overflow for the Mercator Projection, tôi nhận này

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

Dưới đây là một thử nghiệm đơn vị cho câu trả lời ban đầu

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

} 

Nếu bạn (nói) làm việc với chụp ảnh trên không, tôi cảm thấy như thuật toán không tính đến hiệu ứng kéo dài của phép chiếu mercator, vì vậy nó có thể mất độ chính xác nếu khu vực bạn quan tâm không tương đối gần với eq uator. Tôi đoán bạn có thể ước tính nó bằng cách nhân x của bạn tọa độ bởi cos (vĩ độ) của trung tâm?

0

Có vẻ như đáng nói rằng bạn có thể có API bản đồ google cung cấp cho bạn tọa độ theo chiều dọc & theo chiều dọc từ tọa độ pixel.

Mặc dù nó hơi phức tạp trong V3 đây là ví dụ về cách thực hiện.
(Chú ý: Đây là giả sử bạn đã có một bản đồ và các đỉnh điểm ảnh được chuyển đổi sang một lat & lng phối hợp):

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 

Hy vọng rằng sẽ giúp một ai đó.

CẬP NHẬT: Tôi nhận ra rằng tôi đã thực hiện hai cách này, cả hai vẫn sử dụng cùng một cách tạo lớp phủ (vì vậy tôi sẽ không lặp lại mã đó).

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()); 
Các vấn đề liên quan