如何延长线段使其触达多边形?
拉伸裁剪法:延长线段至多边形边界
针对「延长线段使其触达多边形」的需求,我设计了这个拉伸裁剪法的解决方案——它比我最初的方案更全面,覆盖了水平线、垂直线以及所有倾斜方向的线段场景。代码实现简洁,暂未做性能优化,适合基础场景使用。
代码实现
library(sf) # 定义测试线段 s1 <- rbind(c(1, 2), c(2, 3)) ls1 <- st_linestring(s1) s2 <- rbind(c(2, 2), c(1, 3)) ls2 <- st_linestring(s2) s3 <- rbind(c(2, 2), c(1, 1)) ls3 <- st_linestring(s3) s4 <- rbind(c(1, 2), c(2, 1)) ls4 <- st_linestring(s4) # 垂直线段 vl <- rbind(c(2.5, 2), c(2.5, 3)) svl <- st_linestring(vl) # 水平线段 hl <- rbind(c(0.5, 0.5), c(1, 0.5)) shl <- st_linestring(hl) # 组合为多线段 line <- st_multilinestring(list(ls1, ls2, ls3, ls4, svl, shl)) # 定义测试多边形 p1 <- rbind(c(0, 0), c(1, 0), c(3, 2), c(2, 4), c(1, 4), c(0, 0)) pol <- st_polygon(list(p1)) # 可选:绘制原始线段和多边形查看初始状态 # ( plot1 <- ggplot() + geom_sf(data = ls1, col = 'red', size = 2) + geom_sf(data = ls2, col = 'darkred', size = 2) + geom_sf(data = ls3, col = 'blue', size = 2) + geom_sf(data = ls4, col = 'darkblue', size = 2) + geom_sf(data = svl, col = 'green', size = 2) + geom_sf(data = shl, col = 'green', size = 2) + geom_sf(data = pol, fill = NA) ) ####################### 核心函数:拉伸并裁剪线段至多边形 line_stretchntrim <- function(line, polygon) { # 先检查坐标系是否匹配 if (st_crs(line) != st_crs(polygon)) return("CRS not matching") # 获取多边形的边界框,计算对角线长度作为拉伸基准 bb <- st_bbox(polygon) bbdiagLength <- as.numeric(sqrt((bb$xmin - bb$xmax) ^ 2 + (bb$ymin - bb$ymax) ^ 2)) # 提取线段的坐标对 xy <- st_coordinates(line)[, 1:2] npairs <- nrow(xy) / 2 etline <- NULL # 遍历每一条线段进行处理 for (i in 1:npairs) { ii <- (i - 1) * 2 + 1 x <- as.numeric(xy[ii:(ii + 1), 1]) y <- as.numeric(xy[ii:(ii + 1), 2]) dxline <- diff(x) dyline <- diff(y) d <- sqrt(dxline ^ 2 + dyline ^ 2) scale <- abs(as.numeric(bbdiagLength)) # 可自行调整拉伸倍数 signx <- sign(dxline) signy <- sign(dyline) theta <- atan(dxline / dyline) # 根据线段方向计算拉伸偏移量 if (signy == 1) { dx1 <- -sin(theta) * scale dy1 <- -cos(theta) * scale dx2 <- sin(theta) * scale dy2 <- cos(theta) * scale } if (signy == -1) { dx1 <- sin(theta) * scale dy1 <- cos(theta) * scale dx2 <- -sin(theta) * scale dy2 <- -cos(theta) * scale } # 处理垂直线段(dxline == 0)的特殊情况 if ((dxline == 0) * (signy == -1)) { dx1 <- 0 dy1 <- cos(theta) * scale dx2 <- 0 dy2 <- -cos(theta) * scale } if ((dxline == 0) * (signy == 1)) { dx1 <- 0 dy1 <- -cos(theta) * scale dx2 <- 0 dy2 <- cos(theta) * scale } # 处理水平线段(dyline == 0)的特殊情况 if ((signx == 1) * (dyline == 0)) { dx1 <- -sin(theta) * scale dy1 <- 0 dx2 <- sin(theta) * scale dy2 <- 0 } if ((signx == -1) * (dyline == 0)) { dx1 <- sin(theta) * scale dy1 <- 0 dx2 <- -sin(theta) * scale dy2 <- 0 } # 计算拉伸后的线段端点 x1 <- x[1] + dx1 y1 <- y[1] + dy1 x2 <- x[2] + dx2 y2 <- y[2] + dy2 # 构建拉伸后的空间线段 sline <- st_linestring(matrix(c(x1, y1, x2, y2), byrow = TRUE, ncol = 2)) slineSf <- st_sf(geom = st_sfc(sline), crs = st_crs(polygon)) # 将拉伸后的线段与多边形求交集,得到裁剪后的最终线段 stline <- st_intersection(slineSf, polygon) etline <- if (i == 1) stline else rbind(etline, stline) } return(etline) } # 调用函数处理线段 stretched_line <- line_stretchntrim(line, pol) # 可选:绘制结果查看效果 # ggplot() + geom_sf(data = pol, fill = NA) + geom_sf(data = line, size = 2) + geom_sf(data = stretched_line)
工作原理
- 坐标系检查:首先确保线段和多边形的坐标系一致,避免空间计算错误。
- 拉伸线段:以多边形边界框的对角线长度为基准,将每条线段向两端大幅拉伸,保证拉伸后的线段必然穿过多边形边界。
- 裁剪至多边形:通过空间交集计算,把拉伸后的线段裁剪到多边形的边界内,最终得到刚好触达多边形的线段。
- 特殊场景处理:单独适配水平线和垂直线的计算逻辑,避免三角函数运算带来的异常情况。
内容的提问来源于stack exchange,提问作者Ross D
相关产品推荐
相关产品推荐

