Calcolo della distanza tra un punto e una linea virtuale di due lat / lng


14

Fare riferimento all'esempio e all'immagine corrispondente.

Desidero di raggiungere i seguenti: fornire due riprese (lat / lng), che sono di seguito riportate come A e B . Da questo, verrebbe tracciata una linea virtuale e quindi la distanza tra questa linea e C verrebbe calcolata (in qualsiasi misura).

disegno

L'ho raggiunto attualmente nell'API v3 di Google Maps, ma vorrei poterlo eseguire anche dietro le quinte nella mia lingua prescelta. Eventuali suggerimenti / idee sarebbero molto apprezzati!


AB è una linea Great Circle ?
Kirk Kuykendall,

@Kirk, No, AB è solo una linea retta
Prigioniero

@Michael, questo è un punto interessante. Dovrò dare un'occhiata!
Prigioniero il

@Prisoner @Kirk Letteralmente, una "linea retta" passerà sotto la superficie terrestre. In generale, la sua proiezione radiale sulla superficie sarà effettivamente un segmento di un grande cerchio (usando un modello di terra sferica).
whuber

1
@Prisoner Questa è un'informazione extra estremamente utile! Sì hai ragione. Devi ancora compensare il fatto che l'uso di (lat, lon) distorce in modo differenziale le distanze est-ovest rispetto a nord-sud. Come consiglia @Jose, proiettare le coordinate. Questo può essere semplice come pre-moltiplicare le longitudini per il coseno della latitudine media e quindi fingere di essere su un piano euclideo.
whuber

Risposte:


6
def get_perp( X1, Y1, X2, Y2, X3, Y3):
    """************************************************************************************************ 
    Purpose - X1,Y1,X2,Y2 = Two points representing the ends of the line segment
              X3,Y3 = The offset point 
    'Returns - X4,Y4 = Returns the Point on the line perpendicular to the offset or None if no such
                        point exists
    '************************************************************************************************ """
    XX = X2 - X1 
    YY = Y2 - Y1 
    ShortestLength = ((XX * (X3 - X1)) + (YY * (Y3 - Y1))) / ((XX * XX) + (YY * YY)) 
    X4 = X1 + XX * ShortestLength 
    Y4 = Y1 + YY * ShortestLength
    if X4 < X2 and X4 > X1 and Y4 < Y2 and Y4 > Y1:
        return X4,Y4
    return None

La lunghezza più breve è la distanza richiesta, a meno che non mi sbagli?


Sì, sto cercando la distanza più breve da C al segmento di linea. È questo che calcola questa matematica?
Prigioniero

1
Ha funzionato davvero bene, ho superato i tre punti (A, B, C) nel seguente: i.imgur.com/bK9oB.jpg ed è tornato con il lat / lng di X. Ottimo lavoro!
Prigioniero

1
@Peloso, un'ultima cosa, come potrei fare per modificarlo per andare al punto più vicino (non solo la linea), quindi se avessi passato il punto di unire una linea, come potrei farlo per controllare la distanza dal punto?
Prigioniero

1
@Hairy Buon inizio, ma sembra che troppo spesso questo codice ritorni Nonequando esiste una soluzione legittima. Il problema è che l'ultimo condizionale assume X1 <X2 e Y1 <Y2, il che non può essere sempre garantito. È necessario un test migliore della via di mezzo.
whuber

1
@Hairy Sembra che questo scambio tra te e @prisoner sia stato produttivo. Vorrei sottolineare che non ho avuto nulla a che fare con (o addirittura alcun controllo) su eventuali cambiamenti di voto o punti che potrebbero essersi verificati e che il mio commento era inteso solo per aiutarti a migliorare la tua risposta.
whuber

11

Forse lo sto rendendo troppo complicato, ma quello che vuoi è la distanza da un punto a una linea. Questa è la distanza da un punto lungo AB che collega AB con C con una linea ortogonale ad AB. Questo vettore perpendicolare ad AB è dato da

v=[x2-x1, -(y2-y1)] # Point A is [x1,y1] Point B is [x2,y2]

