沿一个方向偏移多段线

Offsetting a polyline in one direction

我正在寻找一种方法来在一个方向(R 中)偏移通过 xy 坐标定义的任意曲线。我可以使用 {polyclip} 包在两个方向上偏移曲线。

library(polyclip)
#> polyclip 1.10-0 built from Clipper C++ version 6.4.0

# Make a curve
t <- seq(10, 0, by = -0.05)
curve <- data.frame(
  x = t * cos(t), y = t * sin(t)
)
plot(curve, type = 'l')

# Find offset
offset <- polylineoffset(curve, delta = 0.5, 
                         jointype = "round", endtype = "openbutt")[[1]]
offset <- as.data.frame(offset) # xy coordinates

lines(offset, col = "red")

因为曲线上的点比偏移的 delta 参数间隔更近,我可以通过找出一个点与下一个点之间的距离最大的地方来启发式地拆分偏移。

distance <- c(0, sqrt(diff(offset$x)^2 + sqrt(diff(offset$y)^2)))
max_dist <- which.max(distance)

plot(curve, type = 'l')
lines(offset[1:(max_dist - 1), ], col = 3)
lines(offset[max_dist:nrow(offset), ], col = 4)

reprex package (v2.0.1)

于 2021-11-11 创建

但是,我希望能够拆分偏移量,或者仅在一个方向上偏移,即使曲线上的点之间的距离比偏移距离更远。有没有办法在 R 中做到这一点?我没有与 {polyclip} 包结婚,使用其他包的解决方案也很好。

不需要额外的包 Teunbrand - 这可以用一个小的三角函数来完成:

offset <- function(x, y, d) {
 angle <- atan2(diff(y), diff(x)) + pi/2
 angle <- c(angle[1], angle)
 data.frame(x = d * cos(angle) + x, y = d * sin(angle) + y)
}

因此,如果我们重新创建您的示例,我们有:

t <- seq(10, 0, by = -0.05)

curve <- data.frame(
  x = t * cos(t), y = t * sin(t)
)

plot(curve, type = 'l')

我们可以添加一个偏移量:

curve2 <- offset(curve$x, curve$y, 0.5)

lines(curve2, col = "red")

此函数的工作方式是通过使用 atan2([delta y], [delta x]) 获取线的每个点的斜率角度,然后加上 90 度以找到线的角度 运行 与该点的曲线垂直。最后,它找到了沿这条线距离原始x,y坐标d的点,即(x + d * cos(angle), y + d * sin(angle))

这可能最好以图形方式显示。这里的蓝线是函数offset:

计算得到的偏移量
segments(curve$x, curve$y, curve2$x, curve2$y, col = "blue")

我们可以通过简单地传递负值 d:

来向相反的方向偏移
lines(offset(curve$x, curve$y, -0.5), col = "forestgreen")

我们需要了解定义偏移量的含义的局限性,尤其是当偏移量与绘图的任何凹面部分相比较大时。例如,如果我们查看 -2 的偏移量,我们的螺旋中心似乎有一个工件:

plot(curve, type = 'l')
curve3 <- offset(curve$x, curve$y, -2)
lines(curve3, col = "gray50")

如果我们再次绘制偏移线段,我们就能明白为什么会发生这种情况:

segments(curve$x, curve$y, curve3$x, curve3$y, col = "blue")

从本质上讲,如果你有一个紧凹的曲线和一个相当大的偏移量,那么偏移线就会交叉。这会产生一些与我们期望看到的“偏移路径”不完全匹配的东西,但是如果不仔细定义偏移路径的含义以及我们想要的方式,很难看出如何解决这个问题它出现在像上面那样的情况下。我的猜测是,最令人满意的解决方案是缩小 d 的点,否则它会超过该点的曲线半径,但我不会在这里实施,因为这只是一个选项,并且我敢肯定还有更好的。

无论如何,这样做的好处之一是结果中的点数与输入的点数相同。这使得将偏移量放入初始数据框中变得容易。方便构建新几何体!

reprex package (v2.0.0)

于 2021-11-12 创建