r sf центр тяжести пакета внутри многоугольника

Мне нужно добавить метки к многоугольникам, и я обычно использую центроид, однако центроид не попадает внутрь многоугольника. Я нашел этот вопрос Рассчитать центроид ВНУТРИ / ВНУТРИ пространственного многоугольника, но я использую пакет SF.

Ниже представлены данные игрушки

rm(list = ls(all = TRUE)) #start with empty workspace

library(sf)
library(tidyverse)
library(ggrepel)

pol <- st_polygon(list(rbind(c(144, 655),c(115, 666)
                         ,c(97, 660),c(86, 640)
                         ,c(83, 610),c(97, 583)
                         ,c(154, 578),c(140, 560)
                         ,c(72, 566),c(59, 600)
                         ,c(65, 634),c(86, 678)
                         ,c(145, 678),c(144, 655)))) %>%
  st_sfc()

a = data.frame(NAME = "A")
st_geometry(a) = pol

a <- a  %>% 
  mutate(lon = map_dbl(geometry, ~st_centroid(.x)[[1]]),
     lat = map_dbl(geometry, ~st_centroid(.x)[[2]]))

ggplot() +
  geom_sf(data = a, fill = "orange") +
  geom_label_repel(data = a, aes(x = lon, y = lat, label = NAME)) 

что приводит к следующему

введите описание изображения здесь


person user3357059    schedule 26.09.2018    source источник
comment
Вы можете заменить ~st_centroid на ~st_point_on_surface. То есть, если вас не волнует истинный центроид любого многоугольника.   -  person Mitch    schedule 26.09.2018
comment
В этом вопросе содержится дополнительная информация о st_PointOnSurface от postgis gis .stackexchange.com / questions / 76498 /   -  person Mitch    schedule 26.09.2018


Ответы (2)


Простой ответ - заменить st_centroid на st_point_on_surface. Это не вернет истинный центроид в случаях, когда центроид находится внутри многоугольника.

a2 <- a  %>% 
  mutate(lon = map_dbl(geometry, ~st_point_on_surface(.x)[[1]]),
         lat = map_dbl(geometry, ~st_point_on_surface(.x)[[2]]))

ggplot() +
  ggplot2::geom_sf(data = a2, fill = "orange") +
  geom_label_repel(data = a2, aes(x = lon, y = lat, label = NAME))

Или же

Если у многоугольника есть центроид, который находится внутри многоугольника, используйте его, в противном случае найдите точку внутри многоугольника.

st_centroid_within_poly <- function (poly) {

  # check if centroid is in polygon
  centroid <- poly %>% st_centroid() 
  in_poly <- st_within(centroid, poly, sparse = F)[[1]] 

  # if it is, return that centroid
  if (in_poly) return(centroid) 

  # if not, calculate a point on the surface and return that
  centroid_in_poly <- st_point_on_surface(poly) 
  return(centroid_in_poly)
}

a3 <- a  %>% 
  mutate(lon = map_dbl(geometry, ~st_centroid_within_poly(.x)[[1]]),
         lat = map_dbl(geometry, ~st_centroid_within_poly(.x)[[2]]))

ggplot() +
  ggplot2::geom_sf(data = a3, fill = "orange") +
  geom_label_repel(data = a3, aes(x = lon, y = lat, label = NAME)) 

Вышеупомянутая функция st_centroid_within_polygon адаптирована из вопроса, на который вы ссылаетесь для пакета sf. Более подробный обзор того, как работает st_point_on_surface, можно найти здесь .

person Mitch    schedule 26.09.2018

Расширение ответа Митча, потому что функция st_centroid_within_poly, представленная выше, работает только с отдельными полигонами.

Чтобы использовать на нескольких полигонах, используйте:

st_centroid_within_poly <- function (poly) {

  # check if centroid is in polygon
  ctrd <- st_centroid(poly, of_largest_polygon = TRUE)
  in_poly <- diag(st_within(ctrd, poly, sparse = F))

  # replace geometries that are not within polygon with st_point_on_surface()
  st_geometry(ctrd[!in_poly,]) <- st_geometry(st_point_on_surface(poly[!in_poly,]))

  ctrd
}
person M.M. Middeldorp    schedule 11.03.2019
comment
Ошибка на st_geometry(ctrd[!in_poly,]) <- st_geometry(st_point_on_surface(poly[!in_poly,])) с Error in poly[!in_poly, ] : incorrect number of dimensions - person CoderGuy123; 30.09.2019