Подтвердить что ты не робот

Проверьте, находится ли точка в пространственном объекте, который состоит из нескольких полигонов/отверстий

У меня есть SpatialPolygonsDataFrame с 11589 объектами класса "полигоны". 10699 из этих объектов состоит из ровно 1 многоугольника, однако остальные из этих объектов состоят из нескольких полигонов (от 2 до 22).

Если объект состоит из нескольких полигонов, возможны три сценария:

  • Иногда эти дополнительные полигоны описывают "дыру" в географическом ара, описываемую первым многоугольником в объекте класса "многоугольники".
  • Иногда эти дополнительные полигоны описывают дополнительные географические области, т.е. форма области довольно сложна и описывается путем объединения нескольких частей.
  • Иногда это может быть сочетание обоих: 1) и 2).

Stackoverflow помог мне правильно построить такой пространственный объект (Площадь пространственного участка, заданная несколькими многоугольниками).

Однако я все еще не могу ответить, как определить, находится ли точка (заданная долготой/широтой) в многоугольнике.

Ниже мой код. Я попытался применить функцию point.in.polygon в пакете sp, но не нашел способа, как он мог бы обрабатывать такой объект, который состоит из нескольких полигонов/дыр.

# Load packages
# ---------------------------------------------------------------------------
library(maptools)
library(rgdal)
library(rgeos)
library(ggplot2)
library(sp) 


# Get data
# ---------------------------------------------------------------------------
# Download shape information from the internet
URL <- "http://www.geodatenzentrum.de/auftrag1/archiv/vektor/vg250_ebenen/2012/vg250_2012-01-01.utm32s.shape.ebenen.zip"
td <- tempdir()
setwd(td)
temp <- tempfile(fileext = ".zip")
download.file(URL, temp)
unzip(temp)

# Get shape file
shp <- file.path(tempdir(),"vg250_0101.utm32s.shape.ebenen/vg250_ebenen/vg250_gem.shp")

# Read in shape file
map <- readShapeSpatial(shp, proj4string = CRS("+init=epsg:25832"))

# Transform the geocoding from UTM to Longitude/Latitude
map <- spTransform(map, CRS("+proj=longlat +datum=WGS84"))


# Pick an geographic area which consists of multiple polygons
# ---------------------------------------------------------------------------
# Output a frequency table of areas with N polygons 
nPolys <- sapply([email protected], function(x)length([email protected]))

# Get geographic area with the most polygons
polygon.with.max.polygons <- which(nPolys==max(nPolys))

# Get shape for the geographic area with the most polygons
Poly.coords <- map[which(nPolys==max(nPolys)),]


# Plot
# ---------------------------------------------------------------------------
# Plot region without Google maps (ggplot2) 
plot(Poly.coords,  col="lightgreen")


# Find if a point is in a polygon 
# ---------------------------------------------------------------------------
# Define points 
points_of_interest <- data.frame(long=c(10.5,10.51,10.15,10.4), 
                     lat =c(51.85,51.72,51.81,51.7),
                     id  =c("A","B","C","D"), stringsAsFactors=F)

# Plot points
points(points_of_interest$long, points_of_interest$lat, pch=19)

enter image description here

4b9b3361

Ответ 1

Вы можете сделать это просто с помощью gContains(...) в пакете rgeos.

gContains(sp1,sp2)

возвращает логическое значение в зависимости от того, содержится ли sp2 в sp1. Единственный нюанс заключается в том, что sp2 должен быть объектом SpatialPoints, и он должен иметь тот же прогноз, что и sp1. Чтобы сделать это, вы сделали бы что-то вроде этого:

point <- data.frame(lon=10.2, lat=51.7)
sp2   <- SpatialPoints(point,proj4string=CRS(proj4string(sp1)))
gContains(sp1,sp2)

Вот рабочий пример, основанный на ответе на ваш предыдущий вопрос.

library(rgdal)   # for readOGR(...)
library(rgeos)   # for gContains(...)
library(ggplot2)

