Come calcolo il rettangolo di selezione per una distanza e una latitudine / longitudine indicate


13

Devo essere in grado di calcolare un rettangolo di selezione o un cerchio per una determinata latitudine WGS84 e longitudine WGS84 e distanza, ma non ho idea da dove cominciare!

La distanza dall'inizio Lat / Lon sarebbe di 10 km o meno.

Sarebbe possibile per qualcuno darmi alcuni suggerimenti / Esempio su come farlo


Per le cerchie che non coprono nessuno dei poli, una risposta dettagliata è disponibile su gis.stackexchange.com/questions/19221/… . Ma questa non è la storia completa, come suggeriscono le risposte attuali: è possibile effettuare compromessi sulla complessità del programma di precisione e velocità. Si noti inoltre che esiste un problema "avvolgente" nello specificare i riquadri di delimitazione quando si lavora in lat-lon (le difficoltà si verificano al meridiano + -180 gradi). Per una soluzione a questo, consultare gis.stackexchange.com/questions/17788/… .
whuber

Hai davvero bisogno di una scatola o sarebbero sufficienti 4 punti vicino a un dato punto? Dato un punto p, trova 4 punti d di distanza nelle direzioni NE, SW, SE e NW da p.
Kirk Kuykendall,

@Kirk - Se hai le coordinate dei 4 punti, allora hai la casella ...
martinstoeckli

@martinstoeckli giusto, speravo solo di semplificare il problema non dovendo visualizzare l'aspetto di una scatola proiettata su una sfera. Si noti inoltre che il problema potrebbe essere generalizzato per chiarire che i lati della scatola non devono cadere sulla stessa latitudine / longitudine (una scatola ruotata in altre parole).
Kirk Kuykendall,

@Kirk - Ahh bene, se ne hai bisogno esattamente, allora hai ragione, ovviamente. Penso che la scatola sia utile solo per trovare rapidamente i possibili candidati. Per verificare se due punti si trovano entro una certa distanza (cerchio), è possibile utilizzare la formula di haversine più complessa.
martinstoeckli,

Risposte:


15

WGS-cosa? WGS-84? A seconda dell'accuratezza di cui hai bisogno, potresti aver bisogno di sapere molte più informazioni - suppongo che sia per questo che sei stato votato, anche se nessuno si è preso la briga di lasciare un commento dicendo perché.

Ecco due modi:

Inesatto, ma probabilmente "abbastanza buono"

