【问题标题】:Find the co-ordinates on a line at the closest point to another point in R在 R 中找到离另一点最近的点的直线上的坐标
【发布时间】:2016-01-22 15:16:38
【问题描述】:

在 R 中工作我有 2 个对象,一个 SpatialLinesDataFrame(表示道路网络)和一个 SpatialPointsDataFrame(表示对象位置)。我需要输出最接近每个对象位置的点在道路上的坐标。

我可以从搜索中找到的所有方法都是在其他语言中执行此操作(例如 Python - How to find the closest point on a line segment to an arbitrary point?)或用于查找点和线之间的最小距离(例如使用 geosphere::dist2Line()rgeos::gDistance())。我只对返回直线上最近点的坐标感兴趣。

编辑: 这是我的道路网络的一小部分:

new("SpatialLinesDataFrame"
    , data = structure(list(ID = c(0, 0, 0, 0, 0, 0, 0),
                            ET_ID = c("4", "4", "4", "4", "4", "4", "4"),
                            length = c(0.280848, 0.812133, 0.0402004, 0.209611, 0.0433089, 0.501865, 0.363501)),
                       .Names = c("ID", "ET_ID", "length"),
                       row.names = c(980L, 982L, 983L, 984L, 987L, 988L, 989L),
                       class = "data.frame")
, lines = list(<S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>, 
               <S4 object of class structure("Lines", package = "sp")>)
, bbox = structure(c(433266.568837884, 547825.73420664, 437050.511867258, 548168.921069476),
                   .Dim = c(2L, 2L),
                   .Dimnames = list(c("x", "y"), c("min", "max")))
, proj4string = new("CRS", projargs = "+proj=utm +zone=37 +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")
)

以及我的对象位置:

new("SpatialPointsDataFrame"
    , data = structure(list(x = c(38.4129, 38.41697, 38.41501), y = c(4.95659, 4.95809, 4.96122)),
                       .Names = c("x", "y"), row.names = c(105L, 166L, 185L), class = "data.frame")
    , coords.nrs = numeric(0)
    , coords = structure(c(434912.0166297, 435363.392542353, 435146.398500838, 547894.637850701, 548060.055746692, 548406.25007762),
                         .Dim = c(3L, 2L), .Dimnames = list(c("105", "166", "185"), c("x", "y")))
    , bbox = structure(c(434912.0166297, 547894.637850701, 435363.392542353, 548406.25007762),
                       .Dim = c(2L, 2L), .Dimnames = list(c("x", "y"), c("min", "max")))
    , proj4string = new("CRS", projargs = "+proj=utm +zone=37 +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")
)

提前致谢!

【问题讨论】:

  • 也许您愿意分享您的数据示例?
  • 好的,我试试输出
  • 回答this SO question 有帮助吗?或者geosphere 包中的dist2line 函数。
  • 您是否在maptools 包中寻找nearestPointOnLine?不过,您必须稍微调整一下您的SpatialLinesDF。此外,由于未打印出 S4 对象,因此您粘贴的数据将不起作用。
  • 啊,snapPointsToLinesSpatial* 对象一起使用。您需要几何(投影)坐标,因为它不适用于经纬度。只有在处理全球范围内的数据集时才会出现问题...

标签: r coordinates gis spatial


【解决方案1】:

如果你不介意自己实现这个,从这个伪代码移植...

Point snap_to_segment(Point point, Segment segment):
    Point s1 = segment.start;
    Point s2 = segment.end;

    Vector v = s2 - s1;
    Vector w = point - s1;

    double c1 = Vector.dot_product(w,v);
    double c2 = Vector.dot_product(v,v);

    Point snap;

    if c1 <= 0:
        snap = s1

    elif c2 <= c1:
        snap = s2

    else:
        snap = s1 + v * (c1 / c2)

    return snap

除此之外,当我决定使用 Shapely 时,我在 Python 中的表现要比上面的函数好得多。事实证明:

rgeos 是 Python 的 Shapely 的 R 对应物。 Shapely 和 rgeos 都基于 GEOS(即 PostGIS 引擎)(source)

...但是,在 Shapely 中,我找到了这样的所需点:

desiredPoint = road.distance(road.project(point));

rgeos 似乎缺少linestring.project(point)linestring.distance(scalarValue) 方法...

【讨论】:

    【解决方案2】:

    这里是 heltonbiker 在 R(2D 版本)中的答案的快速破解,供可能需要的人使用。当然,最好使用库,但有时您不想这样做,如果您只需要获取一条线上最近的点,就可以了。

    findClosestPtToSeg <- function( ptx,pty, sx0,sy0,sx1,sy1 ){
    
      sdx <- sx1-sx0
      sdy <- sy1-sy0
      wx <- ptx-sx0
      wy <- pty-sy0
    
      lambda <- (wx*sdx + wy*sdy) / (sdx*sdx + sdy*sdy)
      trunclamb <- min(max(lambda,0),1)
    
      rv <- list() # return the coordinates in a list
      rv$x <- sx0 + trunclamb*sdx
      rv$y <- sy0 + trunclamb*sdy
      return(rv)
    }
    

    下面是一些测试用例的一些输出:

    > findClosestPtToSeg( 1,2, 0,0,1,1 )
    $x
    [1] 1
    $y
    [1] 1
    
    > findClosestPtToSeg( -1,-2, 0,0,1,1 )
    $x
    [1] 0
    $y
    [1] 0
    
    > findClosestPtToSeg( 0.5,0.6, 0,0,1,1 )
    $x
    [1] 0.55
    $y
    [1] 0.55
    

    请注意,这不是漂亮的代码,它不检查退化间隔,并且处理输入点的方式(通过坐标传递)与返回值(打包在带有名称的列表中)不同。哦,好吧,这是一个快速的 hack,对我来说效果很好。

    如果这有帮助,请确保 heltonbiker 也获得任何支持。

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 2013-09-07
      相关资源
      最近更新 更多