General programming

Что ты должен знать про географические координаты

revised 30 January 2013

Короткая шпаргалка для программистов.

🇺🇦 Версія українською

Короткая шпаргалка для программистов.

  • Широта, Latitude, lat - идет с севера (North, N) на юг (South, S).

  • Долгота, Longitude, lng - идет с запада (West, W) на восток (East, E).

  • Практически всегда координаты идут в порядке “широта, долгота” - Lat, Lng. В Google Maps, в Яндекс-Картах, в Википедии. Это стоит зазубрить: в географии сначала идет Y, потом X.

  • И широта, и долгота измеряются в градусах. Градус можно понимать как геометрический градус, то есть 1/360 земной окружности. Иногда их записывают в виде дробного числа, с которым все понятно; иногда - в “часовом” виде: 12°34'56" - 12 градусов, 34 минуты, 56 секунд. Такая запись легко переводится в дробь: deg + min/60.0 + sec/3600.0

  • Долгота изменяется от -180 до +180; ноль - Основной меридиан, проходящий через Гринвич, минусовые значения - западное полушарие, плюсовые - восточное.

  • Широта изменяется от -90 до +90. Ноль - экватор, минусовые значения - южное полушарие, плюсовые - северное.

  • Длина одного градуса долготы непостоянна, поскольку долгота откладывается по окружности, параллельной экватору, и длина этой окружности уменьшается с увеличением (по модулю) широты. Считай длину градуса долготы по формуле

    def lng_2_km(lat)
        EARTH_RADIUS*(Math::PI/180)*cos(lat*Math::PI/180) # EARTH_RADIUS = 6371
    end
    
  • Длина одного градуса широты почти постоянна и равна 111 км.

  • Длина земной окружности (диапазон изменения координат) приблизительно равна 4*10⁸ м. В базовом типе числа с плавающей запятой умещается семь разрядов точности. Это значит, что в переменную или колонку типа single/float влезут координаты с точностью около 10 м. Это значит, что для хранения географических координат лучше использовать поля типа DOUBLE.

  • Расстояние между двумя координатами нельзя считать по Евклидовой формуле (sqrt(x*x+y*y)), потому что они находятся на сфере, а не на плоскости (поэтому, кстати, маршруты дальних перелетов выглядят “неоптимально кривыми” на плоской карте). Расстояние нужно считать по большой окружности.

  • Однако если тебе поставили задачу “показывать близлежащие объекты”, необязательно углубляться в математику и в географические расширения баз данных - для близлежащих точек вполне сойдет евклидово расстояние.

  • А если ещё упростить нашу модель, то можно просто показывать объекты, ограниченные отдельно по каждой координате: WHERE lat BETWEEN lat1 AND lat 2 AND lng BETWEEN lng1 AND lng2. Особенно если ты собираешься показывать результаты выборки на прямоугольной карте. Алгоритм такой:

    def nearest(lat, lng, radius)
      lat2km = LAT_DEGREE_KM # 111
      lng2km = lng_2_km(lat)
      # lat2km*dlat = lng2km*dlng = lateral_distance_km
      # 2*lateral_distance_km^2 = radius^2
      # lateral_distance_km = radius / sqrt(2)
      dlat = radius / (lat2km * Math.sqrt(2))
      dlng = radius / (lng2km * Math.sqrt(2))
    
      where(:lat => (lat-dlat)..(lat+dlat), :lng => (lng-dlng)..(lng+dlng))
    end
    

    Такое условие можно запросто скормить движку полнотекстового поиска, например, Sphinx Search - именно так работает поиск на rentfeed.dp.ua.

  • И, наконец, координаты Днепропетровска - 48 градусов северной широты, 35 градусов восточной долготы.