Проблема с проецированием многоугольника, пересекающего линию даты R

У меня есть многоугольник в равновеликой проекции Северной Америки, и я хотел бы преобразовать его в неспроецированную долготу/широту. Я хотел бы использовать его для обрезки глобального растра в непроецируемом лонглате.

Проблема в том, что он пересекает линию даты и возвращает проблемный многоугольник. Есть ли способ вместо этого вернуть два многоугольника, по одному по обе стороны от линии даты?

Я также открыт для других предложений.

Примечание. Растр, который я собираюсь обрезать, является глобальным и имеет разрешение 1 км. Поэтому я стараюсь избежать необходимости проецировать этот растр, так как это будет связано с большими вычислительными затратами.

library(terra)
library(sf)
library(rnaturalearth)

ee <- ext(c(-4342031, 3457969, -3389091, 4710909))
ee <- as.polygons(ee, crs = "+proj=aea +lat_0=40 +lon_0=-96 +lat_1=20 +lat_2=60 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs")

ee <- st_transform(st_as_sf(ee), 4326)

world <- ne_coastline()
plot(world, lwd =0.5)
plot(ee, add=T)

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Существует функция sf::st_break_antimeridian(), которая отлично подходит для подобных задач, однако она работает только для непроецируемых координат (GCS).

Поскольку ваш объект ee проецируется и становится «проблемным» при преобразовании в WGS84/EPSG:4326, простым решением является:

  • создайте модифицированную версию CRS WGS84/EPSG:4326, сместив центральный меридиан, чтобы гарантировать, что размер вашего объекта ee не пересекает антимеридиан (в этом примере 180 работает).
  • используйте sf::st_break_antimeridian(), чтобы разделить/сломать ее на антимеридиане
  • проект обратно к стандарту WGS84/EPSG:4326 CRS

Поскольку ваш SpatRaster имеет высокое разрешение, например. Размер ячейки 1 км, возможно, вам понадобится crop() и mask() в два этапа. Когда я попробовал выполнить один шаг, значения в результате были неправильными.

library(terra)
library(sf)
library(rnaturalearth)
library(ggplot2)
library(tidyterra)

# CRS projection strings
prj_aea <- "+proj=aea +lat_0=40 +lon_0=-96 +lat_1=20 +lat_2=60 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs"
prj_wgs84_180 <- "+proj=longlat +datum=WGS84 +lon_0=180"

# Create sf object, project to modified WGS84/EPSG:4326 CRS, split at anti-meridian,
# project back to standard WGS84/EPSG:4326
ee <- as.polygons(ext(c(-4342031, 3457969, -3389091, 4710909)), crs = prj_aea) |>
  st_as_sf() |>
  st_transform(prj_wgs84_180) |>
  st_break_antimeridian(lon_0 = 180) |>
  st_transform(4326)

# Example SpatRaster with a global extent at approximately 1km resolution
r <- rast(ext(-180, 180, -90, 90), res = 1000/111320, crs = "EPSG:4326")
set.seed(1)
r[] <- sample(1:5, ncell(r), replace = TRUE)

# Crop, then mask r using ee
r1 <- crop(r, ee)
r1 <- mask(r1, ee)

# Plot
ggplot() +
  geom_spatraster(data = r1) +
  scale_fill_gradient2(low = "#0072B2",
                       mid = "#ffff6d", midpoint = 3,
                       high = "#C74A8F",
                       na.value = "transparent") +
  geom_sf(data = ne_coastline(), colour = "grey45", linewidth = 0.1) +
  coord_sf(expand = FALSE) +
  theme(panel.background = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank())

Ниже приведен оригинальный ответ, практичный только в том случае, если ваши растровые данные имеют относительно низкое разрешение.

library(terra)
library(sf)
library(rnaturalearth)
library(ggplot2)

# CRS projection strings
prj_aea <- "+proj=aea +lat_0=40 +lon_0=-96 +lat_1=20 +lat_2=60 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs"
prj_wgs84_180 <- "+proj=longlat +datum=WGS84 +lon_0=180"
 
# Create sf object, project to modified WGS84 / EPSG:4326 CRS
ee <- as.polygons(ext(c(-4342031, 3457969, -3389091, 4710909)), crs = prj_aea) |>
  st_as_sf() |>
  st_transform(prj_wgs84_180)

# Create world sf, split at anti-meridian, project to modified WGS84 / EPSG:4326
# Will throw a warning, which you can safely ignore
world <- ne_coastline() |>
  st_break_antimeridian(lon_0 = 180) |>
  st_transform(prj_wgs84_180)

ggplot() +
  geom_sf(data = world, colour = "grey") +
  geom_sf(data = ee, fill = NA, linewidth = 1) +
  theme_void()

Вот рабочий процесс обрезки растра. Предполагается, что ваш растр представляет собой SpatRaster с WGS84/EPSG:4326 в качестве CRS. Убедитесь, что значения nrow и ncol для объекта r1 соответствуют размерам ваших фактических данных.

# Create example SpatRaster with global extent to represent your data
r <- rast(ext(-180, 180, -90, 90), nrow = 180, ncol = 360, crs = "EPSG:4326")
set.seed(1)
r[] <- sample(1:5, ncell(r), replace = TRUE)

# Project r to same CRS as ee
r1 <- rast(ext(0, 360, -90, 90), nrow = 180, ncol = 360, crs = prj_wgs84_180)
r1 <- project(r, r1)
r1 <- rotate(r1, 180)

# Crop r1 using ee, project back to standard WGS84/EPSG:4326
r2 <- crop(r1, ee, mask = TRUE)
r3 <- project(r2, r)

Постройте график результатов для сравнения:

library(tidyterra)
library(patchwork)

p1 <- ggplot() +
  geom_spatraster(data = r2) +
  scale_fill_gradient2(low = "#0072B2", 
                       mid = "#ffff6d", midpoint = 3, 
                       high = "#C74A8F",
                      na.value = "transparent") +
  geom_sf(data = world, colour = "grey45", linewidth = 0.1) +
  labs(title = "Projected to custom CRS and cropped") +
  coord_sf(expand = FALSE) +
  theme(panel.background = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank())

p2 <- ggplot() +
  geom_spatraster(data = r3) +
  scale_fill_gradient2(low = "#0072B2", 
                       mid = "#ffff6d", midpoint = 3, 
                       high = "#C74A8F",
                       na.value = "transparent") +
  geom_sf(data = ne_coastline(), colour = "grey45", linewidth = 0.1) +
  labs(title = "Cropped data projected back to standard WGS84") +
  coord_sf(expand = FALSE) +
  theme(legend.position = "none",
        panel.background = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank())

p1 + p2

Обратите внимание, что изображение выше имеет относительно низкое разрешение, поэтому если вы увеличите масштаб, появятся расхождения в цветах некоторых одинаковых ячеек (особенно по краям). Эта проблема не сохраняется при разрешении 600 точек на дюйм.

Это интересное решение, @l-tyrone, спасибо! Однако я стараюсь избежать необходимости преобразовывать растр, который мне нужно обрезать, поэтому это работает, но для меня не идеально. Добавлю примечание к своему вопросу.

Pascal 15.07.2024 03:53

Другие вопросы по теме