Comment calculer le cadre de délimitation pour une distance et une latitude / longitude données

13

J'ai besoin de pouvoir calculer une boîte ou un cercle de délimitation pour une latitude et une longitude WGS84 et une distance WGS84 données, mais je ne sais pas par où commencer!

La distance du départ Lat / Lon serait de 10 km ou moins.

Serait-il possible pour quelqu'un de me donner quelques conseils / exemple sur la façon de procéder

nmtoken
la source
Pour les cercles qui ne couvrent aucun des deux pôles, une réponse détaillée est donnée à gis.stackexchange.com/questions/19221/… . Mais ce n'est pas toute l'histoire, comme le suggèrent les réponses actuelles: vous pouvez faire des compromis entre la complexité de la vitesse et la précision du programme. Notez également qu'il existe un problème de "bouclage" dans la spécification des boîtes englobantes lorsque vous travaillez en lat-lon (les difficultés se produisent au méridien de + -180 degrés). Pour une solution à cela, voir gis.stackexchange.com/questions/17788/… .
whuber
Avez-vous vraiment besoin d'une boîte, ou 4 points près d'un point donné seraient-ils suffisants? Étant donné un point p, trouvez 4 points d distance aux directions NE, SW, SE et NW de p.
Kirk Kuykendall
@Kirk - Si vous avez les coordonnées des 4 points, alors vous avez la case ...
martinstoeckli
@martinstoeckli à droite, j'espérais simplement simplifier le problème en n'ayant pas à visualiser à quoi ressemble une boîte projetée sur une sphère. Notez également que le problème pourrait être généralisé pour indiquer clairement que les côtés de la boîte ne doivent pas nécessairement tomber sur la même latitude / longitude (une boîte pivotée en d'autres termes).
Kirk Kuykendall
@Kirk - Eh bien, si vous en avez besoin exactement, vous avez bien sûr raison. Je pense que la boîte n'est utile que pour trouver rapidement les candidats possibles. Pour vérifier si deux points sont à une certaine distance (cercle), la formule haversine plus complexe peut être utilisée.
martinstoeckli

Réponses:

15

WGS-quoi? WGS-84? Selon la précision dont vous avez besoin, vous devrez peut-être en savoir beaucoup plus d'informations - je suppose que c'est la raison pour laquelle vous avez été rejeté, bien que personne n'ait pris la peine de laisser un commentaire expliquant pourquoi.

Voici deux façons:

Imprécis, mais probablement «assez bon»

Un degré de latitude est d'environ 10001,965729 / 90 kilomètres (distance de l'équateur au pôle, divisée par quatre-vingt-dix degrés) ou 111,113 kilomètres, en utilisant la donnée WGS-84. C'est une approximation à cause de la forme de la terre et parce que les distances changent à mesure que vous vous approchez des pôles (une raison d'utiliser la latitude, pas la longitude - finalement la distance d'un degré de longitude est nulle!) La terre n'est pas non plus parfaite sphère. Ce sont deux raisons d'utiliser une approche plus complexe basée sur la projection et les données, dans ma deuxième réponse.

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

Cela utilise des degrés décimaux, pas des degrés / minutes / secondes.

Ainsi, votre boîte englobante sera votre point, plus et moins 0,08999 degrés. Vous pouvez également utiliser ce nombre comme un rayon, vous donnant un cercle de délimitation .

Toute personne SIG lisant ceci frémira. Ce sera surtout précis, selon l'endroit où vous vous trouvez dans le monde. Pour un rayon de 10 km, ça devrait aller.

Beaucoup plus précis, mais plus de code

Utilisez une bibliothèque de projection et spécifiez votre datum, etc. Je recommande Proj4; il est largement utilisé, donc Google renvoie des tas de résultats pour les questions à ce sujet, et il existe des wrappers Delphi . Si vous avez du mal à l'utiliser, postez une autre question ici sur SO - c'est hors de portée pour celle-ci. Le site Web de Proj4 contient des exemples d'utilisation des API de base, et bien que ceux-ci soient en C, il devrait être assez facilement traduisible. Leur référence API est le meilleur endroit pour commencer, suivie de la FAQ .

J'utiliserais WGS-84 comme référence de base (représentation de la terre) à moins que vous ne connaissiez une donnée spécifique que vous souhaitez utiliser, ou qui a été utilisée pour créer vos coordonnées. Il est couramment utilisé et assez précis.

