Карты Google рисуют квадрат, несмотря на проекцию

Я пытаюсь нарисовать квадратную сетку на картах Google через Android.

Если я измерю расстояния 250 на 250 метров на своем сервере Python, используя VincentyDistance в geopy, результирующая сетка на карте будет прямоугольной, а не квадратной.

Я бы отметил это как вызванное проекцией, используемой картами Google, вызывающей непропорциональное растяжение, хотя, если я вместо этого использую SphericalUtil.computeOffset от Google, я могу создать почти идеальные квадраты на карте.

Означает ли это, что расстояния от calculateOffset неверны? Или что геопы неверны? Может ли кто-нибудь помочь мне понять это поведение?

В идеале я хотел бы, чтобы вычисления выполнялись на стороне сервера, и в идеале я мог бы создать квадратную сетку в любой точке мира, даже если это означает, что на самом деле квадрат не является квадратом, пока он выглядит квадратным на проекции карты.


person RedEyes    schedule 11.08.2017    source источник


Ответы (1)


РЕДАКТИРОВАТЬ:

«Означает ли это, что расстояния от calculateOffset неверны? ..."

Нет, это не неправильно, это проекция. Проекции растягиваются, сжимаются, искажаются, ... все

Слово проецируется в виде прямоугольника, вдвое превышающего высоту. 360° в ширину, 180° в высоту. Северный и южный полюса (оба всего лишь точка) вытянуты так, как если бы они были такими же длинными, как экватор.

За исключением ... Карты Google затем сжимают эту карту почти до квадрата (в зависимости от масштаба). Поэтому вы должны проверить границы, которые дает вам Google Maps.


Вы можете прочитать плотность градусов по горизонтали, а затем по вертикали от границ карты. Когда плитки загружены, вы можете прочитать это. Если вы хотите, вы можете отправить эти данные на сервер с помощью AJAX (не включено в этот код)

Одна вещь, с которой я не могу помочь, это если пиксели на вашем экране не квадратные.

Что ж, может быть, вы можете найти физическую плотность пикселей и учесть ее. Возможно, это поможет: Мобильный Интернет: как получить размер физического пикселя?

В качестве примера: карта 400x400 px. Красный квадрат посередине, половина ширины и высоты карты. Извините, это пример 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>
person Emmanuel Delay    schedule 11.08.2017
comment
Спасибо за такой интересный подход. Проблема в том, что нужна сетка, которая непротиворечива от пользователя к пользователю, поэтому я делаю это на стороне сервера. - person RedEyes; 12.08.2017