Как рассчитать ограничивающий прямоугольник для заданного расстояния и широты / долготы

13

Мне нужно иметь возможность рассчитать ограничивающую рамку или окружность для заданной широты WGS84 и долготы WGS84, а также расстояния, но я не знаю, с чего начать!

Расстояние от начала широты / долготы будет 10 км или меньше.

Может ли кто-нибудь дать мне несколько советов / Пример того, как это сделать?

NMTOKEN
источник
Для кругов, которые не охватывают ни одного из полюсов, подробный ответ приводится по адресу gis.stackexchange.com/questions/19221/… . Но это не полная история, как показывают текущие ответы: вы можете сделать компромисс между скоростью и точностью программы. Также обратите внимание, что при задании ограничивающих рамок при работе в широте существует проблема «обхода» (трудности возникают при меридиане + -180 градусов). Для решения этой проблемы см. Gis.stackexchange.com/questions/17788/… .
whuber
Вы действительно нуждаетесь в коробке, или было бы достаточно 4 пунктов около данной точки? Для заданной точки p найдите расстояние 4 точки d в направлениях NE, SW, SE и NW от p.
Кирк Куйкендалл
@Kirk - Если у вас есть координаты 4 точек, то у вас есть поле ...
martinstoeckli
@martinstoeckli Правильно, я просто надеялся упростить проблему, не имея необходимости визуализировать, как выглядит коробка, спроецированная на сферу. Также обратите внимание, что проблема может быть обобщена, чтобы прояснить, что стороны прямоугольника не должны падать на одну и ту же широту / долготу (повернутый прямоугольник другими словами).
Кирк Куйкендалл
@ Кирк - А, ну, если вам это нужно, то вы правы, конечно. Я думаю, что поле полезно только для быстрого поиска возможных кандидатов. Чтобы проверить, находятся ли две точки на определенном расстоянии (круг), можно использовать более сложную формулу haversine.
martinstoeckli

Ответы:

15

WGS-что? WGS-84? В зависимости от того, какая точность вам нужна, вам, возможно, потребуется знать гораздо больше информации - я думаю, именно поэтому за вас проголосовали, хотя никто не удосужился оставить комментарий, объясняющий почему.

Вот два способа:

Неточно, но, вероятно, «достаточно хорошо»

Один градус широты составляет приблизительно 10001,965729 / 90 километров (расстояние от экватора до полюса, деленное на девяносто градусов) или 111,113 километра с использованием данных WGS-84. Это приблизительное значение из-за формы земли и потому, что расстояния меняются при приближении к полюсам (одна из причин использовать широту, а не долготу - в конечном итоге расстояние в один градус долготы равно нулю!) Земля также не идеальна сфера. Обе эти причины являются причиной использования более сложного подхода на основе проекций и основанных на данных, в моем втором ответе.

10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees

Это использует десятичные градусы, а не градусы / минуты / секунды.

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

Любой ГИС, читающий это, будет содрогаться. Это будет в основном точно, хотя, в зависимости от того, где вы находитесь в мире. Для радиуса 10 км это должно быть хорошо.

Гораздо точнее, но больше кода

Используйте библиотеку проекций и укажите свои данные и т. Д. Я рекомендую Proj4; он широко используется, поэтому Google возвращает кучу результатов по вопросам об этом, и есть обертки Delphi . Если у вас возникли проблемы с его использованием, опубликуйте еще один вопрос на SO - он выходит за рамки этого. На веб-сайте Proj4 есть примеры использования базовых API, и хотя они написаны на языке C, их должно быть довольно легко перевести. Их ссылка на API - лучшее место для начала, за которым следует FAQ .

Я бы использовал WGS-84 в качестве базового элемента (представление Земли), если вы не знаете конкретный объект, который вы хотите использовать, или который использовался для создания ваших координат. Это обычно используется и довольно точно.

Если ваша позиция основана на Google Картах (например), укажите проекцию Меркатора. Вы можете использовать другую проекцию или, скажем, координаты UTMвместо широты и долготы, в зависимости от источника ваших данных и от того, хотите ли вы высокую точность для небольшого локального района. (У UTM есть несколько зон, каждая из которых изменяет искажение, так что в пределах этой зоны это очень точно; если вы используете зону для координат вне ее, искажение будет значительно увеличиваться при удалении. Если вы просматриваете всю Землю, спроецированную из одной зона может быть неузнаваемой. Но в пределах зоны UTM переводы будут примерно такими же хорошими, как вы можете получить. Координаты обычно указываются в метрах, а не в градусах, поэтому это может быть более полезным для вас, если вам требуется 10 км. радиус. 10 км легко в пределах одной зоны, вам просто нужно выбрать соответствующую зону на основе вашей центральной координаты. Единственный сложный момент, когда вы приближаетесь к границе: это обычная ситуация, и это хорошо, простов соответствии с тем, как вы выбираете, какой вы используете . Proj4 также позволит вам переводить проекции, чтобы вы могли перейти от своего Mercator WGS-84 lat / long к UTM-зоне n , например, или в и из двух UTM-зон.)

