[英]Calculating the distance between polygon and point in R
I have a, not necessarily convex, polygon without intersections and a point outside this polygon. 我有一个不一定是凸的多边形,没有交叉点,也有一个点在这个多边形之外。 I'm wondering how calculate the Euclidian distance most efficiently in a 2-dimensional space.
我想知道如何在二维空间中最有效地计算欧几里德距离。 Is there a standard method in
R
? R
有标准方法吗?
My first idea was to calculate the minimum distance of all the lines of the polygon (extended infinitely so they are line, not line pieces) and then calculate the distance from the point to each individual line using the start of the line piece and Pythagoras. 我的第一个想法是计算多边形的所有线的最小距离(无限延伸,因此它们是线,而不是线条),然后使用线条和毕达哥拉斯的起点计算从点到每条单独线的距离。
Do you know about a package that implements an efficient algorithm? 你知道一个实现高效算法的包吗?
You could use the rgeos package and the gDistance
method. 您可以使用rgeos包和
gDistance
方法。 This will require you to prepare your geometries, creating spgeom
objects from the data you have (I assume it is a data.frame or something similar). 这将要求您准备几何,从您拥有的数据创建
spgeom
对象(我假设它是data.frame或类似的东西)。 The rgeos documentation is very detailed (see the PDF manual of the package from the CRAN page), this is one relevant example from the gDistance
documentation: rgeos文档非常详细(请参阅CRAN页面中的软件包的PDF手册),这是
gDistance
文档中的一个相关示例:
pt1 = readWKT("POINT(0.5 0.5)")
pt2 = readWKT("POINT(2 2)")
p1 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
p2 = readWKT("POLYGON((2 0,3 1,4 0,2 0))")
gDistance(pt1,pt2)
gDistance(p1,pt1)
gDistance(p1,pt2)
gDistance(p1,p2)
readWKT
is included in rgeos as well. readWKT
也包含在rgeos中。
Rgeos is based on the GEOS library, one of the de facto standards in geometric computing. Rgeos基于GEOS库,是几何计算中事实上的标准之一。 If you don't feel like reinventing the wheel, this is a good way to go.
如果您不想重新发明轮子,这是一个很好的方法。
I decided to return and write up a theoretical solution, just for posterity. 我决定回归并撰写理论解决方案,仅供后人使用。 This isn't the most concise example, but it is fully transparent for those who want to know how to go about solving a problem like this by hand.
这不是最简洁的例子,但对于那些想要知道如何手动解决这类问题的人来说,它是完全透明的。
The theoretical algorithm 理论算法
First, our assumptions. 首先,我们的假设。
Now before coding, we should write out in basic terms what we want to do. 在编码之前,我们应该用基本的术语写出我们想要做的事情。 We can assume that the shortest distance between the polygon and the point outside the polygon will always be one of two things: a vertex of the polygon or a point on a line between two vertices.
我们可以假设多边形和多边形外部点之间的最短距离将始终是两个事物之一:多边形的顶点或两个顶点之间的线上的点。 With this in mind, we do the following steps:
考虑到这一点,我们执行以下步骤:
We're basically just looking to see if a vertex is closest to the point or if a point on a line is closest to the point. 我们基本上只是想看一个顶点是否最接近该点,或者一条线上的点是否最接近该点。 We have to use a few trig functions to make this work.
我们必须使用一些trig函数来完成这项工作。
The code 编码
To make this work properly, we want to avoid any 'for' loops and want to only use vectorized functions when looking at the entire list of polygon vertices. 为了使其正常工作,我们希望避免任何“for”循环,并且在查看整个多边形顶点列表时只想使用矢量化函数。 Luckily, this is pretty easy in R. We accept a data frame with 'x' and 'y' columns for our polygon's vertices, and we accept a vector with one 'x' and 'y' value for the point's location.
幸运的是,在R中这很容易。我们接受一个带有'x'和'y'列的数据框用于我们的多边形顶点,我们接受一个带有一个'x'和'y'值的矢量用于该点的位置。
get_Point_Dist_from_Polygon <- function(.polygon, .point){
# Calculate all vertex distances from the target point.
vertex_Distance <- sqrt((.point[1] - .polygon$x)^2 + (.point[2] - .polygon$y)^2)
# Select two closest vertices.
min_1_Index <- which.min(vertex_Distance)
min_2_Index <- which.min(vertex_Distance[-min_1_Index])
# Calculate lengths of triangle sides made of
# the target point and two closest points.
a <- vertex_Distance[min_1_Index]
b <- vertex_Distance[min_2_Index]
c <- sqrt(diff(.polygon$x[c(min_1_Index, min_2_Index)])^2 + diff(.polygon$y[c(min_1_Index, min_2_Index)])^2)
if(abs(min_1_Index - min_2_Index) != 1 |
acos((b^2 + c^2 - a^2)/(2*b*c)) >= pi/2 |
acos((a^2 + c^2 - b^2)/(2*a*c)) >= pi/2
){
# Step 3 of algorithm.
return(vertex_Distance[min_1_Index])
} else {
# Step 4 of algorithm.
# Here we are using the law of cosines.
return(sqrt((a+b-c) * (a-b+c) * (-a+b+c) * (a+b+c)) / (2 * c))
}
}
Demo 演示
polygon <- read.table(text="
x, y
0, 1
1, 0.8
2, 1.3
3, 1.4
2.5,0.3
1.5,0.5
0.5,0.1", header=TRUE, sep=",")
point <- c(3.2, 4.1)
get_Point_Dist_from_Polygon(polygon, point)
# 2.707397
Otherwise: 除此以外:
p2poly <- function(pt, poly){
# Closing the polygon
if(!identical(poly[1,],poly[nrow(poly),])){poly<-rbind(poly,poly[1,])}
# A simple distance function
dis <- function(x0,x1,y0,y1){sqrt((x0-x1)^2 +(y0-y1)^2)}
d <- c() # Your distance vector
for(i in 1:(nrow(poly)-1)){
ba <- c((pt[1]-poly[i,1]),(pt[2]-poly[i,2])) #Vector BA
bc <- c((poly[i+1,1]-poly[i,1]),(poly[i+1,2]-poly[i,2])) #Vector BC
dbc <- dis(poly[i+1,1],poly[i,1],poly[i+1,2],poly[i,2]) #Distance BC
dp <- (ba[1]*bc[1]+ba[2]*bc[2])/dbc #Projection of A on BC
if(dp<=0){ #If projection is outside of BC on B side
d[i] <- dis(pt[1],poly[i,1],pt[2],poly[i,2])
}else if(dp>=dbc){ #If projection is outside of BC on C side
d[i] <- dis(poly[i+1,1],pt[1],poly[i+1,2],pt[2])
}else{ #If projection is inside of BC
d[i] <- sqrt(abs((ba[1]^2 +ba[2]^2)-dp^2))
}
}
min(d)
}
Example: 例:
pt <- c(3,2)
triangle <- matrix(c(1,3,2,3,4,2),byrow=T, nrow=3)
p2poly(pt,triangle)
[1] 0.3162278
I used distm()
function in geosphere
package to calculate the distence when points and apexes are presented in coordinate system. 我用
distm()
函数在geosphere
包时被呈现点和顶点坐标系来计算distence。 Also, you can easily make some alternation by substitude dis <- function(x0,x1,y0,y1){sqrt((x0-x1)^2 +(y0-y1)^2)}
for distm()
. 此外,您可以通过
dis <- function(x0,x1,y0,y1){sqrt((x0-x1)^2 +(y0-y1)^2)}
轻松地进行一些替换,用于distm()
。
algo.p2poly <- function(pt, poly){
if(!identical(poly[1,],poly[nrow(poly),])){poly<-rbind(poly,poly[1,])}
library(geosphere)
n <- nrow(poly) - 1
pa <- distm(pt, poly[1:n, ])
pb <- distm(pt, poly[2:(n+1), ])
ab <- diag(distm(poly[1:n, ], poly[2:(n+1), ]))
p <- (pa + pb + ab) / 2
d <- 2 * sqrt(p * (p - pa) * (p - pb) * (p - ab)) / ab
cosa <- (pa^2 + ab^2 - pb^2) / (2 * pa * ab)
cosb <- (pb^2 + ab^2 - pa^2) / (2 * pb * ab)
d[which(cosa <= 0)] <- pa[which(cosa <= 0)]
d[which(cosb <= 0)] <- pb[which(cosb <= 0)]
return(min(d))
}
Example: 例:
poly <- matrix(c(114.33508, 114.33616,
114.33551, 114.33824,
114.34629, 114.35053,
114.35592, 114.35951,
114.36275, 114.35340,
114.35391, 114.34715,
114.34385, 114.34349,
114.33896, 114.33917,
30.48271, 30.47791,
30.47567, 30.47356,
30.46876, 30.46851,
30.46882, 30.46770,
30.47219, 30.47356,
30.47499, 30.47673,
30.47405, 30.47723,
30.47872, 30.48320),
byrow = F, nrow = 16)
pt1 <- c(114.33508, 30.48271)
pt2 <- c(114.6351, 30.98271)
algo.p2poly(pt1, poly)
algo.p2poly(pt2, poly)
Outcome: 结果:
> algo.p2poly(pt1, poly)
[1] 0
> algo.p2poly(pt2, poly)
[1] 62399.81
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.