¿Cómo calculo el cuadro delimitador para una distancia dada y latitud / longitud

13

Necesito poder calcular un cuadro o círculo delimitador para una latitud WGS84 dada y longitud y distancia WGS84, ¡pero no tengo idea de por dónde empezar!

La distancia desde el inicio Lat / Lon sería de 10 km o menos.

¿Sería posible que alguien me diera algunos consejos / Ejemplo sobre cómo hacer esto?

nmtoken
fuente
Para los círculos que no cubren ninguno de los polos, se proporciona una respuesta detallada en gis.stackexchange.com/questions/19221/… . Pero esta no es la historia completa, como lo sugieren las respuestas actuales: puede hacer compensaciones de complejidad de programa de velocidad-precisión. Tenga en cuenta también que existe un problema "envolvente" al especificar cuadros delimitadores cuando trabaja en lat-lon (las dificultades se producen en el meridiano de + -180 grados). Para una solución a esto, vea gis.stackexchange.com/questions/17788/… .
whuber
¿Realmente necesita una caja, o serían suficientes 4 puntos cerca de un punto dado? Dado un punto p, encuentre 4 puntos d distancia en las direcciones NE, SW, SE y NW de p.
Kirk Kuykendall
@Kirk - Si tienes las coordenadas de los 4 puntos, entonces tienes la caja ...
martinstoeckli
@martinstoeckli bien, solo esperaba simplificar el problema al no tener que visualizar cómo se ve una caja proyectada en una esfera. Tenga en cuenta también que el problema podría generalizarse para dejar en claro que no es necesario que los lados del cuadro caigan en la misma latitud / longitud (un cuadro rotado en otras palabras).
Kirk Kuykendall
@Kirk - Ahh, bueno, si lo necesitas exactamente, entonces tienes razón, por supuesto. Creo que el recuadro solo es útil para encontrar rápidamente a los posibles candidatos. Para verificar si dos puntos están dentro de una cierta distancia (círculo), se puede usar la fórmula de haversina más compleja.
martinstoeckli

Respuestas:

15

WGS-qué? WGS-84? Dependiendo de la precisión que necesite, es posible que necesite saber mucha más información; supongo que es por eso que ha sido rechazado, aunque nadie se molestó en dejar un comentario diciendo por qué.

Aquí hay dos formas:

Inexacta, pero probablemente 'suficientemente buena'

Un grado de latitud es de aproximadamente 10001.965729 / 90 kilómetros (distancia del ecuador al polo, dividido entre noventa grados) o 111.113 kilómetros, utilizando el dato WGS-84. Esta es una aproximación debido a la forma de la tierra, y porque las distancias cambian a medida que te acercas a los polos (una razón para usar la latitud, no la longitud, ¡finalmente la distancia de un grado de longitud es cero!) La tierra tampoco es perfecta esfera. Ambas son razones para usar un enfoque más complejo basado en proyecciones y datos, en mi segunda respuesta.

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

Esto está usando grados decimales, no grados / minutos / segundos.

Entonces, su cuadro delimitador será su punto, más y menos 0.08999 grados. Alternativamente, podría usar este número como un radio, dándole un círculo delimitador .

Cualquier persona SIG que lea esto se estremecerá. Sin embargo, será principalmente preciso, dependiendo de dónde se encuentre en el mundo. Para un radio de 10 km, debería estar bien.

Mucho más preciso, pero más código

Use una biblioteca de proyección y especifique su dato, etc. Recomiendo Proj4; es ampliamente utilizado, por lo que Google devuelve montones de resultados para preguntas al respecto, y hay envoltorios de Delphi . Si tiene problemas para usarlo, publique otra pregunta aquí en SO, está fuera del alcance de esta. El sitio web de Proj4 tiene ejemplos que usan las API básicas, y aunque están en C, debería ser bastante fácil de traducir. Su referencia de API es el mejor lugar para comenzar, seguido de las preguntas frecuentes .

Usaría WGS-84 como un dato básico (representación de la tierra) a menos que conozca uno específico que quiera usar, o que se usó para crear sus coordenadas. Es de uso común y bastante preciso.

