-->

确定给定的纬度和经度属于一个多边形(Determine if a given lat-lon bel

2019-09-29 09:04发布

假设我有称为数据文件zone19942D协调员表示多边形的顶点的坐标等以下的(每行的RHS的非常第一数字表示zone

c1 <- "1", "1 21, 31 50, 45 65, 75 80"

c2 <- "2", "3 20, 5 15, 2 26, 70 -85, 40 50, 60 80"

.....

c1993 <- "1993", "3 2, 2 -5, 0 60, 7 -58, -12 23, 56 611, 85 152"

c1994 <- "1994", "30 200, 50 -15, 20 260, 700 -850, -1 2, 5 6, 8 15"

现在我想操纵给定一个随机对这样这些字符串lat-lon (比方说1220 ),我可以比较,看它是否属于第一多边形,第二面,第三面,...或第一千九百九十四多边形。 蛮力溶液:比较x-coordinate= 12 )与所有4 x坐标-和y-coordinate= 20) to all the 4 ý -coordinates in C1 and C2 , respectively. The conclusion would be whether there is a valid **sandwich** inequality for each given coordinate , respectively. The conclusion would be whether there is a valid **sandwich** inequality for each given coordinate X and y`。

例如,通过使用如上述方案中的过程中,点(12,20)将在C1而不是C2。

我的问题:我怎么能实现读该目标是什么?

我尝试:感谢斯特凡纳·洛朗的帮助,我是能够产生所有矩阵,每个具有一定尺寸,存储的lat-lon用下面的代码每个多边形的所有顶点对:

 zone <- read_delim("[directory path to zone.csv file]", delim = ",", col_names = TRUE)
for(i in 1:nrow(zone)){
  zone$geo[i] = substr(zone$geo[i],10,135)
}
zone <- zone[complete.cases(zone),]

 Numextract <- function(string){
    unlist(regmatches(string, gregexpr("[[:digit:]]+\\.*[[:digit:]]*", string)))
 }

for(i in 1:nrow(zone)){
        poly1 <- matrix(as.numeric(Numextract(zone$geo[i])),i, ncol=2, byrow=TRUE)
        poly2 <- cbind(poly1, c(i))
}

然而,正如你可能会看到,我需要找到一种方法, 指数对应的期间生成的每个区域每个矩阵for()循环。 究其原因是因为事后,我可以用另一种for()循环来确定一个点属于哪个区! 但我一直没能想出解决办法,所以任何人都可以请帮我详细的代码?

实际数据集
区和多边形数据集

纬度,经度对数据集

Answer 1:

首先,定义多边形的矩阵,每一行代表一个顶点:

poly1 <- rbind(c(1,21), c(31,50), c(45,65), c(75,80))
poly2 <- rbind(c(3,20), c(5,15), c(2,26), c(70,-85))

定义要测试的点:

point <- c(12,20)

现在,使用pip2d的功能ptinpoly包:

> library(ptinpoly)
> pip2d(poly1, rbind(point))
[1] -1
> pip2d(poly2, rbind(point))
[1] 1

这意味着(见?pip2d )的一点是外poly1和内部poly2

注意rbind(point)pip2d 。 我们使用rbind因为我们可以更普遍地在同一个多边形运行几个点的测试。

如果您需要帮助转换

c1 <- "1 21, 31 50, 45 65, 75 80"

poly1 <- rbind(c(1,21), c(31,50), c(45,65), c(75,80))

那么也许你应该打开另一个问题。

编辑

好了,不要打开另一个问题。 您可以按以下步骤操作。

c1 <- "1 21, 31 50, 45 65, 75 80"

Numextract <- function(string){
  unlist(regmatches(string, gregexpr("[[:digit:]]+\\.*[[:digit:]]*", string)))
}

poly1 <- matrix(as.numeric(Numextract(c1)), ncol=2, byrow=TRUE)

这使:

> poly1
     [,1] [,2]
[1,]    1   21
[2,]   31   50
[3,]   45   65
[4,]   75   80

第二次编辑

对于你的第二个问题,你的数据是太大了。 我可以看到的唯一的解决办法是将数据分割成更小的碎片。

但首先,它似乎pip2d功能也使R对话崩溃。 所以请使用其他功能: pnt.in.poly从包SDMTools

下面是该函数的一小的修改,通过删除无用的输出使其更快:

library(SDMTools)
pnt.in.poly2 <- function(pnts, poly.pnts){
  if (poly.pnts[1, 1] == poly.pnts[nrow(poly.pnts), 1] && 
      poly.pnts[1, 2] == poly.pnts[nrow(poly.pnts), 2]){ 
    poly.pnts = poly.pnts[-1, ]
  }
  out = .Call("pip", pnts[, 1], pnts[, 2], nrow(pnts), poly.pnts[,1], poly.pnts[, 2], nrow(poly.pnts), PACKAGE = "SDMTools")
  return(out)
}

现在,如前面所说的,拆分lat_lon在更小的片,每百万长度,(除了最后一个,更小):

lat_lon_list <- vector("list", 70)
for(i in 1:69){
  lat_lon_list[[i]] = lat_lon[(1+(i-1)*1e6):(i*1e6),]
}
lat_lon_list[[70]] <- lat_lon[69000001:nrow(lat_lon),]

现在,运行此代码:

library(data.table)
for(i in 1:70){
  DT <- data.table(V1 = pnt.in.poly2(lat_lon_list[[i]], polys[[1]]))
  for(j in 2:length(polys)){
    DT[, (sprintf("V%d",j)):=pnt.in.poly2(lat_lon_list[[i]], polys[[j]])]
  }
  fwrite(DT, sprintf("results%02d.csv", i))
  rm(DT)
}

如果它工作,它应产生70个CSV文件, result01.csv ,..., result70.csv ,各尺寸的1000000x1944 (除了最后一个,小),那么就可以在Excel中打开它们。

3编辑

我试过的代码,我得到了一个错误: Error: cannot allocate vector of size 7.6 Mb

我们需要一个更精细的分割:

lat_lon_list <- vector("list", 2*69+1)
for(i in 1:(2*69)){
  lat_lon_list[[i]] = lat_lon[(1+(i-1)*1e6/2):(i*1e6/2),]
}
lat_lon_list[[2*69+1]] <- lat_lon[69000001:nrow(lat_lon),]

for(i in 1:(2*69+1)){
  DT <- data.table(V1 = pnt.in.poly2(lat_lon_list[[i]], polys[[1]]))
  for(j in 2:length(polys)){
    DT[, (sprintf("V%d",j)):=pnt.in.poly2(lat_lon_list[[i]], polys[[j]])]
  }
  fwrite(DT, sprintf("results%02d.csv", i))
  rm(DT)
}


文章来源: Determine if a given lat-lon belong to a polygon