R 将线旋转到正北或垂直方向

R 将线旋转到正北或垂直方向,r,ggplot2,sf,R,Ggplot2,Sf,我有一个数据集,其中包含对角运行的多段线,我想将这些线旋转到垂直或正北,以便正确显示x轴数据。我已经看过罗德里格斯公式,但它的方式超过我的头,想知道他们是否是一个包在R,我可以使用。请参见下面的示例,我需要对其进行旋转 library(sf) library(ggplot2) ex<-structure(list(OBJECTID = c(10526, 10913), geometry = structure(list( structure(c(-103.47406, -103.

我有一个数据集,其中包含对角运行的多段线,我想将这些线旋转到垂直或正北,以便正确显示x轴数据。我已经看过罗德里格斯公式,但它的方式超过我的头,想知道他们是否是一个包在R,我可以使用。请参见下面的示例,我需要对其进行旋转

library(sf)
library(ggplot2)

ex<-structure(list(OBJECTID = c(10526, 10913), geometry = structure(list(
    structure(c(-103.47406, -103.46268, 31.47367, 31.48499), .Dim = c(2L, 
    2L), class = c("XY", "LINESTRING", "sfg")), structure(c(-103.46525, 
    -103.4788333, 31.4879722000001, 31.4748056), .Dim = c(2L, 
    2L), class = c("XY", "LINESTRING", "sfg"))), n_empty = 0L, crs = structure(list(
    epsg = 4267L, proj4string = "+proj=longlat +datum=NAD27 +no_defs"), class = "crs"), class = c("sfc_LINESTRING", 
"sfc"), precision = 0, bbox = structure(c(xmin = -103.4788333, 
ymin = 31.47367, xmax = -103.46268, ymax = 31.4879722000001), class = "bbox"))), row.names = c(NA, 
-2L), sf_column = "geometry", agr = structure(c(OBJECTID = NA_integer_), .Label = c("constant", 
"aggregate", "identity"), class = "factor"), class = c("sf", 
"tbl_df", "tbl", "data.frame"))

ggplot(ex)+geom_sf()
库(sf)
图书馆(GG2)

ex假设所有直线平行,旋转点是所有直线的质心,一种方法是

  • 找到直线的质心
  • 找到直线和正北方向之间的方位
  • 围绕质心旋转每个坐标
  • 完成了
  • 库(sf)
    图书馆(sfheaders)
    图书馆(GG2)
    图书馆(地球圈)
    ##找到线的中心
    
    我相信它需要在离原点最近的点附近。如果多段线的长度明显不同,围绕中点或任何其他点旋转都会有问题。就我而言,这不是一个很好的原点定义。我只想把线旋转到垂直方向,但保持两条线之间的距离不变。我已经更新了,加入了我所追求的东西的图表。左图为原始方位/方向。正确的两个情节中的任何一个都是我想要做的。可能在直线组的中点旋转?是的,它们将始终平行或接近平行。
    library(sf)
    library(sfheaders)
    library(ggplot2)
    library(geosphere)
    
    ## get the centre of the lines
    centre <- sf::st_centroid( sf::st_union( ex ) )
    
    ## remove class so we just have coordinates as a vector
    centre <- unclass( centre[[1]] )
    
    ## get each coordinate of the lines. These will each be rotated
    coords <- sf::st_coordinates( ex )
    
    ## to know the angle of rotation, we need to know due-north from a given point
    ## under the assumption all lines are parallel, we just need the bearing between the 
    ## start of a line and the end
    ##
    ## you're using lon / lat values, so we can use geosphere package to get the bearing
    bearing <- geosphere::bearing(
      p1 = coords[1, c("X","Y")]
      , p2 = coords[2, c("X","Y")]
      )
    
    
    theta <- bearing * pi / 180 ## in radians
    
    #' rotate
    #' function to rotate x and y coordinates around a point
    #' theta - angle of rotation
    #' p - point(s) to rotate
    #' centre - centre point
    rotate <- function( theta, p, centre ) {
      new_x <- cos( theta ) * ( p[, 1] - centre[1] ) - sin( theta ) * ( p[, 2] - centre[2] ) + centre[1]
      new_y <- sin( theta ) * ( p[, 1] - centre[1] ) + cos( theta ) * ( p[, 2] - centre[2] ) + centre[2] 
      return( matrix( c( new_x, new_y ), ncol = 2 ) ) 
    }
    
    ## calculate the rotated points
    coords_new <- rotate( theta, coords, centre )
    
    ## we've kept order in tact, so we can cbind the L1 id back on
    coords_new <- cbind( coords_new, coords[, "L1"])
    
    ## new sf object (using library(sfheaders) )
    sf_new <- sfheaders::sf_linestring( obj = coords_new, linestring_id = 3)
    sf::st_crs( sf_new ) <- sf::st_crs( ex )
    
    ## plot to verify
    ggplot() + geom_sf( data = sf_new ) + 
      geom_sf( data = ex ) + 
      geom_sf( data = sf::st_centroid( sf::st_union( ex ) ) )