setwd("< directory with all your files >")
map <- readOGR(dsn=".", layer="vg250_gem", p4s="+init=epsg:25832")
map <- spTransform(map, CRS("+proj=longlat +datum=WGS84"))

nPolys <- sapply([email protected], function(x)length([email protected]))
region <- map[which(nPolys==max(nPolys)),]

region.df <- fortify(region)
points <- data.frame(long=c(10.5,10.51,10.15,10.4), 
                     lat =c(51.85,51.72,51.81,51.7),
                     id  =c("A","B","C","D"), stringsAsFactors=F)

ggplot(region.df, aes(x=long,y=lat,group=group))+
  geom_polygon(fill="lightgreen")+
  geom_path(colour="grey50")+
  geom_point(data=points,aes(x=long,y=lat,group=NULL, color=id), size=4)+
  coord_fixed()

Здесь точка A находится в основном полигоне, точка B находится в озере (дыра), точка C находится на острове, а точка D полностью вне области. Таким образом, этот код проверяет все точки с помощью gContains(...)

sapply(1:4,function(i)
  list(id=points[i,]$id,
       gContains(region,SpatialPoints(points[i,1:2],proj4string=CRS(proj4string(region))))))
#    [,1] [,2]  [,3] [,4] 
# id "A"  "B"   "C"  "D"  
#    TRUE FALSE TRUE FALSE

Ответ 2

Поскольку вы можете использовать подпрограмму "point in polygon", и это, по-видимому, уже не подходит для обработки многополигонального футляра в R (который я нахожу немного нечетным на самом деле), вам остается выполнить цикл через каждый из многоугольников. Теперь трюк, если вы находитесь внутри нечетного числа полигонов, вы находитесь внутри многополигона. Если вы находитесь внутри четного числа полигонов, вы фактически находитесь вне формы.

Точка в полигональном тестировании, использующая перекрестку лучей, должна УЖЕ быть в состоянии справиться с этим, просто убедившись, что вы передаете все вершины в исходный тест point.in.polygon, но я не уверен, какой механизм R использует, поэтому я могу дать вам даже четный совет выше.

Я также нашел этот код, не уверен, поможет ли он:

require(sp)
require(rgdal)
require(maps)

# read in bear data, and turn it into a SpatialPointsDataFrame
bears <- read.csv("bear-sightings.csv")
coordinates(bears) <- c("longitude", "latitude")

# read in National Parks polygons
parks <- readOGR(".", "10m_us_parks_area")

# tell R that bear coordinates are in the same lat/lon reference system
# as the parks data -- BUT ONLY BECAUSE WE KNOW THIS IS THE CASE!
proj4string(bears) <- proj4string(parks)

# combine is.na() with over() to do the containment test; note that we
# need to "demote" parks to a SpatialPolygons object first
inside.park <- !is.na(over(bears, as(parks, "SpatialPolygons")))

# what fraction of sightings were inside a park?
mean(inside.park)
## [1] 0.1720648

# use 'over' again, this time with parks as a SpatialPolygonsDataFrame
# object, to determine which park (if any) contains each sighting, and
# store the park name as an attribute of the bears data
bears$park <- over(bears, parks)$Unit_Name

# draw a map big enough to encompass all points (but don't actually plot
# the points yet), then add in park boundaries superimposed upon a map
# of the United States
plot(coordinates(bears), type="n")
map("world", region="usa", add=TRUE)
plot(parks, border="green", add=TRUE)
legend("topright", cex=0.85,
    c("Bear in park", "Bear not in park", "Park boundary"),
    pch=c(16, 1, NA), lty=c(NA, NA, 1),
    col=c("red", "grey", "green"), bty="n")
title(expression(paste(italic("Ursus arctos"),
    " sightings with respect to national parks")))

# now plot bear points with separate colors inside and outside of parks
points(bears[!inside.park, ], pch=1, col="gray")
points(bears[inside.park, ], pch=16, col="red")

# write the augmented bears dataset to CSV
write.csv(bears, "bears-by-park.csv", row.names=FALSE)

# ...or create a shapefile from the points
writeOGR(bears, ".", "bears-by-park", driver="ESRI Shapefile")