Skip to main content
 首页 » 编程设计

android之尽管有投影,谷歌地图仍绘制正方形

2025年02月15日35del

我正在尝试通过 android 在谷歌地图上绘制方形网格。

如果我在我的 python 服务器上使用 geopy 中的 VincentyDistance 测量出 250 米 x 250 米的距离,则 map 上生成的网格明显是矩形而不是正方形。

我将其标记为由谷歌地图使用的投影导致不成比例的拉伸(stretch),但如果我改为使用谷歌的 SphericalUtil.computeOffset,我可以在 map 上生成近乎完美的正方形。

这是否表明与 computeOffset 的距离是错误的?还是那个 geopy 错了?有人可以帮助我理解这种行为吗?

理想情况下我希望在服务器端进行计算,理想情况下我可以在世界任何地方生成一个正方形网格,即使这意味着在现实中正方形不是正方形,只要它在 map 投影上显示为正方形即可。

请您参考如下方法:

编辑:

"Does this suggest that the distances from computeOffset are wrong? ..."

不,没有错,是投影。投影拉伸(stretch)、挤压、倾斜……一切

单词被投影为矩形,是高度的两倍。 360° 宽,180° 高。 北极和南极(都只是一个点)被拉伸(stretch)得好像和赤道一样长。

除了 ... Google map 然后将该 map 压缩成几乎一个正方形(取决于缩放比例)。所以你必须检查谷歌地图给你的边界


您可以从 map 边界水平读取度数密度,然后垂直读取。加载图 block 后,您可以阅读此内容。如果您愿意,可以使用 AJAX(未包含在此代码中)将此数据发送到服务器

如果您屏幕上的像素不是正方形,我也无能为力。

好吧,也许您也可以搜索物理像素密度和因素。也许这有帮助:Mobile web: how to get physical pixel size?

例如:400x400 像素的 map 。中间有一个红色方 block ,是 map 宽度和高度的一半。 抱歉,这是一个 javascript/网站示例,而不是 Python/Android。但我想您可以使用相同的原则。

<!DOCTYPE html> 
<html> 
<head> 
<title>Square on Map</title> 
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"> 
<meta charset="utf-8"> 
<style> 
    html, 
    body { 
        height: 400px; 
        width: 400px; 
        padding: 0; 
    } 
    #map { 
        height: 80%; 
    } 
</style> 
<script> 
    var map; 
    // return a polyline.   If you give 2 points, it will simply be a line 
    function makePolyline(points, color, close) { 
        if (close) { 
            points.push(points[0]); // closed polyline, so duplicate the start point as the endpoint 
        } 
        return new google.maps.Polyline({ 
            path: points, 
            //geodesic: false, 
            strokeColor: color, // example: '#FF0000', 
            strokeOpacity: 1.0, 
            strokeWeight: 2, 
            map: map  
        }); 
    } 
 
    function initMap() { 
        var myLocation = { 
            lat: 43, 
            lng: -108 
        }; 
        map = new google.maps.Map(document.getElementById('map'), { 
            center: myLocation, 
            zoom: 5 
        }); 
 
        // wait until the map is loaded before calculating bounds 
        google.maps.event.addListenerOnce(map, 'tilesloaded', function() { 
          var mapWidth = document.getElementById('map').offsetWidth; 
          var mapHeight = document.getElementById('map').offsetWidth; 
          var bounds = map.getBounds(); 
          var NE = bounds.getNorthEast(); 
          var SW = bounds.getSouthWest(); 
 
          // draw a square half the size of the map (200 X 200 px), in the midle  => start at 1/4, stop at 3/4 
          points = [{ 
            lat: SW.lat() + ((NE.lat() - SW.lat()) * 1/4), 
            lng: SW.lng() + ((NE.lng() - SW.lng()) * 1/4) 
          }, 
          { 
            lat: SW.lat() + ((NE.lat() - SW.lat()) * 1/4), 
            lng: SW.lng() + ((NE.lng() - SW.lng()) * 3/4) 
          }, 
          { 
            lat: SW.lat() + ((NE.lat() - SW.lat()) * 3/4), 
            lng: SW.lng() + ((NE.lng() - SW.lng()) * 3/4) 
          }, 
          { 
            lat: SW.lat() + ((NE.lat() - SW.lat()) * 3/4), 
            lng: SW.lng() + ((NE.lng() - SW.lng()) * 1/4) 
          }]; 
          makePolyline(points, '#ff0000', true); 
 
          // display the numbers in a div.  Feel free to not do this 
          document.getElementById('log').innerHTML  = 'map width: ' + mapWidth + 'px - map height: ' + mapHeight + 'px<br/>'; 
          document.getElementById('log').innerHTML += 'horizontal: ' + ((NE.lng() - SW.lng() ) / mapWidth ).toFixed(4) + ' degrees/px<br/>'; 
          document.getElementById('log').innerHTML += 'vertical: ' + ((NE.lat() - SW.lat() ) / mapHeight ).toFixed(4) + ' degrees/px<br/>'; 
        }); 
    } 
</script> 
</head> 
<body> 
  <div id="map"></div> 
  <div id="log"></div> 
  <script src="https://maps.googleapis.com/maps/api/js?callback=initMap" async defer></script> 
</body> 
</html>