R에서 다각형 중심을 계산하는 방법 (인접하지 않은 모양의 경우)


41

나는이 질문에 대한 답을 알아내는 동안 약간을 보냈습니다. Google 검색 에서 즉시 분명하지는 않으므로 여기에 답변을 게시하면 도움이 될 것이라고 생각했습니다. 비 연속 다각형 에 대한 추가 질문도 있습니다 .

즉각적인 쉬운 답변 : 다음 명령을 사용하십시오.

centroids <- getSpPPolygonsLabptSlots(polys)

(이것은 R의 중요한 공간 패키지에 대한 SpatialPolygonsDataFrame R 데이터 클래스 의 클래스 설명 에서 발견되었습니다. sp )

이것은 정확히 똑같은 일을하는 것 같습니다

cents <- SpatialPointsDataFrame(coords=cents, data=sids@data, proj4string=CRS("+proj=longlat +ellps=clrk66"))

다음 코드에서 R 설치시 복제 가능해야합니다 (시도하십시오!)

#Rcentroids
install.packages("GISTools")
library(GISTools)
sids <- readShapePoly(system.file("shapes/sids.shp", package="maptools")[1], 
                      proj4string=CRS("+proj=longlat +ellps=clrk66"))
class(sids)
plot(sids)
writeSpatialShape(sids, "sids")
cents <- coordinates(sids)
cents <- SpatialPointsDataFrame(coords=cents, data=sids@data, 
                  proj4string=CRS("+proj=longlat +ellps=clrk66"))
points(cents, col = "Blue")
writeSpatialShape(cents, "cents")

centroids <- getSpPPolygonsLabptSlots(sids)
points(centroids, pch = 3, col = "Red")

센트 (파란색)와 센트 로이드 (빨간색)가 동일한 센트 로이드 인 경우 (코드를 실행 한 후에 표시되어야 함) :

R에 의해 계산 된 중심

여태까지는 그런대로 잘됐다. 그러나 QGIS에서 다각형 중심을 계산할 때 (메뉴 : Vector | Geometry | Polygon Centroids) 비 연속 다각형에 대한 결과는 약간 다릅니다.

QGIS 생성 다각형

따라서이 질문은 3 가지입니다.

  1. 빠르고 쉬운 답변
  2. 인접하지 않은 다각형의 중심을 계산하기 위해 R을 사용하는 사람들에게 경고
  3. 멀티 파트 (비 연속) 폴리곤을 올바르게 설명하기 위해 R에서 어떻게 수행해야하는지에 대한 질문

위에서 설명한 함수 중심을 인용하는 방법을 알아야합니다. 감사합니다
Santiago Fernandez

GIS StackExchange에 오신 것을 환영합니다! 새로운 사용자로서 둘러보세요 . 이것은이 질문에 대한 답이 아닌 새로운 질문으로 보입니다. 새로운 질문으로 게시하십시오.
smiller

답변:


56

첫째, 나는 말한다 모든 문서 찾을 수 없습니다 coordinates또는 getSpPPolygonsLabptSlots중앙-의 질량 중심을 반환합니다. 실제로 후자의 기능은 이제 '더 이상 사용되지 않음'으로 표시되며 경고를 발행해야합니다.

피쳐의 질량 중심으로 중심을 계산하기 위해 원하는 gCentroid것은 rgeos패키지 의 기능입니다 . 그렇게 help.search("centroid")했을 것입니다.

trueCentroids = gCentroid(sids,byid=TRUE)
plot(sids)
points(coordinates(sids),pch=1)
points(trueCentroids,pch=2)

차이를 보여 주어야하며 Qgis 중심과 동일해야합니다.


3
많은 R의 공간 패키지 개발자 인 Roger Bivand에 따르면, "그렇다."Polygons-class "의 클래스 문서에는 다른 점이 레이블 포인트로 유효하게 삽입 될 수 있기 때문에 이것이 사실이라고 명시되어 있지 않다. 기본 생성자는 Polygons 객체에서 가장 큰 비홀 링의 중심을 사용합니다. " -비 연속성을 설명합니다. stat.ethz.ch/pipermail/r-help/2009-February/187436.html . 확인 : gCentroid (sids, byid = TRUE)는 실제로 문제를 해결합니다.
RobinLovelace

gCentroid (polygon, byid = TRUE)를 적용하더라도 중심이 두 다각형 사이에 배치됩니다. 따라서 다중 다각형으로 간주되는 것으로 가정합니다. 어떻게 나눌 수 있습니까? 포인트 (좌표 (SC.tracks), pch = 16, col = "blue", cex = 0.4), 그러나 생성은 다각형에서 중심을 생성하지 않습니다.
maycca