(Ho usato le parentesi quadre per definire un vettore o una matrice a due elementi). La distanza tra C [xp, yp] e il punto A è

u=[x1-xp, y1-xp]

La distanza tra la linea e C è solo la proiezione di u su v. Se assumiamo mod (v) = 1 (semplicemente normalizzalo), allora

distance = u*v = abs( (x2-x1)*(y1-yp) - (x1-xp)*(y2-y1) )

L'unica complicazione è che probabilmente vuoi assicurarti che le tue coordinate non siano coppie lat / log WGS84, ma proiettate (o usa coordinate geodetiche). È possibile utilizzare OGR o Proj4 per questo.


3
+ diversi milioni di pseudo-punti per non usare le funzioni trigonometriche, tra l'altro. Troppe persone tirano fuori ArcTan quando dovrebbero guardare questo: en.wikipedia.org/wiki/Dot_product
Herb

@Jose, grazie per la risposta! Sto usando lat / long dall'API di google maps. La parte matematica è abbastanza nuova per me, quindi ci proverò e vedrò cosa posso inventare. Qualche consiglio con la matematica? Ad esempio [x2-x1, - (y2-y1)], in cosa si traduce?
Prigioniero il

Ho aggiunto una breve modifica per questo. Fondamentalmente, è una notazione di array, ma se memorizzi le tue coordinate nelle variabili x1, x2, y1, y2 e xp, yp, devi solo scrivere il lato destro dell'ultima equazione che ho fornito. Questo è praticamente un codice C, Java, JS, Python ecc. Valido :)
Jose

1
@Jose Stai calcolando la distanza da C alla linea AB. Sulla base della figura, credo che l'OP voglia la distanza da C al segmento di linea AB. Ciò richiede un lavoro extra per verificare se la proiezione di C sulla linea AB è compresa tra A e B o meno. In quest'ultimo caso, utilizzare la più corta delle due lunghezze CA e CB.
whuber

1
@Prisoner La differenza principale è che una linea si estende per sempre (è definita solo da un vettore di direzione e un punto, o da due punti), mentre un segmento tra A e B è il bit della linea infinita che va tra A e B (ha una lunghezza finita)
Jose

4

Essendo un po 'contrario anche a tutta questa matematica, ci arriverei da una prospettiva diversa. Vorrei renderlo una linea "reale", piuttosto che una linea virtuale, e quindi utilizzare gli strumenti esistenti.

Se A e B condividono un attributo, potresti collegarli tracciando una linea (Kosmo GIS ha uno strumento che creerà linee da punti, e credo che ci sia anche un plugin QGIS per questo). Una volta che hai le linee, una funzione 'vicino' sul livello del punto 'C' ti darà la distanza dalla linea. Lascia che il software gestisca la matematica per te!


Grazie per il commento, ma Hairy ha avuto la meglio su questo!
Prigioniero

1
(+1) Fai un punto eccellente. Gli algoritmi di geometria computazionale sono notoriamente difficili da ottenere completamente nella pratica (come possiamo vedere da tutto il codice offerto finora, che è utile e illustrativo ma non funziona ancora del tutto). L'uso di una procedura GIS di alto livello spesso è un buon modo per assicurarti di ottenere la risposta che ti aspetti e che sia corretta (a condizione che ti fidi del tuo GIS ;-).
whuber

1

Se stavi usando Java su Android, è solo una riga con la funzione di libreria

import static com.google.maps.android.PolyUtil.distanceToLine;

distanceToLine:

public static double distanceToLine(LatLng p, LatLng start,LatLng end)

Calcola la distanza sulla sfera tra il punto p e il segmento di linea dall'inizio alla fine.

Parametri: p - il punto da misurare

inizio - l'inizio del segmento di linea

end - la fine del segmento di linea

Restituisce: la distanza in metri (assumendo la terra sferica)

Aggiungi libreria al tuo

dependencies {
    compile 'com.google.maps.android:android-maps-utils:0.5+'
}
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.