Un grado di latitudine è di circa 10001.965729 / 90 chilometri (distanza dall'equatore al polo, diviso per novanta gradi) o 111.113 chilometri, usando il dato WGS-84. Questa è un'approssimazione a causa della forma della terra e perché le distanze cambiano mentre ti avvicini ai poli (un motivo per usare la latitudine, non la longitudine - alla fine la distanza di un grado di longitudine è zero!) Anche la terra non è perfetta sfera. Entrambi questi sono motivi per utilizzare un approccio più complesso basato sulla proiezione e sul dato, nella mia seconda risposta.

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

Questo utilizza gradi decimali, non gradi / minuti / secondi.

Quindi, il rettangolo di selezione sarà il tuo punto, più e meno 0,08999 gradi. In alternativa puoi usare questo numero come raggio, dandoti un cerchio di delimitazione .

Qualsiasi persona GIS che legge questo rabbrividirà. Sarà per lo più accurato, tuttavia, a seconda di dove ti trovi nel mondo. Per un raggio di 10 km dovrebbe andare bene.

Molto più preciso, ma più codice

Utilizzare una libreria di proiezione e specificare il proprio dato, ecc. Raccomando Proj4; è ampiamente utilizzato, quindi Google restituisce un sacco di risultati per domande al riguardo e ci sono involucri Delphi . Se hai problemi ad usarlo, pubblica un'altra domanda qui su SO - è fuori portata per questo. Il sito Web Proj4 contiene esempi che utilizzano le API di base e sebbene siano in C, dovrebbe essere facilmente traducibile. Il loro riferimento API è il punto di partenza migliore, seguito dalle FAQ .

Userei WGS-84 come dato di base (rappresentazione della terra) a meno che tu non ne conosca uno specifico che desideri utilizzare o che sia stato utilizzato per creare le tue coordinate. È comunemente usato e abbastanza preciso.

Se la tua posizione proviene da Google Maps (ad esempio), specifica una proiezione di Mercatore. Potresti voler usare un'altra proiezione o usare, diciamo, coordinate UTManziché latitudine e longitudine, a seconda della fonte dei dati e se si desidera un'elevata precisione per una piccola area locale. (UTM ha più zone, ognuna delle quali cambia la distorsione in modo che all'interno di quella zona sia estremamente precisa; se usi una zona per coordinate al di fuori di essa, la distorsione aumenterà notevolmente man mano che ti allontani. Se vedi l'intera terra proiettata da una zona, potrebbe essere irriconoscibile, ma all'interno di una zona, le traduzioni UTM saranno le migliori possibili. Le coordinate sono generalmente specificate in metri, non in gradi, quindi potrebbe essere più utile per te, dato che hai bisogno di 10 km raggio 10 km è facilmente all'interno di una singola zona, devi solo scegliere la zona appropriata in base alla tua coordinata centrale. L'unica cosa difficile è quando ti avvicini a un confine: è una situazione comune, e va bene, bastacoerente nel modo in cui scegli quale utilizzare . Proj4 ti consente anche di tradurre le proiezioni, in modo da poter passare dal tuo Mercator WGS-84 lat / long a una zona UTM n , ad esempio, o da e verso due zone UTM.)


2
Per dove viviamo, un geometra una volta mi disse che usa 1 grado approssimativamente equivale a 108 km per i suoi calcoli mentali. Mentalmente 10 km sono circa 0,1 gradi. Poiché si tratta di approssimazioni approssimative, è meglio trattarle con precisione fino a 1 cifra significativa (2 o 3 al massimo) anziché 0,089982311915998 poiché ciò implica un livello di precisione.
Stephen Quan,

1
Non è davvero difficile calcolare i gradi più precisi, tenendo conto della latitudine. Poiché il computer esegue il calcolo, non si ottiene nulla con un'approssimazione (vedere la prima funzione nel mio esempio).
martinstoeckli,

3

Supponendo di voler effettuare una query in un database, è probabile che si desideri effettuare una ricerca rapida (inaccurata) e successivamente calcolare esattamente la distanza per i luoghi risultanti. È quello il tuo scenario?

La seguente funzione (in PHP, scusa) calcolerà approssimativamente le differenze di latitudine e longitudine. Queste differenze dipendono dalla latitudine del punto di ricerca. Usali (con una piccola tolleranza) per effettuare una ricerca veloce nel database. La casella può essere calcolata semplicemente con latitudine + -deltaLatitudine e longitudine + -deltaLongitudine.

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 formula haversine , puoi calcolare le distanze sulla sfera. Usalo per ciascuno dei luoghi trovati, per ottenere la distanza "esatta". In questo modo è possibile verificare se i due punti si trovano entro un certo raggio (un cerchio anziché la casella).

/**
 * 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;
}

3

Per verificare se un lat / lon si trova all'interno o all'esterno di un cerchio di delimitazione, è necessario calcolare la distanza dal lat / lon di riferimento al punto lat / lon che si desidera verificare. Dato che la distanza è di 10 km o meno, proverei a usare l'approssimazione equirettangolare per ottenere la distanza anziché Haversine per semplicità. Per ottenere la distanza in km:

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

Nota importante: lat / lon in queste formule sono in radianti e non in gradi. Il valore tipico di EarthRadius è 6371 km che restituirà la distanza in unità di km. Ora è un semplice test se la distanza è all'interno o all'esterno del cerchio. Se un cerchio di delimitazione funziona, vorrei andare con quello.

Per un rettangolo di delimitazione, suppongo che tu voglia definire il rettangolo essendo parallelo all'equatore. Vorrei quindi calcolare gli angoli del rettangolo di selezione utilizzando i calcoli di portata / cuscinetto (i cuscinetti sono 45 gradi, 135 gradi, 225 gradi e 315 gradi). Da lì, suppongo che tu non sia nei pressi dei poli e utilizzerei un punto nel test poligonale.


2

Di seguito è riportato il codice T-SQL che utilizzo per la creazione del riquadro di selezione in SQL-Server 2012. Nel mio caso ottengo valori decimali per Lat, Long. Lo uso per limitare rapidamente il numero di righe prima di utilizzare la STDistancefunzione SQL per verificare che i risultati siano effettivamente entro una determinata distanza. Le funzioni geografiche sono molto costose in SQL Server, quindi costruendo la finestra di delimitazione sono in grado di ridurre notevolmente il numero di volte che deve essere eseguito.

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 )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.