增加折线长度 r sf
increase polyline length r sf
我想找到一种方法,将多段线从起点增加 1000 英尺,从终点增加 1000 英尺。任何帮助是极大的赞赏!下面是一个示例。
structure(
list(
TECHNICAL_ = NA_character_,
geometry = structure(
list(
structure(
c(812697.360851467,
813792.18162311,
430678.939150205,
425750.102767913),
.Dim = c(2L, 2L),
class = c("XY", "LINESTRING", "sfg")
)
),
n_empty = 0L,
crs = structure(
list(
input = "+init=epsg:2257",
wkt = "PROJCRS[\"NAD83 / New Mexico East (ftUS)\",\n BASEGEOGCRS[\"NAD83\",\n DATUM[\"North American Datum 1983\",\n ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n LENGTHUNIT[\"metre\",1]]],\n PRIMEM[\"Greenwich\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n ID[\"EPSG\",4269]],\n CONVERSION[\"SPCS83 New Mexico East zone (US Survey feet)\",\n METHOD[\"Transverse Mercator\",\n ID[\"EPSG\",9807]],\n PARAMETER[\"Latitude of natural origin\",31,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8801]],\n PARAMETER[\"Longitude of natural origin\",-104.333333333333,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8802]],\n PARAMETER[\"Scale factor at natural origin\",0.999909091,\n SCALEUNIT[\"unity\",1],\n ID[\"EPSG\",8805]],\n PARAMETER[\"False easting\",541337.5,\n LENGTHUNIT[\"US survey foot\",0.304800609601219],\n ID[\"EPSG\",8806]],\n PARAMETER[\"False northing\",0,\n LENGTHUNIT[\"US survey foot\",0.304800609601219],\n ID[\"EPSG\",8807]],\n ID[\"EPSG\",15339]],\n CS[Cartesian,2],\n AXIS[\"(E)\",east,\n ORDER[1],\n LENGTHUNIT[\"US survey foot\",0.304800609601219,\n ID[\"EPSG\",9003]]],\n AXIS[\"(N)\",north,\n ORDER[2],\n LENGTHUNIT[\"US survey foot\",0.304800609601219,\n ID[\"EPSG\",9003]]],\n USAGE[\n SCOPE[\"unknown\"],\n AREA[\"USA - New Mexico - SPCS - E\"],\n BBOX[32,-105.72,37,-102.99]]]"
),
class = "crs"
),
class = c("sfc_LINESTRING", "sfc"),
precision = 0,
bbox = structure(
c(xmin = 812697.360851467,
ymin = 425750.102767913,
xmax = 813792.18162311,
ymax = 430678.939150205),
class = "bbox"
)
)
),
row.names = 1L,
sf_column = "geometry",
agr = structure(c(TECHNICAL_ = NA_integer_),
.Label = c("constant", "aggregate", "identity"),
class = "factor"),
class = c("sf", "tbl_df", "tbl", "data.frame")
)
我找到了解决办法。首先,使用 st_length() 计算原始线的长度,并附加类似于以下数据的原始坐标 table。在构建 table 之后,下面的公式就可以解决问题。
df<-structure(list(x= "abcd", surf_long = 569270.67464245,
surf_lat = 645729.112942885, bh_long = 569667.630944828,
bh_lat = 645187.374426766, length = 671.606228265491), row.names = c(NA,
-1L), groups = structure(list(x= "abcd", .rows = structure(list(
1L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr",
"list"))), row.names = 1L, class = c("tbl_df", "tbl", "data.frame"
), .drop = TRUE), class = c("grouped_df", "tbl_df", "tbl", "data.frame"
))
现在我们可以按比例增加线长X距离。
df<- df%>%mutate(surf_lat_ext=surf_lat-(bh_lat-surf_lat)*1250/length,
surf_long_ext=surf_long-(bh_long-surf_long)*1250/length,
bh_lat_ext=bh_lat+(bh_lat-surf_lat)*1250/length,
bh_long_ext=bh_long+(bh_long-surf_long)*1250/length)
下面是一种更通用的方法:
首先你需要一个函数来找到每个端点指向的方向:
st_ends_heading <- function(line)
{
M <- sf::st_coordinates(line)
i <- c(2, nrow(M) - 1)
j <- c(1, -1)
headings <- mapply(i, j, FUN = function(i, j) {
Ax <- M[i-j,1]
Ay <- M[i-j,2]
Bx <- M[i,1]
By <- M[i,2]
unname(atan2(Ay-By, Ax-Bx))
})
return(headings)
}
然后将线(一端或两端)延长给定距离(单位距离)的主要功能:
st_extend_line <- function(line, distance, end = "BOTH")
{
if (!(end %in% c("BOTH", "HEAD", "TAIL")) | length(end) != 1) stop("'end' must be 'BOTH', 'HEAD' or 'TAIL'")
M <- sf::st_coordinates(line)[,1:2]
keep <- !(end == c("TAIL", "HEAD"))
ends <- c(1, nrow(M))[keep]
headings <- st_ends_heading(line)[keep]
distances <- if (length(distance) == 1) rep(distance, 2) else rev(distance[1:2])
M[ends,] <- M[ends,] + distances[keep] * c(cos(headings), sin(headings))
newline <- sf::st_linestring(M)
# If input is sfc_LINESTRING and not sfg_LINESTRING
if (is.list(line)) newline <- sf::st_sfc(newline, crs = sf::st_crs(line))
return(newline)
}
所以在这种情况下,在 OP 的问题中使用 sf 对象作为 line_feature
:
sf::st_geometry(line_feature) <- st_extend_line(sf::st_geometry(line_feature), 1000)
我想找到一种方法,将多段线从起点增加 1000 英尺,从终点增加 1000 英尺。任何帮助是极大的赞赏!下面是一个示例。
structure(
list(
TECHNICAL_ = NA_character_,
geometry = structure(
list(
structure(
c(812697.360851467,
813792.18162311,
430678.939150205,
425750.102767913),
.Dim = c(2L, 2L),
class = c("XY", "LINESTRING", "sfg")
)
),
n_empty = 0L,
crs = structure(
list(
input = "+init=epsg:2257",
wkt = "PROJCRS[\"NAD83 / New Mexico East (ftUS)\",\n BASEGEOGCRS[\"NAD83\",\n DATUM[\"North American Datum 1983\",\n ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n LENGTHUNIT[\"metre\",1]]],\n PRIMEM[\"Greenwich\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n ID[\"EPSG\",4269]],\n CONVERSION[\"SPCS83 New Mexico East zone (US Survey feet)\",\n METHOD[\"Transverse Mercator\",\n ID[\"EPSG\",9807]],\n PARAMETER[\"Latitude of natural origin\",31,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8801]],\n PARAMETER[\"Longitude of natural origin\",-104.333333333333,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8802]],\n PARAMETER[\"Scale factor at natural origin\",0.999909091,\n SCALEUNIT[\"unity\",1],\n ID[\"EPSG\",8805]],\n PARAMETER[\"False easting\",541337.5,\n LENGTHUNIT[\"US survey foot\",0.304800609601219],\n ID[\"EPSG\",8806]],\n PARAMETER[\"False northing\",0,\n LENGTHUNIT[\"US survey foot\",0.304800609601219],\n ID[\"EPSG\",8807]],\n ID[\"EPSG\",15339]],\n CS[Cartesian,2],\n AXIS[\"(E)\",east,\n ORDER[1],\n LENGTHUNIT[\"US survey foot\",0.304800609601219,\n ID[\"EPSG\",9003]]],\n AXIS[\"(N)\",north,\n ORDER[2],\n LENGTHUNIT[\"US survey foot\",0.304800609601219,\n ID[\"EPSG\",9003]]],\n USAGE[\n SCOPE[\"unknown\"],\n AREA[\"USA - New Mexico - SPCS - E\"],\n BBOX[32,-105.72,37,-102.99]]]"
),
class = "crs"
),
class = c("sfc_LINESTRING", "sfc"),
precision = 0,
bbox = structure(
c(xmin = 812697.360851467,
ymin = 425750.102767913,
xmax = 813792.18162311,
ymax = 430678.939150205),
class = "bbox"
)
)
),
row.names = 1L,
sf_column = "geometry",
agr = structure(c(TECHNICAL_ = NA_integer_),
.Label = c("constant", "aggregate", "identity"),
class = "factor"),
class = c("sf", "tbl_df", "tbl", "data.frame")
)
我找到了解决办法。首先,使用 st_length() 计算原始线的长度,并附加类似于以下数据的原始坐标 table。在构建 table 之后,下面的公式就可以解决问题。
df<-structure(list(x= "abcd", surf_long = 569270.67464245,
surf_lat = 645729.112942885, bh_long = 569667.630944828,
bh_lat = 645187.374426766, length = 671.606228265491), row.names = c(NA,
-1L), groups = structure(list(x= "abcd", .rows = structure(list(
1L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr",
"list"))), row.names = 1L, class = c("tbl_df", "tbl", "data.frame"
), .drop = TRUE), class = c("grouped_df", "tbl_df", "tbl", "data.frame"
))
现在我们可以按比例增加线长X距离。
df<- df%>%mutate(surf_lat_ext=surf_lat-(bh_lat-surf_lat)*1250/length,
surf_long_ext=surf_long-(bh_long-surf_long)*1250/length,
bh_lat_ext=bh_lat+(bh_lat-surf_lat)*1250/length,
bh_long_ext=bh_long+(bh_long-surf_long)*1250/length)
下面是一种更通用的方法:
首先你需要一个函数来找到每个端点指向的方向:
st_ends_heading <- function(line)
{
M <- sf::st_coordinates(line)
i <- c(2, nrow(M) - 1)
j <- c(1, -1)
headings <- mapply(i, j, FUN = function(i, j) {
Ax <- M[i-j,1]
Ay <- M[i-j,2]
Bx <- M[i,1]
By <- M[i,2]
unname(atan2(Ay-By, Ax-Bx))
})
return(headings)
}
然后将线(一端或两端)延长给定距离(单位距离)的主要功能:
st_extend_line <- function(line, distance, end = "BOTH")
{
if (!(end %in% c("BOTH", "HEAD", "TAIL")) | length(end) != 1) stop("'end' must be 'BOTH', 'HEAD' or 'TAIL'")
M <- sf::st_coordinates(line)[,1:2]
keep <- !(end == c("TAIL", "HEAD"))
ends <- c(1, nrow(M))[keep]
headings <- st_ends_heading(line)[keep]
distances <- if (length(distance) == 1) rep(distance, 2) else rev(distance[1:2])
M[ends,] <- M[ends,] + distances[keep] * c(cos(headings), sin(headings))
newline <- sf::st_linestring(M)
# If input is sfc_LINESTRING and not sfg_LINESTRING
if (is.list(line)) newline <- sf::st_sfc(newline, crs = sf::st_crs(line))
return(newline)
}
所以在这种情况下,在 OP 的问题中使用 sf 对象作为 line_feature
:
sf::st_geometry(line_feature) <- st_extend_line(sf::st_geometry(line_feature), 1000)