Duccio 提出的解决方案会重置每个新段的间距。我将脚本改编为具有运行间距的版本。下图显示了差异。
按照 Duccio 的方法进行拆分
所需的间距(由绿色条的长度表示)始终从每个段开始。与前一段的剩余距离不会转移到下一段。因此,得到的间距在整行上不是恒定的。
按照我的方法进行拆分
所需的间距被转移到拐角处。这种方法保证了这些点相对于原始线始终具有所需的间距。然而,这里的结果点彼此的间距都不是恒定的。此外,这种方法产生的线比原始线短。
这种效果会随着分辨率的提高而减弱。
或者可以通过将可选参数“add_original_points”设置为 TRUE 来防止。
注意:“使用正确的算法”取决于您的应用程序。
免责声明:我的版本完全基于 Duccio A 的解决方案,我给予他充分的信任。
我的方法不使用 Line 对象(sp 包),但完全适用于数据帧。因此,我不想分叉原始的 github 存储库。
完整代码为:
resample_polyline = function(polyline, interval_length = 20, add_original_points = TRUE, add_final_point = FALSE) {
# The function splits a polyline into segments of a given length.
# polyline: a spatial polyline data frame
# interval_length: the length of the segments to split the lines into, in units of the polyline coordinates
# add_original_points: whether or not the original points of the polyline should be added to the resulting line
# if set FALSE, the resulting line will be shorter
# add_final_point: whether or not the final point of the polyline should be added to the resulting line
# transform input polyline
linedf = data.frame(
x = polyline$x[1:nrow(polyline)-1],
y = polyline$y[1:nrow(polyline)-1],
x2 = polyline$x[2:nrow(polyline)],
y2 = polyline$y[2:nrow(polyline)]
)
# prepare output
df = data.frame(
x = numeric(),
y = numeric()
)
residual_seg_length = 0
for (i in 1:nrow(linedf)) {
# for each line of the dataframe calculate segment length
v_seg = linedf[i, ]
seg_length = sqrt((v_seg$x - v_seg$x2) ^ 2 + (v_seg$y - v_seg$y2) ^ 2)
# create a vector of direction for the segment
v = c(v_seg$x2 - v_seg$x, v_seg$y2 - v_seg$y)
# unit length
u = c(v[1] / sqrt(v[1] ^ 2 + v[2] ^ 2), v[2] / sqrt(v[1] ^ 2 + v[2] ^ 2))
# calculate number of segment the segment is split into
num_seg = floor((seg_length - residual_seg_length) / interval_length)
# skip if next vertex is before interval_length
if(num_seg >= 0) {
# add interpolated segments
for (i in 0:(num_seg)) {
df[nrow(df) + 1,] = c(
v_seg$x + u[1] * residual_seg_length + u[1] * interval_length * i ,
v_seg$y + u[2] * residual_seg_length + u[2] * interval_length * i
)
}
# add original point (optional)
if(add_original_points){
df[nrow(df) + 1,] = c(
v_seg$x2,
v_seg$y2
)
}
} else {
# add original point (optional)
if(add_original_points){
df[nrow(df) + 1,] = c(
v_seg$x2,
v_seg$y2
)
}
residual_seg_length = residual_seg_length - seg_length
next()
}
# calculate residual segment length
residual_seg_length = interval_length - ((seg_length - residual_seg_length) - (num_seg * interval_length))
}
# add final point (optional)
if(add_final_point){
df = rbind(df, data.frame(
x = tail(polyline$x, n=1),
y = tail(polyline$y, n=1)
))
}
return(df)
}
测试一下
polyline = data.frame(
x = c(-5,1,5,7,8,12,14,16,17,13), # x
y = c(0,11,3,8,2,15,9,13,15,23) # y
)
plot(polyline$x, polyline$y, type="l", asp=1, lwd=1)
points(polyline$x, polyline$y, pch=4, cex=4, col="gray")
polyline2 = resample_polyline(polyline, interval_length = 5, add_final_point = FALSE, add_original_points = TRUE)
lines(polyline2$x, polyline2$y, col="red", lty=4, lwd=3)
points(polyline2$x, polyline2$y, pch=19)
legend("topleft",
c("original points", "added points", "resulting line"),
pch = c(4, 19, NA),
lty = c(NA, NA, 2),
pt.cex = c(4,1,1),
col = c("gray", "black", "red")
)