1 km circonda punti lat-long in molti punti del mondo


11

Ho centinaia di punti lat-long sparsi in tutto il mondo e devo creare poligoni circolari attorno a ciascuno di essi, con un raggio esatto di 1000 metri. Capisco che i punti devono prima essere proiettati da gradi (lat long) a qualcosa con unità di misura, ma come è possibile farlo senza cercare e definire manualmente le zone UTM per ciascun punto?

Ecco una meraviglia per il primo punto in Finlandia.

library(sp)
library(rgdal)
library(rgeos)
the.points.latlong <- data.frame(
  Country=c("Finland", "Canada", "Tanzania", "Bolivia", "France"),
  lat=c(63.293001, 54.239631, -2.855123, -13.795272, 48.603949),
  long=c(27.472918, -90.476303, 34.679950, -65.691146, 4.533465))
the.points.sp <- SpatialPointsDataFrame(the.points.latlong[, c("long", "lat")], data.frame(ID=seq(1:nrow(the.points.latlong))), proj4string=CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))

the.points.projected <- spTransform(the.points.sp[1, ], CRS( "+init=epsg:32635" ))  # Only first point (Finland)
the.circles.projected <- gBuffer(the.points.projected, width=1000, byid=TRUE)
plot(the.circles.projected)
points(the.points.projected)

the.circles.sp <- spTransform(the.circles.projected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))

Ma con il secondo punto (Canada) non funziona (perché zona UTM errata).

the.points.projected <- spTransform(the.points.sp[2, ], CRS( "+init=epsg:32635" ))

Come è possibile farlo senza ottenere e specificare manualmente il punto della zona UTM per punto? Non ho più informazioni per punto di lat long.

Aggiornare:

Usando e combinando le grandi risposte di AndreJ e Mike T, ecco il codice sia per le versioni che per i grafici. Sono diversi al 4 ° decimale o giù di lì, ma entrambe le risposte sono molto buone!

gnomic.buffer <- function(p, r) {
  stopifnot(length(p) == 1)
  gnom <- sprintf("+proj=gnom +lat_0=%s +lon_0=%s +x_0=0 +y_0=0",
                  p@coords[[2]], p@coords[[1]])
  projected <- spTransform(p, CRS(gnom))
  buffered <- gBuffer(projected, width=r, byid=TRUE)
  spTransform(buffered, p@proj4string)
}

custom.buffer <- function(p, r) {
  stopifnot(length(p) == 1)
  cust <- sprintf("+proj=tmerc +lat_0=%s +lon_0=%s +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", 
                  p@coords[[2]], p@coords[[1]])
  projected <- spTransform(p, CRS(cust))
  buffered <- gBuffer(projected, width=r, byid=TRUE)
  spTransform(buffered, p@proj4string)
}

test.1 <- gnomic.buffer(the.points.sp[2,], 1000)
test.2 <- custom.buffer(the.points.sp[2,], 1000)

library(ggplot2)
test.1.f <- fortify(test.1)
test.2.f <- fortify(test.2)
test.1.f$transf <- "gnomic"
test.2.f$transf <- "custom"
test.3.f <- rbind(test.1.f, test.2.f)

p <- ggplot(test.3.f, aes(x=long, y=lat, group=transf))
p <- p + geom_path()
p <- p + facet_wrap(~transf)
p

