查找与指定方向的空间点的最近距离
Posted
技术标签:
【中文标题】查找与指定方向的空间点的最近距离【英文标题】:Find nearest distance from spatial point with direction specified 【发布时间】:2019-08-18 23:33:47 【问题描述】:我想计算预定方位 (0,45,90,135,180,225,270,315) 的空间点到空间线(或多边形)的最近距离。
这个想法是计算海岸线上多个海湾的暴露指数。下面提供一个简单的例子:
创建线条
library(sp)
coords<-structure(list(lon = c(-6.1468506, -3.7628174, -3.24646,
-3.9605713, -4.4549561, -4.7955322, -4.553833, -5.9710693, -6.1468506),
lat = c(53.884916, 54.807017, 53.46189, 53.363665, 53.507651, 53.363665, 53.126998, 53.298056,53.884916)), class = "data.frame", row.names = c(NA,-9L))
l<-Line(coords)
sl<-SpatialLines(list(Lines(list(l),ID="a")),proj4string=CRS("+init=epsg:4326"))
创建点
pt<-SpatialPoints(coords[5,]+0.02,proj4string=CRS("+init=epsg:4326"))
剧情
plot(sl)
plot(pt,add=T)
我无法找到有关下一步可能是什么的示例并且需要帮助。 我想计算的距离示例
【问题讨论】:
你不应该使用c
来命名对象,因为它是一个函数。除了您的点与折线相交:sf::st_intersects(sl, pt, sparse=FALSE)
.
已编辑。点代表海岸线上的一个位置,如果不在线上,它们将接近。我假设这些距离会返回零 - 我应该编辑这个点吗?
我已经移动了点
【参考方案1】:
您可以使用geosphere
库来完成它。不过,您需要在积分中添加CRS
:
library(geosphere)
pt <- SpatialPoints(c[5,],
proj4string=CRS("+init=epsg:4326"))
然后使用dist2Line
函数:
st_distance(st_cast(sl, "POINT"), pt)
# distance lon lat ID
#[1,] 2580.843 -4.451901 53.50677 1
或者,您可以使用sf
包将多段线转换为点,然后获取距离矩阵(您需要将对象转换为sf
class):
library(sf)
sl <- SpatialLines(list(Lines(list(l),ID="a")),
proj4string=CRS("+init=epsg:4326")) %>%
st_as_sf()
pt <- SpatialPoints(coords[5,]+0.02,
proj4string=CRS("+init=epsg:4326")) %>%
st_as_sf()
st_distance(st_cast(sl, "POINT"), pt)
#Units: [m]
# [,1]
# [1,] 119833.165
# [2,] 149014.814
# [3,] 79215.071
# [4,] 36422.390
# [5,] 2591.267
# [6,] 30117.701
# [7,] 45287.637
# [8,] 105289.230
# [9,] 119833.165
【讨论】:
谢谢,如果我理解正确,这种方法会计算到线连接点的距离(准确吗?)。我希望能够设置测量距离的方向。 当然,它们是准确的。【参考方案2】:提醒:在 R 中的地理数据方面,我不是英雄。
另外:我还没有自动计算所有方位角,而是手动执行操作以获得与 de 45 方位角相交的距离。 你必须自己弄清楚循环,因为我没有时间。完成后,请随时在此处提供/发布您的最终发现/代码。
这是我对这个问题的破解,一步一步。
#load libraries used
library(geosphere)
library(tidyverse)
library(sf)
#get bearings of lines of the polygon
df.poly <- coords %>%
mutate( lon_next = lead(lon), lat_next = lead(lat) ) %>%
mutate( bearing_to_next = ifelse( !is.na( lon_next ),
unlist( pmap( list( a = lon, b = lat, x = lon_next, y = lat_next ),
~ round( geosphere::bearing( c(..1, ..2), c(..3, ..4) ) )
)
),
NA )
) %>%
filter( !is.na( lon_next ) )
# lon lat bearing_to_next
# 1 -6.146851 53.88492 56
# 2 -3.762817 54.80702 167
# 3 -3.246460 53.46189 -103
# 4 -3.960571 53.36366 -64
# 5 -4.454956 53.50765 -125
# 6 -4.795532 53.36366 148
# 7 -4.553833 53.12700 -78
# 8 -5.971069 53.29806 -10
#find intersection point based on the intersection of two 'great circles'
#from two points with a bearing
gcIntersectBearing(
#coordinates 2nd point of polyline, with bearing to third point
c( -3.7628174, 54.807017 ), 167,
#coordinates point, with bearing of 45
c( -4.454956, 53.50765 ), 45 )
# lon lat lon lat
# [1,] -3.476074 54.07798 176.5239 -54.07798
让我们看看到目前为止我们得到了什么
p_intersect <- data.frame( lon = -3.476074, lat = 54.07798 ) %>%
st_as_sf( coords = c( "lon", "lat" ), crs = 4326 )
startpoint <- coords %>% slice(5) %>% mutate( lon = lon + 0.02, lat = lat + 0.02 ) %>%
st_as_sf( coords = c("lon","lat"), crs = 4326 )
poly <- coords %>%
as.matrix() %>%
list() %>%
st_polygon() %>%
st_sfc() %>%
st_set_crs( 4326 )
mapview::mapview( list(poly, startpoint, p_intersect) )
与startpoint
的交点p_intersect
在多边形poly
上的位置看起来正确,方位角为45 度。
现在您可以按如下方式计算距离:
#calculate distance
st_distance( startpoint, p_intersect )
# Units: [m]
# [,1]
# [1,] 87993.3
谷歌地图似乎就距离达成了一致(由于鼠标在这些点周围点击,有点差距,但在我看来还可以)
现在你必须弄清楚一些巧妙的循环/矢量化,你就完成了:) 我必须回到我真正的工作。
【讨论】:
【参考方案3】:感谢@patL 和@Wimpel,我已根据您的建议提出解决此问题的方法。
首先,我使用destPoint::geosphere
从原点创建设定距离和方位的空间线。然后我使用gIntersection::rgeos
获取每个样带与海岸线相交的空间点。最后,我分别使用gDistance::rgeos
计算每个样带线的原点到所有相交点的距离,并将最小值作为子集,即最近的相交。
加载包
pkgs=c("sp","rgeos","geosphere","rgdal") # list packages
lapply(pkgs,require,character.only=T) # load packages
创建数据
海岸线
coords<-structure(list(lon =c(-6.1468506,-3.7628174,-3.24646,
-3.9605713,-4.4549561,-4.7955322,-4.553833,-5.9710693,-6.1468506),
lat=c(53.884916,54.807017,53.46189,53.363665,53.507651,53.363665,53.126998,53.298056,53.884916)), class = "data.frame", row.names = c(NA,-9L))
l=Line(coords)
sl=SpatialLines(list(Lines(list(l),ID="a")),proj4string=CRS("+init=epsg:4326"))
点
sp=SpatialPoints(coords[5,]+0.02,proj4string=CRS("+init=epsg:4326"))
p=coordinates(sp) # needed for destPoint::geosphere
创建样带线
b=seq(0,315,45) # list bearings
tr=list() # container for transect lines
for(i in 1:length(b))
tr[[i]]<-SpatialLines(list(Lines(list(Line(list(rbind(p,destPoint(p=p,b=b[i],d=200000))))),ID="a")),proj4string=CRS("+init=epsg:4326")) # create spatial lines 200km to bearing i from origin
计算距离
minDistance=list() # container for distances
for(j in 1:length(tr)) # for transect i
intersects=gIntersection(sl,tr[[j]]) # intersect with coastline
minDistance[[j]]=min(distGeo(sp,intersects)) # calculate distances and use minimum
do.call(rbind,minDistance)
实际上,原点是一个空间点数据框,并且该过程针对多个站点循环多次。执行相交时也有许多 NULL 结果,因此循环包含一个 if 语句。
【讨论】:
以上是关于查找与指定方向的空间点的最近距离的主要内容,如果未能解决你的问题,请参考以下文章
在给定坐标和最大距离的情况下查找到某个点的最近点 - 使用 Mongoose 和 MEAN 堆栈查询结果未定义