stat.ethz.ch에 대한 링크가 더 이상 작동하지 않습니다. 완벽을 기하기 위해 답을 찾을 수 있다고 확신합니다 : r.789695.n4.nabble.com/…
Exocom

8

다음은 sf를 사용하는 접근법입니다. 설명했듯이 sf :: st_centroid와 rgeos :: gCentroid의 결과는 동일합니다.

library(sf)
library(ggplot2)

# I transform to utm because st_centroid is not recommended for use on long/lat 
nc <- st_read(system.file('shape/nc.shp', package = "sf")) %>% 
  st_transform(32617)

# using rgeos
sp_cent <- gCentroid(as(nc, "Spatial"), byid = TRUE)

# using sf
sf_cent <- st_centroid(nc)

# plot both together to confirm that they are equivalent
ggplot() + 
  geom_sf(data = nc, fill = 'white') +
  geom_sf(data = sp_cent %>% st_as_sf, color = 'blue') + 
  geom_sf(data = sf_cent, color = 'red') 

여기에 이미지 설명을 입력하십시오


3

이 문제를 극복하기 위해 수행 한 것은 다각형이 볼록 다각형을 기대하기에 충분히 작을 때까지 음을 버퍼링하는 함수를 생성하는 것입니다. 사용할 기능은centroid(polygon)

#' find the center of mass / furthest away from any boundary
#' 
#' Takes as input a spatial polygon
#' @param pol One or more polygons as input
#' @param ultimate optional Boolean, TRUE = find polygon furthest away from centroid. False = ordinary centroid

require(rgeos)
require(sp)

centroid <- function(pol,ultimate=TRUE,iterations=5,initial_width_step=10){
  if (ultimate){
    new_pol <- pol
    # For every polygon do this:
    for (i in 1:length(pol)){
      width <- -initial_width_step
      area <- gArea(pol[i,])
      centr <- pol[i,]
      wasNull <- FALSE
      for (j in 1:iterations){
        if (!wasNull){ # stop when buffer polygon was alread too small
          centr_new <- gBuffer(centr,width=width)
          # if the buffer has a negative size:
          substract_width <- width/20
          while (is.null(centr_new)){ #gradually decrease the buffer size until it has positive area
            width <- width-substract_width
            centr_new <- gBuffer(centr,width=width)
            wasNull <- TRUE
          }
          # if (!(is.null(centr_new))){
          #   plot(centr_new,add=T)
          # }
          new_area <- gArea(centr_new)
          #linear regression:
          slope <- (new_area-area)/width
          #aiming at quarter of the area for the new polygon
          width <- (area/4-area)/slope
          #preparing for next step:
          area <- new_area
          centr<- centr_new
        }
      }
      #take the biggest polygon in case of multiple polygons:
      d <- disaggregate(centr)
      if (length(d)>1){
        biggest_area <- gArea(d[1,])
        which_pol <- 1                             
        for (k in 2:length(d)){
          if (gArea(d[k,]) > biggest_area){
            biggest_area <- gArea(d[k,])
            which_pol <- k
          }
        }
        centr <- d[which_pol,]
      }
      #add to class polygons:
      new_pol@polygons[[i]] <- remove.holes(new_pol@polygons[[i]])
      new_pol@polygons[[i]]@Polygons[[1]]@coords <- centr@polygons[[1]]@Polygons[[1]]@coords
    }
    centroids <- gCentroid(new_pol,byid=TRUE)
  }else{
    centroids <- gCentroid(pol,byid=TRUE)  
  }  
  return(centroids)
}

#Given an object of class Polygons, returns
#a similar object with no holes


remove.holes <- function(Poly){
  # remove holes
  is.hole <- lapply(Poly@Polygons,function(P)P@hole)
  is.hole <- unlist(is.hole)
  polys <- Poly@Polygons[!is.hole]
  Poly <- Polygons(polys,ID=Poly@ID)
  # remove 'islands'
  max_area <- largest_area(Poly)
  is.sub <- lapply(Poly@Polygons,function(P)P@area<max_area)  
  is.sub <- unlist(is.sub)
  polys <- Poly@Polygons[!is.sub]
  Poly <- Polygons(polys,ID=Poly@ID)
  Poly
}
largest_area <- function(Poly){
  total_polygons <- length(Poly@Polygons)
  max_area <- 0
  for (i in 1:total_polygons){
    max_area <- max(max_area,Poly@Polygons[[i]]@area)
  }
  max_area
}

느리지 만 매우 좋은 결과를 제공합니다. 잘 배치되고 라벨 배치에 좋은 결과를 제공합니다
Bastien
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.