Si votre position provient de Google Maps (par exemple), spécifiez une projection Mercator. Vous pouvez utiliser une autre projection ou utiliser, par exemple, les coordonnées UTMau lieu de la latitude et de la longitude, selon la source de vos données et si vous souhaitez une grande précision pour une petite zone locale. (L'UTM a plusieurs zones, qui modifient toutes la distorsion de sorte que dans cette zone, elle est très précise; si vous utilisez une zone pour des coordonnées à l'extérieur, la distorsion augmentera considérablement à mesure que vous vous éloignez. Si vous regardez la terre entière projetée à partir d'une seule peut être méconnaissable. Mais dans une zone, les traductions UTM seront à peu près aussi bonnes que possible. Les coordonnées sont généralement spécifiées en mètres, pas en degrés, donc cela peut être plus utile pour vous, étant donné que vous avez besoin de 10 km 10 km est facilement dans une seule zone, il vous suffit de choisir la zone appropriée en fonction de votre coordonnée centrale. Le seul point délicat est lorsque vous approchez d'une frontière: c'est une situation courante, et c'est bien, soyez justecohérent dans la façon dont vous choisissez celui que vous utilisez . Proj4 vous permettra également de traduire des projections, afin que vous puissiez passer de votre Mercator WGS-84 lat / long à une zone UTM n , par exemple, ou vers et depuis deux zones UTM.)

David
la source
2
Pour l'endroit où nous vivons, un arpenteur m'a dit une fois qu'il utilise 1 degré équivaut environ à 108 km pour ses calculs mentaux. Mentalement, 10 km correspondent à environ 0,1 degré. Comme ce sont des approximations approximatives, il est préférable de les traiter avec précision à 1 chiffre significatif (2 ou 3 au plus) plutôt qu'à 0,089982311915998, car cela implique un niveau de précision.
Stephen Quan
1
Ce n'est vraiment pas difficile de calculer les degrés plus précis, en tenant compte de la latitude. Puisque l'ordinateur fait le calcul, rien n'est gagné avec une approximation (voir la première fonction dans mon exemple).
martinstoeckli
3

En supposant que vous souhaitiez effectuer une requête dans une base de données, vous souhaiterez probablement effectuer une recherche rapide (inexacte), puis calculer exactement la distance pour les endroits résultants. Est-ce votre scénario?

La fonction suivante (en PHP, désolé) calculera grossièrement les différences de latitude et de longitude. Ces différences dépendent de la latitude de votre point de recherche. Utilisez-les (avec une petite tolérance) pour effectuer une recherche rapide dans la base de données. La boîte peut être calculée simplement avec latitude + -deltaLatitude et longitude + -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);
}

Avec la formule haversine , vous pouvez calculer les distances sur la sphère. Utilisez-le pour chacun des endroits trouvés, pour obtenir la distance "exacte". De cette façon, vous pouvez tester si les deux endroits sont dans un certain rayon (un cercle au lieu de la boîte).

/**
 * 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
la source
3

Pour tester si un lat / lon se trouve à l'intérieur ou à l'extérieur d'un cercle de délimitation, vous devez calculer la distance entre votre lat / lon de référence et le point lat / lon que vous souhaitez tester. Étant donné que votre distance est de 10 km ou moins, j'essayerais d'utiliser l'approximation équirectangulaire pour obtenir la distance plutôt que Haversine en raison de la simplicité. Pour obtenir la distance en km:

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

Remarque importante: les lat / lon dans ces formules sont en radians et non en degrés. La valeur typique d'EarthRadius est de 6371 km, ce qui renvoie la distance en unités de km. Maintenant, c'est un test simple si votre distance est à l'intérieur ou à l'extérieur du cercle. Si un cercle de délimitation fonctionne, j'irais avec ça.

Pour un rectangle englobant, je suppose que vous voulez que le rectangle soit défini en étant parallèle à l'équateur. Je calculerais ensuite les coins de la boîte englobante en utilisant des calculs de distance / relèvement (les relèvements étant de 45 degrés, 135 degrés, 225 degrés et 315 degrés). À partir de là, je suppose que vous n'êtes pas autour des pôles et utilisez un point dans le test de polygone.

TreyA
la source
2

Ci-dessous se trouve le code T-SQL que j'utilise pour construire la boîte englobante dans SQL-Server 2012. Dans mon cas, j'obtiens des valeurs décimales pour Lat, Long. J'utilise cela pour limiter rapidement le nombre de lignes avant d'utiliser la STDistancefonction SQL pour vérifier que les résultats sont réellement à une distance particulière. Les fonctions de géographie sont très coûteuses dans SQL Server, donc en construisant un cadre de délimitation, je suis en mesure de réduire considérablement le nombre de fois où il doit être exécuté.

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
la source