(Non sono sicuro di come ottenere la trama nell'aggiornamento).


1
Una possibile soluzione alla parte di ricerca manuale: cosa succede se si ottiene una griglia della zona UTM e la intersecano con i punti, in modo da aggiungere la zona appropriata come attributo? L'attributo può essere il nome della zona o il codice EPSG, ma qualcosa che può essere inserito come variabile per selezionare automaticamente il CRS giusto per ciascun punto.
Chris W,

1
Ho un problema con "esattamente 1000m" e la frase "poligoni circolari". I tuoi poligoni circolari hanno bisogno di segmenti infiniti per essere esattamente 1000m e la conversione in UTM (o in qualsiasi altro sistema planare) introdurrà ancora più errori. Fare attenzione con l'uso di "esatto".
Spacedman

Sì, non avrei dovuto esprimerlo diversamente. Intendevo dire che 1100m o 900m sarebbero troppo spenti e che circa 20 segmenti sul cerchio sono ok.
Chris,

Risposte:


9

Simile a @AndreJ, ma uso una proiezione gnomica dinamica , intendo una proiezione equidistante azimutale dinamica per una precisione ancora maggiore. Una proiezione AEQ centrata su ciascun punto proietterà distanze uguali in tutte le direzioni, come un cerchio tamponato. (Una proiezione di Mercatore presenterà alcune distorsioni nelle direzioni nord e est, poiché si avvolge attorno al lato di un cilindro.)

Quindi per il tuo primo punto in Finlandia, la stringa PROJ.4 sarà simile a questa:

+proj=aeqd +lat_0=63.293001 +lon_0=27.472918 +x_0=0 +y_0=0

Quindi puoi fare una funzione R per fare questa proiezione dinamica:

aeqd.buffer <- function(p, r)
{
    stopifnot(length(p) == 1)
    aeqd <- sprintf("+proj=aeqd +lat_0=%s +lon_0=%s +x_0=0 +y_0=0",
                    p@coords[[2]], p@coords[[1]])
    projected <- spTransform(p, CRS(aeqd))
    buffered <- gBuffer(projected, width=r, byid=TRUE)
    spTransform(buffered, p@proj4string)
}

Quindi fai qualcosa del genere per il Canada (articolo 2):

aeqd.buffer(the.points.sp[2,], 1000)

1
Dalla pagina di Wikipedia: "Nessuna distorsione si verifica nel punto tangente, ma la distorsione aumenta rapidamente lontano da esso". Hai effettuato un calcolo di offset campione? Forse en.wikipedia.org/wiki/Azimuthal_equidistant_projection è più adatto.
AndreJ,

2
Qualsiasi proiezione che abbia la scala corretta all'origine del cerchio ed è conforme lì andrà bene, semplicemente perché 1000m è così piccolo. Per raggi molto più grandi, tuttavia, una proiezione gnomonica sarà terribile. Probabilmente intendevi stipulare una proiezione equidistante .
whuber

2
Ottimo feedback, una proiezione AEQ sta ovviamente andando molto meglio per questa tecnica, quindi ho cambiato gnomic. L'AEQP resisterà anche per distanze molto maggiori, come nella gamma di oltre 10.000 km.
Mike T,

1
Forse sto fraintendendo il codice, ma devi solo costruire il poligono buffer una volta, in qualsiasi proiezione AEQD (il centro è sempre zero, il coord min è sempre -1k, il max è sempre + 1k. Quindi riproiettalo su lat / lon usando un AEQD centrato su ciascuno dei punti di cui hai bisogno per ottenere i valori lat / lon ...
mkennedy,

2
@mkennedy hai ragione. projectedè infatti sempre a (0, 0), e bufferedpresenta i punti di ± 1000 m x - e y -directions. Se fosse fondamentale ottimizzarlo, trasforma una semplice versione cartesiana del buffer da AEQD dinamico a WGS84.
Mike T,

4

Invece di cercare la giusta zona UTM, è possibile creare una proiezione trasversale personalizzata per ogni punto

+proj=tmerc +lat_0=.... +lon_0=... +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs

Disegna il cerchio in quella proiezione. Le coordinate del vertice del cerchio proiettato saranno sempre le stesse, quindi è necessario crearle una sola volta. Per quanto segue, basta assegnare loro il nuovo CRS personalizzato.

Riproiettare il cerchio in EPSG: 4326 per un ulteriore utilizzo.

Nel raggio di 1000 m, il cerchio sarà quasi esatto. In caso contrario (o per cerchi più grandi), utilizzare aeqdinvece di tmerc.


0

Che cosa succede se segui l'approccio di creare un 1000 metri in EPSG: 4326 attorno a ciascuno dei tuoi punti. Quindi convertire l'EPSG: 4326 nell'altro sistema di coordinate? Il vantaggio di proiettare il punto è che non devi preoccuparti della curvatura della terra con EPSG: 4326.


1
Come esattamente creereste buffer da 1000 m da EPSG: 4326, che ha unità di lunghezza in gradi?
Mike T,

Un modo in cui mi avvicinerei a questo è quello di creare un buffer di 1000 metri in EPSG: 32635. Converti quello in EPSG: 4326 e ora avresti il ​​numero che ti serve.
Greg,

1
Questo è lo stesso approccio descritto nella domanda, insieme ai limiti di questa tecnica.
Mike T,
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.