Google 尽管有投影,地图仍绘制正方形
Google Maps draw square despite projection
我正在尝试通过 android 在 google 地图上绘制方形网格。
如果我在 python 服务器上使用 geopy 中的 VincentyDistance 测量出 250 米 x 250 米的距离,则地图上生成的网格明显是矩形而不是正方形。
我将其标记为 google 地图使用的投影导致不成比例的拉伸,但如果我改为使用 google 的 SphericalUtil.computeOffset,我可以生成接近完美的正方形在地图上。
这是否表明与 computeOffset 的距离有误?还是那个 geopy 错了?有人可以帮助我理解这种行为吗?
理想情况下,我希望在服务器端进行计算,理想情况下,我可以在世界任何地方生成正方形网格,即使这意味着在现实中正方形不是正方形,只要它在地图投影上显示为正方形即可。
编辑:
"Does this suggest that the distances from computeOffset are wrong? ..."
不,没有错,是投影。投影拉伸、挤压、倾斜……一切
单词投影为矩形,是高度的两倍。 360° 宽,180° 高。
北极和南极(都只是一个点)被拉伸得好像和赤道一样长。
Except ... Google Maps 然后将该地图挤压成几乎一个正方形(取决于缩放比例)。所以你必须检查 Google 地图给你的边界
您可以从地图边界水平读取度数密度,然后垂直读取。加载图块后,您可以阅读此内容。如果您愿意,可以将此数据发送到服务器,使用 AJAX(不包含在此代码中)
如果您屏幕上的像素不是正方形,我也无能为力。
好吧,也许您也可以搜索物理像素密度和因素。也许这有帮助:Mobile web: how to get physical pixel size?
例如:400x400 像素的地图。中间有一个红色方块,是地图宽度和高度的一半。
抱歉,这是 javascript/website 示例,而不是 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>
我正在尝试通过 android 在 google 地图上绘制方形网格。
如果我在 python 服务器上使用 geopy 中的 VincentyDistance 测量出 250 米 x 250 米的距离,则地图上生成的网格明显是矩形而不是正方形。
我将其标记为 google 地图使用的投影导致不成比例的拉伸,但如果我改为使用 google 的 SphericalUtil.computeOffset,我可以生成接近完美的正方形在地图上。
这是否表明与 computeOffset 的距离有误?还是那个 geopy 错了?有人可以帮助我理解这种行为吗?
理想情况下,我希望在服务器端进行计算,理想情况下,我可以在世界任何地方生成正方形网格,即使这意味着在现实中正方形不是正方形,只要它在地图投影上显示为正方形即可。
编辑:
"Does this suggest that the distances from computeOffset are wrong? ..."
不,没有错,是投影。投影拉伸、挤压、倾斜……一切
单词投影为矩形,是高度的两倍。 360° 宽,180° 高。 北极和南极(都只是一个点)被拉伸得好像和赤道一样长。
Except ... Google Maps 然后将该地图挤压成几乎一个正方形(取决于缩放比例)。所以你必须检查 Google 地图给你的边界
您可以从地图边界水平读取度数密度,然后垂直读取。加载图块后,您可以阅读此内容。如果您愿意,可以将此数据发送到服务器,使用 AJAX(不包含在此代码中)
如果您屏幕上的像素不是正方形,我也无能为力。
好吧,也许您也可以搜索物理像素密度和因素。也许这有帮助:Mobile web: how to get physical pixel size?
例如:400x400 像素的地图。中间有一个红色方块,是地图宽度和高度的一半。 抱歉,这是 javascript/website 示例,而不是 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>