如何从(x, y)屏幕坐标转换为LatLng(谷歌地图)

How to convert from (x, y) screen coordinates to LatLng (Google Maps)

本文关键字:屏幕坐标 转换 谷歌地图 LatLng      更新时间:2023-09-26

我正在使用Google Maps和Leap Motion实现一个应用程序,我现在想要什么,我有点卡住了,是一种将(x, y)屏幕坐标转换为Google Maps LatLng对象的方法。

我想实现这一点,以便在用户使用Leap Motion指向的点上启动全景(街景)。

我知道fromPointToLatLng函数的存在,但我不知道使用它的正确方法是什么,以及如何将我的x和y坐标转换为llng变量。

你能帮我一下吗?
function latLng2Point(latLng, map) {
  var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
  var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
  var scale = Math.pow(2, map.getZoom());
  var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
  return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
}
function point2LatLng(point, map) {
  var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
  var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
  var scale = Math.pow(2, map.getZoom());
  var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
  return map.getProjection().fromPointToLatLng(worldPoint);
}

经过一些研究和一些失败后,我想出了一个解决方案。根据这个链接的文档,我发现google点的计算范围是x:[0-256], y:[0-256](贴图是256x256像素),(0,0)点是地图的最左边的点(查看链接获取更多信息)。

然而,我的方法如下:

  • 具有x和y坐标(这是屏幕上的坐标-在地图上),我计算了x和y坐标放置在响应包含地图(在我的情况下,洞窗)的div的百分比

  • 计算(可见)地图的东北和西南边界

  • 转换google Points的边界

  • 在x和y的边界和百分比的帮助下,以google点计算新的lat和lng

  • 转换回后期lng

      // retrieve the lat lng for the far extremities of the (visible) map
      var latLngBounds = map.getBounds();
      var neBound = latLngBounds.getNorthEast();
      var swBound = latLngBounds.getSouthWest();
      // convert the bounds in pixels
      var neBoundInPx = map.getProjection().fromLatLngToPoint(neBound);
      var swBoundInPx = map.getProjection().fromLatLngToPoint(swBound);
      // compute the percent of x and y coordinates related to the div containing the map; in my case the screen
      var procX = x/window.innerWidth;
      var procY = y/window.innerHeight;
      // compute new coordinates in pixels for lat and lng;
      // for lng : subtract from the right edge of the container the left edge, 
      // multiply it by the percentage where the x coordinate was on the screen
      // related to the container in which the map is placed and add back the left boundary
      // you should now have the Lng coordinate in pixels
      // do the same for lat
      var newLngInPx = (neBoundInPx.x - swBoundInPx.x) * procX + swBoundInPx.x;
      var newLatInPx = (swBoundInPx.y - neBoundInPx.y) * procY + neBoundInPx.y;
      // convert from google point in lat lng and have fun :)
      var newLatLng = map.getProjection().fromPointToLatLng(new google.maps.Point(newLngInPx, newLatInPx));
    

希望这个解决方案也能帮助别人!:)

查看简单的解决方案(v3):

map.getProjection().fromLatLngToPoint(marker.position);

https://developers.google.com/maps/documentation/javascript/3.exp/reference投影

添加基于现有SO问题代码的替代解决方案,尽管原始海报找到了解决方案。

根据这个答案,我们可以找到Google Maps API v3进行转换的必要部分。它的重点是重新定位地图的中心。修改它以从屏幕读取位置需要计算屏幕坐标与屏幕中心的差。

为了这个例子的缘故,我将函数重命名为pixelOffsetToLatLng,并将其更改为返回位置(除此之外,与上面答案中的代码没有太大不同):

function pixelOffsetToLatLng(offsetx,offsety) {
  var latlng = map.getCenter();
  var scale = Math.pow(2, map.getZoom());
  var nw = new google.maps.LatLng(
      map.getBounds().getNorthEast().lat(),
      map.getBounds().getSouthWest().lng()
  );
  var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(latlng);
  var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0);
  var worldCoordinateNewCenter = new google.maps.Point(
      worldCoordinateCenter.x - pixelOffset.x,
      worldCoordinateCenter.y + pixelOffset.y
  );
  var latLngPosition = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
  return latLngPosition;
}

要调用它,你需要传递你在网页元素上的X和Y坐标:

  var x = mapElement.offsetWidth / 2 - screenPositionX;
  var y = screenPositionY - mapElement.offsetHeight / 2;
  pixelOffsetToLatLng(x,y);

对于leap.js端,你只需要将leap.js的坐标映射到网页上,要么通过实验,要么通过使用screen-position插件,像这样工作:

var $handCursor = $('#hand-cursor'); // using jQuery here, not mandatory though
Leap.loop(function(frame) {
  if (frame.hands.length > 0) {
    var hand = frame.hands[0];
    $handCursor.css({
      left: hand.screenPosition()[0] + 'px',
      top: hand.screenPosition()[1] + 'px'
    });
    if ((hand.grabStrength >= 0.6 && lastGrabStrength < 0.6)) {
      var x = mapElement.offsetWidth / 2 - hand.screenPosition()[0];
      var y = hand.screenPosition()[1] - mapElement.offsetHeight / 2;
      map.setCenter(pixelOffsetToLatLng(x, y));
    }
  }
}).use('screenPosition', {
  scale: 0.5
});

下面是一个关于如何在2D环境中使用Leap.js读取坐标的Codepen示例:http://codepen.io/raimo/pen/pKIko

您可以使用鼠标或将手放在Leap Motion Controller上(参见红色"光标"作为视觉提示)来居中Google Maps视图。

显然,谷歌已经决定让生活变得更容易。

这是内置的解决方案:

Point point = googleMap.getProjection.toScreenLocation(latLng)

LatLng latlng = googleMap.getProjection.fromScreenLocation(point)

MapCanvasProjection对象提供了一个称为fromContainerPixelToLatLng的方法,它正好满足您的需要。然而,获得MapCanvasProjection对象的唯一方法是实现OverlayView。为此,我使用了一个虚拟叠加:

    // Create dummy overlay so that we can access MapCanvasProjection
    let overlay = new google.maps.OverlayView();
    overlay.draw = function(){};
    overlay.onAdd = function() {
        this.projectionAvailable = true;
    };
    overlay.onRemove = function() {};
    overlay.setMap(map);

然后,当你需要从屏幕坐标转换到纬度时,lng:

    let x = screen_x_coordinate_relative_to_map_div
    let y = screen_y_coordinate_relative_to_map_div
    if(overlay.projectionAvailable) {
        let projection = overlay.getProjection();
        let divPixel = new google.maps.Point(event.offsetX, event.offsetY);
        let latLng = projection.fromContainerPixelToLatLng(divPixel);
    }

您需要知道地图元素中心的(x0,y0),地图中心的(lat0,lng0),以及每像素度的比率r,对应于地图的缩放级别。

lat(y) = lat0 + r(y-y0)
lng(x) = lng0 + r(x-x0) 

注意,这是一个简化的线性化模型,适用于显示小区域的地图。