Come posso raggruppare punti vicini con posizioni GPS?


10

Sono una persona IT quindi non so troppo sulle proiezioni e così via, spero che tu mi possa aiutare.

Ho creato un'applicazione per Android che raccoglie una posizione GPS, quindi ho la latitudine e la longitudine in un determinato momento. Voglio salvare insieme quegli elementi vicini l'uno all'altro, in gruppi di aree del terreno della stessa dimensione fisica; il problema è che non conosco in anticipo i punti e che possono provenire da qualsiasi posizione nel mondo .

La mia prima idea (per spiegare un po 'di più il problema) era usare i decimali della latitudine e della longitudine per il raggruppamento; ad esempio, un gruppo saranno le posizioni con latitudine compresa tra 35.123 e 35.124 e la longitudine tra 60.101 e 60.102. Quindi se ottengo una posizione come lat = 35.1235647 e lon = 60.1012254598, questo punto andrà a quel gruppo.

Questa soluzione sarebbe OK per una rappresentazione cartesiana in 2D, poiché avrei aree di 0,001 unità di larghezza e altezza; tuttavia, poiché la dimensione di 1 grado di longitudine è diversa a diverse latitudini, non posso usare questo approccio.

Qualche idea?


Perché non è possibile memorizzare la posizione come in, quindi eseguire l'elaborazione in un secondo momento? Anche all'equatore, 1 grado di longitudine è di circa 111 km, quindi 0,001 gradi saranno poco più di 1 Km. Vuoi davvero i tuoi bidoni così grandi?
Devdatta Tengshe

Il grado 0,001 era solo un esempio della mia idea. Ovviamente dovrò adattarlo alle esigenze. Non posso fare un post processing in quanto è in programma di essere un'applicazione in tempo reale, e non posso dire ai miei utenti "resisti fino a domani, perché devo raggruppare i punti" Grazie comunque per le idee;)
Kuu

Risposte:


6

Un modo rapido e sporco utilizza una suddivisione sferica ricorsiva . A partire da una triangolazione della superficie terrestre, dividere in modo ricorsivo ogni triangolo da un vertice al centro del suo lato più lungo. (Idealmente divideresti il ​​triangolo in due parti di uguale diametro o parti di uguale area, ma poiché queste comportano un calcolo complicato, ho appena diviso i lati esattamente a metà: questo fa sì che i vari triangoli alla fine varino un po 'di dimensioni, ma che non sembra fondamentale per questa applicazione.)

Naturalmente manterrai questa suddivisione in una struttura di dati che consente di identificare rapidamente il triangolo in cui si trova qualsiasi punto arbitrario. Un albero binario (basato sulle chiamate ricorsive) funziona bene: ogni volta che un triangolo viene diviso, l'albero viene diviso nel nodo di quel triangolo. I dati relativi al piano di divisione vengono conservati, in modo da poter determinare rapidamente su quale lato del piano si trova qualsiasi punto arbitrario: ciò determinerà se viaggiare a sinistra o a destra lungo l'albero.

(Ho detto "piano" di divisione? Sì - se si modella la superficie terrestre come una sfera e si usano coordinate geocentriche (x, y, z), la maggior parte dei nostri calcoli avviene in tre dimensioni, dove i lati dei triangoli sono pezzi di intersezioni della sfera con i piani attraverso la sua origine. Questo rende i calcoli facili e veloci.)


Illustrerò mostrando la procedura su un ottante di una sfera; gli altri sette ottanti vengono elaborati allo stesso modo. Tale ottante è un triangolo 90-90-90. Nella mia grafica disegnerò triangoli euclidei che attraversano gli stessi angoli: non sembrano molto belli fino a quando non diventano piccoli, ma possono essere disegnati facilmente e rapidamente. Ecco il triangolo euclideo corrispondente all'ottante: è l'inizio della procedura.

Figura 1

Poiché tutti i lati hanno la stessa lunghezza, uno viene scelto casualmente come il "più lungo" e suddiviso:

figura 2

Ripeti l'operazione per ciascuno dei nuovi triangoli:

Figura 3

Dopo n passaggi avremo 2 ^ n triangoli. Ecco la situazione dopo 10 passaggi, mostrando 1024 triangoli nell'ottante (e 8192 sulla sfera in generale):

Figura 4

Come ulteriore illustrazione, ho generato un punto casuale all'interno di questo ottante e ho viaggiato l'albero di suddivisione fino a quando il lato più lungo del triangolo ha raggiunto meno di 0,05 radianti. I triangoli (cartesiani) sono mostrati con la punta della sonda in rosso.

Figura 5

Per inciso, per restringere la posizione di un punto a un grado di latitudine (circa), noterai che questo è circa 1/60 di radiante e quindi copre circa (1/60) ^ 2 / (Pi / 2) = 1/6000 del superficie totale. Poiché ogni suddivisione dimezza approssimativamente la dimensione del triangolo, circa 13-14 suddivisioni dell'ottante faranno il trucco. Questo non è molto calcolo - come vedremo di seguito - rendendo efficiente non memorizzare affatto l'albero, ma eseguire la suddivisione al volo. All'inizio noterai in quale ottante si trova il punto - che è determinato dai segni delle sue tre coordinate, che possono essere registrate come un numero binario di tre cifre - e ad ogni passo vuoi ricordare se il punto sta a sinistra (0) o destra (1) del triangolo. Questo dà un altro numero binario di 14 cifre. È possibile utilizzare questi codici per raggruppare punti arbitrari.

(Generalmente, quando due codici sono vicini come numeri binari effettivi, i punti corrispondenti sono vicini; tuttavia, i punti possono ancora essere vicini e avere codici notevolmente diversi. Considerare due punti distanti un metro l'uno dall'altro, ad esempio: i loro codici devono differire anche prima del punto binario, perché si trovano in diversi ottanti. Questo tipo di cose è inevitabile con qualsiasi partizionamento fisso dello spazio.)


Ho usato Mathematica 8 per implementare questo: potresti prenderlo così com'è o come pseudocodice per un'implementazione nel tuo ambiente di programmazione preferito.

Determina quale lato del piano 0-ab punto p giace:

side[p_, {a_, b_}] := If[Det[{p, a, b}] >=  0, left, right];

Perfeziona il triangolo abc in base al punto p.

refine[p_, {a_, b_, c_}] := Block[{sides, x, y, z, m},
  sides = Norm /@ {b - c, c - a, a - b} // N;
  {x, y, z} = RotateLeft[{a, b, c}, First[Position[sides, Max[sides]]] - 1];
  m = Normalize[Mean[{y, z}]];
  If[side[p, {x, m}] === right, {y, m, x}, {x, m, z}] 
  ]

L'ultima figura è stata disegnata visualizzando l'ottante e, soprattutto, rendendo il seguente elenco come un insieme di poligoni:

p = Normalize@RandomReal[NormalDistribution[0, 1], 3]        (* Random point *)
{a, b, c} = IdentityMatrix[3] . DiagonalMatrix[Sign[p]] // N (* First octant *)
NestWhileList[refine[p, #] &, {a, b, c}, Norm[#[[1]] - #[[2]]] >= 0.05 &, 1, 16]

NestWhileListapplica ripetutamente un'operazione ( refine) mentre si verifica una condizione (il triangolo è grande) o fino al raggiungimento di un conteggio massimo di operazioni (16).

Per visualizzare la triangolazione completa dell'ottante, ho iniziato con il primo ottante e ho ripetuto la raffinatezza dieci volte. Questo inizia con una leggera modifica di refine:

split[{a_, b_, c_}] := Module[{sides, x, y, z, m},
  sides = Norm /@ {b - c, c - a, a - b} // N;
  {x, y, z} = RotateLeft[{a, b, c}, First[Position[sides, Max[sides]]] - 1];
  m = Normalize[Mean[{y, z}]];
  {{y, m, x}, {x, m, z}}
  ]

La differenza è che splitrestituisce entrambe le metà del suo triangolo di input piuttosto che quello in cui si trova un dato punto. La triangolazione completa si ottiene ripetendo questo:

triangles = NestList[Flatten[split /@ #, 1] &, {IdentityMatrix[3] // N}, 10];

Per verificare, ho calcolato una misura delle dimensioni di ogni triangolo e ho esaminato l'intervallo. (Questa "dimensione" è proporzionale alla figura a forma di piramide sottesa da ciascun triangolo e dal centro della sfera; per piccoli triangoli come questi, questa dimensione è essenzialmente proporzionale alla sua area sferica.)

Through[{Min, Max}[Map[Round[Det[#], 0.00001] &, triangles[[10]] // N, {1}]]]

{0,00523, 0,00739}

Pertanto le dimensioni variano di circa il 25% verso l'alto o verso il basso dalla loro media: ciò sembra ragionevole per ottenere un modo approssimativamente uniforme di raggruppare i punti.

Scansionando questo codice, non noterai alcuna trigonometria : l'unico posto in cui sarà necessario, se non del tutto, sarà la conversione avanti e indietro tra coordinate sferiche e cartesiane. Inoltre, il codice non proietta la superficie terrestre su nessuna mappa, evitando così le distorsioni che ne conseguono. Altrimenti, usa solo la media ( Mean), il Teorema di Pitagora ( Norm) e un determinante 3 per 3 ( Det) per fare tutto il lavoro. (Ci sono alcuni semplici comandi di manipolazione dell'elenco come RotateLefte Flatten, anche, insieme a una ricerca del lato più lungo di ogni triangolo.)


1

Questo è difficile, poiché le proiezioni introducono distorsione quando si passa dal sistema di coordinate geografiche 3D WGS84 a una proiezione 2D piatta. Su scala globale, si è tenuti ad avere distorsioni da qualche parte nel sistema.

Penso che la tua scommessa migliore sia proiettare sulla proiezione di Universal Transverse Mercator . Per quanto ne so, questo è il più vicino possibile ad una proiezione globale con la minima distorsione.

Se è possibile allentare i requisiti che i gruppi devono essere definiti in aree della stessa identica dimensione, nonché i requisiti dell'elaborazione in tempo reale, esistono algoritmi di clustering come DBSCAN e una famiglia di derivati ​​che possono aiutare a produrre raggruppamenti.


1
UTM non è una "proiezione globale": la dimostrazione è che quasi ogni coppia di coordinate valide, come (500000, 5000000), corrisponde ad almeno 120 punti distinti e ampiamente separati nel sistema UTM. E, sfortunatamente, gli algoritmi di clustering non soddisfano le esigenze dell'OP di poter raggruppare i punti in tempo reale in base esclusivamente alla loro posizione (e non alla loro vicinanza ad altri punti).
whuber

@whuber re: "proiezione globale" - giusto. Ecco perché ho detto "il più vicino possibile ad una proiezione globale". Se conosci un sistema di proiezione migliore più appropriato, lascialo nei commenti e modificherò la mia risposta. Inoltre, OP non aveva requisiti in tempo reale nel post iniziale. Modificherò la mia risposta per tenerne conto.
Sean Barbeau,

Sean, (1) La mia soluzione al problema della proiezione globale non è quella di usarne una. Non esiste una proiezione globale senza singolarità. (2) Vero, il chiarimento in tempo reale è apparso in un commento. Il testo che segue "la mia prima idea" fa un buon lavoro, tuttavia, sottolineando che questo problema è quello di dividere la superficie terrestre piuttosto che raggruppare una serie di posizioni. Questo è il punto che stavo (non molto efficacemente) cercando di esprimere nel mio precedente commento a te.
whuber
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.