1 km kreisen an vielen Orten der Welt um Lat-Long-Punkte

11

Ich habe Hunderte von Lat-Long-Punkten auf der ganzen Welt verteilt und muss um jeden von ihnen Kreispolygone mit einem Radius von genau 1000 Metern erstellen. Ich verstehe, dass die Punkte zuerst von Grad (Lat lang) auf etwas mit Metereinheiten projiziert werden müssen, aber wie kann dies geschehen, ohne die UTM-Zonen für jeden Punkt manuell zu suchen und zu definieren?

Hier ist ein Mwe für den ersten Punkt in Finnland.

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"))

Aber mit dem zweiten Punkt (Kanada) funktioniert es nicht (weil falsche UTM-Zone).

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

Wie kann dies geschehen, ohne den UTM-Zonenpunkt pro Punkt manuell abzurufen und anzugeben? Ich habe nicht mehr Informationen pro Punkt als lat lang.

Aktualisieren:

Unter Verwendung und Kombination der großartigen Antworten von AndreJ und Mike T finden Sie hier den Code für beide Versionen und Diagramme. Sie unterscheiden sich auf der 4. Dezimalstelle oder so, aber beide sind sehr gute Antworten!

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

(Nicht sicher, wie der Plot in das Update aufgenommen werden soll).

Chris
quelle
1
Eine mögliche Lösung für den manuellen Suchteil: Was ist, wenn Sie ein UTM-Zonenraster erhalten und dieses mit Ihren Punkten schneiden, sodass Sie die entsprechende Zone als Attribut hinzufügen? Das Attribut kann entweder ein Zonenname oder ein EPSG-Code sein, aber etwas, das als Variable eingegeben werden kann, um automatisch das richtige CRS für jeden Punkt auszuwählen.
Chris W
1
Ich habe ein Problem mit "genau 1000m" und der Phrase "Kreis-Polygone". Ihre Kreispolygone benötigen unendliche Segmente, um genau 1000 m zu sein, und die Konvertierung in UTM (oder ein anderes planares System) führt zu noch mehr Fehlern. Seien Sie vorsichtig mit der Verwendung von "genau".
Spacedman
Ja, ich hätte es nicht anders ausdrücken sollen. Ich meinte, dass 1100 m oder 900 m zu weit entfernt wären und dass ungefähr 20 Segmente auf dem Kreis in Ordnung sind.
Chris

Antworten:

9

Ähnlich wie bei @AndreJ, aber mit einer dynamischen gnomischen Projektion meine ich eine dynamische azimutale äquidistante Projektion für noch mehr Genauigkeit. Eine auf jeden Punkt zentrierte AEQ-Projektion projiziert gleiche Abstände in alle Richtungen, z. B. einen gepufferten Kreis. (Eine Mercator-Projektion weist einige Verzerrungen in Nord- und Ostrichtung auf, da sie sich um die Seite eines Zylinders wickelt.)

Für Ihren ersten Punkt in Finnland sieht die PROJ.4-Zeichenfolge also folgendermaßen aus :

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

Sie können also eine R-Funktion erstellen, um diese dynamische Projektion zu erstellen:

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)
}

Dann machen Sie so etwas für Kanada (Punkt 2):

aeqd.buffer(the.points.sp[2,], 1000)
Mike T.
quelle
1
Auf der Wikipedia-Seite: "Am Tangentenpunkt tritt keine Verzerrung auf, aber die Verzerrung nimmt von dieser weg schnell zu." Haben Sie eine Sample-Offset-Berechnung durchgeführt? Vielleicht ist en.wikipedia.org/wiki/Azimuthal_equidistant_projection besser geeignet.
AndreJ
2
Jede Projektion, die am Ursprung des Kreises die richtige Skalierung hat und dort konform ist, reicht aus, einfach weil 1000 m so klein sind. Für viel größere Radien ist eine gnomonische Projektion jedoch schrecklich. Sie wollten wahrscheinlich eine äquidistante Projektion festlegen .
whuber
2
Tolles Feedback, eine AEQ-Projektion ist offensichtlich viel besser für diese Technik, also habe ich gnomic ausgeschaltet. AEQP hält auch viel größere Entfernungen aus, beispielsweise im Bereich von mehr als 10.000 km.
Mike T
1
Ich verstehe den Code möglicherweise falsch, aber Sie müssen das Pufferpolygon in jeder AEQD-Projektion nur einmal erstellen (Center ist immer Null, min coord ist immer -1k, max ist immer + 1k. Dann projizieren Sie es mit einem auf lat / lon AEQD konzentrierte sich auf jeden der Punkte, die Sie benötigen, um die Lat / Lon-Werte zu erhalten ...
mkennedy
2
@mkennedy du hast einen guten Punkt. projectedist in der Tat immer bei (0, 0) und bufferedhat die Punkte ± 1000 m in x- und y- Richtung. Wenn es wichtig war, dies zu optimieren, transformieren Sie einfach eine einfache kartesische Version des Puffers von der dynamischen AEQD in WGS84.
Mike T
4

Anstatt nach der richtigen UTM-Zone zu suchen, können Sie für jeden Punkt mit eine benutzerdefinierte transversale Mercator-Projektion erstellen

+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

Zeichnen Sie den Kreis in dieser Projektion. Die projizierten Kreisscheitelpunktkoordinaten sind immer gleich, sodass Sie sie nur einmal erstellen müssen. Weisen Sie ihnen im Folgenden einfach das neue benutzerdefinierte CRS zu.

Projizieren Sie den Kreis zur weiteren Verwendung auf EPSG: 4326.

Im Bereich von 1000 m ist der Kreis fast genau. Wenn nicht (oder für größere Kreise), verwenden Sie aeqdanstelle von tmerc.

AndreJ
quelle
0

Was ist, wenn Sie in EPSG: 4326 um jeden Ihrer Punkte einen 1000-Meter-Ansatz erstellen? Konvertieren Sie dann das EPSG: 4326 in Ihr anderes Koordinatensystem? Der Vorteil der Projektion des Punktes besteht darin, dass Sie sich mit EPSG: 4326 keine Gedanken über die Krümmung der Erde machen müssen.

Greg
quelle
1
Wie genau würden Sie 1000 m Puffer aus EPSG: 4326 erstellen, das Längeneinheiten in Grad hat?
Mike T
Eine Möglichkeit, dies zu erreichen, besteht darin, einen 1000-Meter-Puffer in EPSG: 32635 zu erstellen. Konvertieren Sie das in EPSG: 4326 und jetzt hätten Sie die Nummer, die Sie brauchen.
Greg
1
Dies ist der gleiche Ansatz, der in der Frage beschrieben wurde, zusammen mit den Einschränkungen dieser Technik.
Mike T