Дэвид
источник
2
Что касается того, где мы живем, один из геодезистов сказал мне, что для своих умственных расчетов он использует 1 градус, равный примерно 108 км. Мысленно 10 км - это примерно 0,1 градуса. Поскольку это грубые приближения, лучше всего рассматривать их с точностью до 1 значащей цифры (не более 2 или 3), а не 0,089982311915998, поскольку это подразумевает уровень точности.
Стивен Куан
1
На самом деле нетрудно вычислить градусы более точно, учитывая широту. Поскольку компьютер выполняет вычисления, в приближении ничего не получается (см. Первую функцию в моем примере).
martinstoeckli
3

Предполагая, что вы хотите сделать запрос в базе данных, вы, вероятно, захотите сделать быстрый (неточный) поиск, а затем точно рассчитать расстояние для получаемых мест. Это твой сценарий?

Следующая функция (в PHP, извините) примерно рассчитает разницу по широте и долготе. Эти различия зависят от широты вашей поисковой точки. Используйте их (с небольшим допуском) для быстрого поиска в базе данных. Поле можно вычислить просто с помощью широты + -deltaLatitude и долготы + -deltaLongitude.

deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])

/**
 * Calculates the deltas in latitude and longitude to use, for a db search
 * around a location in the database.
 * @param float $distance Radius to use for the search [m]
 * @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
 * @param float $deltaLatitude Calculated delta in latitude [deg]
 * @param float $deltaLongitude Calculated delta in longitude [deg]
 * @param float $earthRadius Mean earth radius in [m]
 */
public static function angleFromSphericDistance($distance, $latitude,
  &$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
  $lat = deg2rad($latitude);

  $radiusOnLatitude = cos($lat) * $earthRadius;
  $deltaLatitude = $distance / $earthRadius;
  $deltaLongitude = $distance / $radiusOnLatitude;

  $deltaLatitude = rad2deg($deltaLatitude);
  $deltaLongitude = rad2deg($deltaLongitude);
}

С помощью формулы haversine вы можете рассчитать расстояния на сфере. Используйте его для каждого найденного места, чтобы получить «точное» расстояние. Таким образом, вы можете проверить, находятся ли два места в пределах определенного радиуса (круг вместо прямоугольника).

/**
 * Calculates the great-circle distance between two points, with
 * the Haversine formula.
 * @param float $latitudeFrom Latitude of start point in [deg decimal]
 * @param float $longitudeFrom Longitude of start point in [deg decimal]
 * @param float $latitudeTo Latitude of target point in [deg decimal]
 * @param float $longitudeTo Longitude of target point in [deg decimal]
 * @param float $earthRadius Mean earth radius in [m]
 * @return float Distance between points in [m] (same as earthRadius)
 */
public static function haversineGreatCircleDistance(
  $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
  // convert from degrees to radians
  $latFrom = deg2rad($latitudeFrom);
  $lonFrom = deg2rad($longitudeFrom);
  $latTo = deg2rad($latitudeTo);
  $lonTo = deg2rad($longitudeTo);

  $latDelta = $latTo - $latFrom;
  $lonDelta = $lonTo - $lonFrom;

  $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
  return $angle * $earthRadius;
}
martinstoeckli
источник
3

Для тестирования является ли широта / долгота в пределах или за пределами ограничивающей круг, вам нужно вычислить расстояние от ссылки широта / долгота в широта / долгота момент вы хотите проверить. Поскольку ваше расстояние составляет 10 км или меньше, я бы попытался использовать эквираугольное приближение, чтобы получить расстояние, а не Haversine из-за простоты. Чтобы узнать расстояние в км:

x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )

Важное примечание: широта / долгота в этих формулах указаны в радианах, а не в градусах. Типичное значение EarthRadius составляет 6371 км, что будет возвращать расстояние в единицах км. Теперь это простой тест, если ваше расстояние находится внутри или за пределами круга. Если работает ограничивающий круг, я бы пошел с этим.

Для ограничивающего прямоугольника я бы предположил, что вы хотите, чтобы прямоугольник был определен параллельным экватору. Затем я бы вычислял углы ограничительной рамки, используя расчеты дальности / подшипника (для подшипников 45 градусов, 135 градусов, 225 градусов и 315 градусов). Оттуда я бы предположил, что вы не вокруг полюсов, и используйте точку в тесте полигонов.

Treya
источник
2

Ниже приведен код T-SQL, который я использую для построения ограничительной рамки в SQL-Server 2012. В моем случае я получаю десятичные значения для Lat, Long. Я использую это для быстрого ограничения количества строк, прежде чем использовать STDistanceфункцию SQL, чтобы убедиться, что результаты на самом деле находятся в пределах определенного расстояния. Географические функции очень дороги в SQL Server, поэтому, создав ограничивающий прямоугольник, я могу значительно сократить количество раз его выполнения.

DECLARE @Lat DECIMAL(20, 13) = 35.7862
   ,@Long DECIMAL(20, 13) = -80.3095
   ,@Radius DECIMAL(7, 2) = 5
   ,@Distance DECIMAL(10, 2)
   ,@Earth_Radius INT = 6371000;

SET @Distance = @Radius * 1609.344;

DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
   ,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
   ,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
   ,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));

SELECT *
    FROM CustomerPosition AS cp
    WHERE (
            cp.Lat >= @SouthLat
            AND cp.Lat <= @NorthLat )
        AND (
              cp.Long >= @WestLong
              AND cp.Long <= @EastLong )
Владимир Осельский
источник