Si su posición proviene de Google Maps (por ejemplo), especifique una proyección de Mercator. Es posible que desee usar otra proyección, o usar, por ejemplo, coordenadas UTMen lugar de latitud y longitud, dependiendo de la fuente de sus datos y si desea alta precisión para un área local pequeña. (UTM tiene múltiples zonas, todas las cuales cambian la distorsión para que dentro de esa zona, sea altamente precisa; si usa una zona para coordenadas fuera de ella, la distorsión aumentará enormemente a medida que se aleja. Si ve la Tierra entera proyectada desde una zona, puede ser irreconocible. Pero dentro de una zona, las traducciones UTM serán tan buenas como sea posible. Las coordenadas generalmente se especifican en metros, no en grados, por lo que puede ser más útil para usted, dado que necesita 10 km radio. 10 km es fácilmente dentro de una sola zona, solo tiene que elegir la zona adecuada en función de su coordenada central. El único bit complicado es cuando se acerca a un borde: es una situación común, y está bien, solo estécoherente en la forma en que elige cuál usar . Proj4 también le permitirá traducir proyecciones, para que pueda pasar de su Mercator WGS-84 lat / long a una zona UTM n , por ejemplo, o desde y hacia dos zonas UTM).

David
fuente
2
Para el lugar donde vivimos, un topógrafo me dijo una vez que usa 1 grado aproximadamente igual a 108 km para sus cálculos mentales. Mentalmente 10 km es aproximadamente 0.1 grados. Como se trata de aproximaciones aproximadas, es mejor tratarlas con precisión de 1 dígito significativo (2 o 3 como máximo) en lugar de 0,089982311915998, ya que eso implica un nivel de precisión.
Stephen Quan
1
Realmente no es difícil calcular los grados con mayor precisión, teniendo en cuenta la latitud. Como la computadora hace el cálculo, no se gana nada con una aproximación (vea la primera función en mi ejemplo).
martinstoeckli
3

Suponiendo que desea realizar una consulta en una base de datos, es probable que desee realizar una búsqueda rápida (inexacta) y luego calcular exactamente la distancia para los lugares resultantes. ¿Es ese tu escenario?

La siguiente función (en PHP, lo siento) calculará aproximadamente las diferencias en latitud y longitud. Estas diferencias dependen de la latitud de su punto de búsqueda. Úselos (con una pequeña tolerancia) para realizar una búsqueda rápida en la base de datos. El cuadro se puede calcular simplemente con latitud + -deltaLatitude y longitud + -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);
}

Con la fórmula de Haversine , puede calcular distancias en la esfera. Úselo para cada uno de los lugares encontrados, para obtener la distancia "exacta". De esta manera, puede probar si los dos lugares están dentro de un radio determinado (un círculo en lugar del cuadro).

/**
 * 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
fuente
3

Para probar si un lat / lon está dentro o fuera de un círculo delimitador, debe calcular la distancia desde su lat / lon de referencia al punto lat / lon que desea probar. Como su distancia es de 10 km o menos, intentaría usar la aproximación equirrectangular para obtener la distancia en lugar de Haversine debido a la simplicidad. Para obtener la distancia en km:

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

Nota importante: lat / lon en estas fórmulas están en radianes, no en grados. El valor típico de EarthRadius es 6371 km, que devolverá la distancia en unidades de km. Ahora es una prueba simple si su distancia está dentro o fuera del círculo. Si funciona un círculo delimitador, iría con eso.

Para un rectángulo delimitador, supongo que desea que el rectángulo se defina siendo paralelo al ecuador. Luego calcularía las esquinas del cuadro delimitador utilizando cálculos de rango / demora (las demoras son 45 grados, 135 grados, 225 grados y 315 grados). A partir de ahí, asumiría que no estás alrededor de los polos y usaré un punto en la prueba de polígono.

TreyA
fuente
2

A continuación se muestra el código T-SQL que uso para construir el cuadro delimitador en SQL-Server 2012. En mi caso, obtengo valores decimales para Lat, Long. Lo uso para limitar rápidamente el número de filas antes de usar la STDistancefunción SQL para verificar que los resultados estén realmente a una distancia particular. Las funciones de geografía son muy costosas en SQL Server, por lo tanto, al construir un cuadro delimitador, puedo reducir en gran medida la cantidad de veces que debe ejecutarse.

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 )
Vladimir Oselsky
fuente