1 km okrąża długie punkty w wielu miejscach na świecie

11

Mam setki lat-długich punktów rozmieszczonych na całym świecie i muszę tworzyć wielokąty kołowe wokół każdego z nich, o promieniu dokładnie 1000 metrów. Rozumiem, że punkty należy najpierw rzutować ze stopni (długości lat) na coś z jednostkami metrowymi, ale jak można to zrobić bez ręcznego wyszukiwania i definiowania stref UTM dla każdego punktu?

Oto mwe za pierwszy punkt w Finlandii.

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

Ale z drugim punktem (Kanada) to nie działa (ponieważ niewłaściwa strefa UTM).

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

Jak można to zrobić bez ręcznego uzyskiwania i określania punktu strefy UTM na punkt? Nie mam więcej informacji na punkt niż lat long.

Aktualizacja:

Używając i łącząc świetne odpowiedzi zarówno AndreJ, jak i Mike T, oto kod dla obu wersji i fabuł. Różnią się mniej więcej na czwartym miejscu po przecinku, ale obie bardzo dobre odpowiedzi!

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

(Nie jestem pewien, jak wprowadzić fabułę do aktualizacji).

Chris
źródło
1
Możliwe rozwiązanie części wyszukiwania ręcznego: Co zrobić, jeśli uzyskasz siatkę Strefy UTM i przetniesz ją swoimi punktami, aby dodać odpowiednią strefę jako atrybut? Atrybutem może być nazwa strefy lub kod EPSG, ale coś, co można podać jako zmienną, aby automatycznie wybrać odpowiedni CRS dla każdego punktu.
Chris W
1
Mam problem z „dokładnie 1000m” i zwrotem „wielokąty kołowe”. Twoje wielokąty kołowe potrzebują nieskończonych segmentów, aby miały dokładnie 1000 m, a konwersja do UTM (lub dowolnego innego układu płaskiego) spowoduje jeszcze więcej błędów. Zachowaj ostrożność przy użyciu „dokładnego”.
Spacedman,
Tak, nie powinienem był tego inaczej wyrażać. Miałem na myśli, że 1100 m lub 900 m byłoby zbyt daleko i że około 20 segmentów na kole jest w porządku.
Chris

Odpowiedzi:

9

Podobnie jak @AndreJ, ale używaj dynamicznej projekcji gnomicznej , mam na myśli dynamiczną, azymutalną równoodległą projekcję dla jeszcze większej dokładności. Projekcja AEQ wyśrodkowana na każdym punkcie spowoduje rzutowanie równych odległości we wszystkich kierunkach, takich jak buforowany okrąg. (Projekcja Mercatora będzie miała pewne zniekształcenia w kierunku północnym i wschodnim, ponieważ owija się wokół boku cylindra.)

Tak więc dla twojego pierwszego punktu w Finlandii łańcuch PROJ.4 będzie wyglądał następująco:

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

Możesz więc wykonać funkcję R, aby wykonać tę dynamiczną projekcję:

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

Następnie zrób coś takiego dla Kanady (pozycja 2):

aeqd.buffer(the.points.sp[2,], 1000)
Mike T.
źródło
1
Ze strony wikipedii: „W punkcie stycznym nie dochodzi do zniekształceń, ale dystorsja gwałtownie rośnie”. Czy wykonałeś przykładowe obliczenia przesunięcia? Może lepiej nadaje się en.wikipedia.org/wiki/Azimuthal_equidistant_projection .
AndreJ
2
Każda projekcja, która ma prawidłową skalę na początku okręgu i jest zgodna, będzie dobrze, po prostu dlatego, że 1000 m jest tak mała. Jednak dla znacznie większych promieni projekcja gnomoniczna będzie okropna. Prawdopodobnie chciałeś przewidzieć projekcję Equidistant .
whuber
2
Świetne informacje zwrotne, projekcja AEQ jest oczywiście znacznie lepsza dla tej techniki, więc zmieniłem gnomię. AEQP utrzyma się również na znacznie większych odległościach, na przykład w zasięgu ponad 10 000 km.
Mike T
1
Być może źle rozumiem kod, ale wystarczy zbudować wielokąt buforowy tylko raz, w dowolnej projekcji AEQD (środek jest zawsze równy zero, minimalna koordynacja to zawsze -1k, maksimum jest zawsze + 1k. Następnie odrzuć go do lat / lon za pomocą AEQD koncentruje się na każdym z punktów potrzebnych do uzyskania wartości lat / lon ...
mkennedy,
2
@mkennedy masz dobry punkt. projectedjest rzeczywiście zawsze w (0, 0) i bufferedma punkty ± 1000 mw kierunkach x i y . Jeśli zoptymalizowanie tego było kluczowe, wystarczy przekształcić prostą kartezjańską wersję bufora z dynamicznego AEQD do WGS84.
Mike T
4

Zamiast szukać właściwej strefy UTM, możesz utworzyć niestandardową projekcję poprzecznego mercatora dla każdego punktu, za pomocą którego

+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

Narysuj okrąg w tej projekcji. Współrzędne rzutowanego wierzchołka okręgu zawsze będą takie same, więc musisz je utworzyć tylko raz. W tym celu wystarczy przypisać im nowy niestandardowy CRS.

Ponownie skieruj okrąg na EPSG: 4326 do dalszego użycia.

W zakresie 1000 m okrąg będzie prawie dokładny. Jeśli nie (lub w przypadku większych kręgów), użyj aeqdzamiast tmerc.

AndreJ
źródło
0

Co się stanie, jeśli podejmiesz podejście polegające na utworzeniu 1000 metrów w EPSG: 4326 wokół każdego z punktów? Następnie przekonwertować EPSG: 4326 na inny układ współrzędnych? Zaletą rzutowania punktu jest to, że dzięki EPSG: 4326 nie musisz się martwić o krzywiznę ziemi.

Greg
źródło
1
Jak dokładnie stworzyłbyś bufory 1000 m z EPSG: 4326, który ma jednostki długości w stopniach?
Mike T
Jednym ze sposobów, w jaki mogę to podejść, jest utworzenie bufora 1000 metrów w EPSG: 32635. Konwertuj to na EPSG: 4326, a teraz będziesz mieć potrzebny numer.
Greg,
1
To samo podejście opisane w pytaniu, wraz z ograniczeniami tej techniki.
Mike T