я пишу с помощью R и RStudio. В моей глобальной среде есть набор полигонов, один из которых называется buek250_shapefile. Я могу нанести их на листовку. Для следующего шага я написал функцию, которая получает значения широты и долготы и должна возвращать информацию о фигуре, которая имеет кратчайшее расстояние до следующей формы многоугольника. Моя проблема: я всегда получаю одну и ту же форму многоугольника для всех значений широты и долготы, которые я пытаюсь использовать. Расчетные расстояния составляют от 5000 до 7000 км. Но все мои фигуры и значения широты находятся в Германии, а Германия не такая уж большая. Мои данные: https://download.bgr.de/bgr/boden/BUEK250/shp/buek250_mg_utm_v55.zip Может ли кто-нибудь здесь помочь мне, пожалуйста? Большое спасибо
lowestdistancebuek <- function(inputlat, inputlon) {
# Modify the clicked point. Make the input data into CRS format
# Order is important: first lat, then lon
point <- st_point(c(inputlat, inputlon)) %>%
st_sfc(crs = 25832)
# Is there a shape containing the clickedpoint?
nearestshape <- st_intersects(point, buek250_shapefile_all, sparse = FALSE)
# nearestsape is a logical matrix. For every polygon it contains if the point is in or not
# Which polygon contains the point? Extract it
nearestshape <- which(nearestshape, arr.ind = TRUE)
# Extract the column
nearestshape <- nearestshape[,2]
# If there is a shape containing the point, nearestshape has length 1
# In this case, nearestshape is set to the sf
# Otherwise, the nearestshape is determinded and set to nearestshape
if (length(nearestshape) == 1) {
nearestshape <- buek250_shapefile_all[nearestshape, ]
} else if (length(nearestshape) == 0){ # no polygon contains the point
# Compute the distances between each polygon and the point. Result is saved in distances
distances <- st_distance(point, buek250_shapefile_all,
by_element = FALSE, # TRUE returns a vector
tolerance = TRUE # speeds up computing
)
# Which distance ist the smallest one?
nearestshape <- which.min(distances)
# The shortest number was saved in nearestshape, now there is saved the polygone information
nearestshape <- buek250_shapefile_all[nearestshape, ]
}
return(nearestshape)
}
Прямо сейчас я получаю для каждого входа один и тот же результат. Я ожидаю, что код вернет шейп-файл с кратчайшим расстоянием до заданной точки.
Делаем еще одно предположение на основе заголовка («трансформировать») и комментариев к коду («щелчок») — если эти входные координаты являются значениями широты и долготы из листовки, st_sfc(crs = 25832)
не преобразует, а просто переводит геометрию CRS в epsg:25832. В результате любое значение широты и долготы из Германии, независимо от порядка, оказывается где-то в Атлантике, рядом с Африкой, в том же диапазоне 5000....7000 км от Германии, свидетелем которого вы являетесь.
Эй, Маргусл, сейчас я просто тестирую некоторые значения широты и долготы, например 52,52, 10,405. Я предполагаю, что моя проблема — ложное смещение на восток, но я не знаю, как ее решить. Почему st_transform делает это нет? Я загружаю форму с помощью: buek250_shapefile_all <- sf::st_read("C:/Users/Documents/Uni/SoilMapExtraData/buek250_mg_utm_v55/buek250_mg_utm_v55.shp") Я могу сопоставить формы с помощью листовки. Прямо сейчас я вызываю lowdistancebuek(52.52,10.405) или другие значения прямо в консоли.
Как правильно предположил @margusl, вы вводите координаты в десятичных градусах в свою функцию, а затем назначаете им проекционную систему координат (PCS) CRS, которая имеет метры для единиц измерения. Таким образом, эти десятичные градусы рассматриваются как метры. Предполагая, что вы вводите значения WGS84/EPSG:4326, вам нужно что-то вроде st_point(c(inputlon, inputlat)) %>% st_sfc(crs = 4326) %>% st_transform(25832)
. Что бы вы ни делали, вам необходимо знать систему координат ваших входных координат и убедиться, что это долгота (назначается первой), а какая широта (назначается второй).
Я уже пробовал этот способ. Но это ничего не меняет при вычислении расстояний. point_df <- data.frame(X = c(inputlat), Y = c(inputlon)) point <- st_as_sf(point_df, coords = c("X", "Y"), crs = 4326) point <- st_transform( point, crs = 25832) > point Простая коллекция объектов с 1 объектом и 0 полями Тип геометрии: POINT Размер: XY Ограничительная рамка: xmin: 5908302 ymin: 1601570 xmax: 5908302 ymax: 1601570 Проецируемая CRS: ETRS89 / зона UTM 32N геометрия 1 POINT (5908302 1601570) > расстояния[которые.мин(расстояния)] 6283818 [м]
Вы все еще инвертируете значения широты и долготы в своем df. Пожалуйста, перечитайте внимательно комментарии выше. Чтобы объяснить это по-другому, x == долгота и y == широта. Так и должно быть df <- data.frame(X = c(inputlon), Y = c(inputlat))
.
Хотя географические координаты обычно представляются в виде пар latitude, longitude
, геометрические операции обычно предполагают порядок x, y
, который также применим и к sf::st_point()
. Если вам нужна мнемоника для широты и долготы, вы можете попробовать «lat» -> «ladder» -> «y» .
Чтобы преобразовать одну CRS в другую, используйте st_transform()
; но для того, чтобы это работало, входным данным должен быть назначен CRS, и это роль аргумента crs
в st_sfc(x, crs = "WGS84")
. Он определяет то, что у вас есть в данный момент, а не то, что вы хотите получить в итоге.
Здесь я использую формы из giscoR
для воспроизводимого примера.
library(giscoR)
library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.3.1; sf_use_s2() is TRUE
# example shapes from GISCO / giscoR
ger_25832 <-
giscoR::gisco_get_nuts(country = "Germany", nuts_level = "1") |>
st_transform(25832)
plot(ger_25832[,"NUTS_NAME"], axes = TRUE)
Во-первых, давайте попробуем построить точку по этим географическим координатам, чтобы она оказалась где-то в интересующей области:
# input point coordinates, WGS84
inputlat_wgs84 <- 52.52 # mnemonic: latitude like "ladder", y-axis
inputlon_wgs84 <- 10.405
# create WGS84 point, transform, check distances:
ref_pt <-
# x,y!
st_point(c(inputlon_wgs84, inputlat_wgs84)) |>
st_sfc(crs = "WGS84") |>
st_transform(crs = st_crs(ger_25832))
st_distance(ger_25832, ref_pt) |> units::set_units(km)
#> Units: [km]
#> [,1]
#> [1,] 221.48755
#> [2,] 184.04861
#> [3,] 88.60661
#> [4,] 114.36606
#> [5,] 101.80472
#> [6,] 115.41499
#> [7,] 87.67142
#> [8,] 0.00000
#> [9,] 87.76893
#> [10,] 250.06811
#> [11,] 396.54742
#> [12,] 165.09594
#> [13,] 35.32782
#> [14,] 94.75578
#> [15,] 99.73750
#> [16,] 308.01952
Кажется, на этот раз у нас правильный порядок и преобразование широты и долготы, давайте соответствующим образом настроим эту функцию, мы можем использовать st_nearest_feature()
для подмножества ближайшего объекта:
# same in the function + subset with st_nearest_feature()
lowestdistancebuek <- function(inputlat_wgs84, inputlon_wgs84, shapes = ger_25832){
ref_pt <-
st_point(c(inputlon_wgs84, inputlat_wgs84)) |>
st_sfc(crs = "WGS84") |>
st_transform(crs = st_crs(shapes))
shapes[st_nearest_feature(ref_pt, shapes),]
}
nearest_shape <- lowestdistancebuek(inputlat_wgs84, inputlon_wgs84)
nearest_shape
#> Simple feature collection with 1 feature and 10 fields
#> Geometry type: MULTIPOLYGON
#> Dimension: XY
#> Bounding box: xmin: 343686.6 ymin: 5682911 xmax: 674176.7 ymax: 5971541
#> Projected CRS: ETRS89 / UTM zone 32N
#> NUTS_ID LEVL_CODE URBN_TYPE CNTR_CODE NAME_LATN NUTS_NAME MOUNT_TYPE
#> 58 DE9 1 0 DE NIEDERSACHSEN NIEDERSACHSEN 0
#> COAST_TYPE FID geo geometry
#> 58 0 DE9 DE9 MULTIPOLYGON (((486772.8 59...
Постройте нашу тестовую точку и полученную форму:
# plot
plot(st_union(ger_25832))
plot(nearest_shape, add = TRUE)
#> Warning in plot.sf(nearest_shape, add = TRUE): ignoring all but the first
#> attribute
plot(ref_pt, col = "red", pch = 16, add = TRUE)
Created on 2024-06-19 with reprex v2.1.0
Добро пожаловать в ТАК! Пожалуйста, сделайте этот пример воспроизводимым для других. Например, мы не знаем, как вы загружаете этот шейп-файл, как вы звоните
lowestdistancebuek()
или какие значения координат вы тестировали. Тем не менее, вашst_point(c(inputlat, inputlon))
должен читатьсяst_point(c(inputlon, inputlat))
. Или, что еще лучше, используйте что-то вродеx,y
илиeasting, northing
при ссылке на координаты зоны 32N ETRS89/UTM в вашем коде.