线处理
目的和范围
本文档介绍 Turf.js 中的线处理操作,通过分割、分段、交点检测和分块来操作 LineString 几何体。这些操作能够将线在特定点分割、找到线交叉位置、提取单个段并将线分割为测量块。
For boolean spatial relationship tests involving lines (e.g., booleanParallel, booleanCrosses), see Boolean Predicates. For polygon manipulation operations, see Polygon Operations. For distance calculations and coordinate transformations along lines, see Distance and Bearing.
模块概述
线处理类别包括六个主要模块,用于操作 LineString 和 MultiLineString 几何体:
| Module | Package | Primary Function | Key Dependencies |
|---|---|---|---|
| Line Split | @turf/line-split | Splits a LineString by another feature | @turf/geojson-rbush, @turf/line-intersect, @turf/line-segment |
| Line Intersect | @turf/line-intersect | Finds intersection points between lines | sweepline-intersections |
| Line Segment | @turf/line-segment | Creates segments from line coordinates | @turf/meta |
| Line Chunk | @turf/line-chunk | Divides lines into distance-based chunks | @turf/length, @turf/line-slice-along |
| Line Overlap | @turf/line-overlap | Finds overlapping segments | @turf/line-segment |
| Line Offset | @turf/line-offset | Offsets lines perpendicular to direction | @turf/meta |
线处理模块依赖
线分割操作
概述
lineSplit 函数在与分割器 feature 的交点处将 LineString 分割为多个段。分割器可以是 Point、MultiPoint、LineString、MultiLineString、Polygon 或 MultiPolygon。
Entry Point: packages/turf-line-split/index.js29-62
输入验证和类型处理
该函数执行类型检查以确保 line 参数是 LineString,并拒绝 FeatureCollections 和 GeometryCollections 作为分割器 packages/turf-line-split/index.js33-40。分割器被截断到 7 位小数,以避免空间索引中的浮点精度问题 packages/turf-line-split/index.js44。
对于非 Point 分割器,该函数首先使用 lineIntersect 查找所有交点,然后在这些点处分割线 packages/turf-line-split/index.js55-60。
单点分割算法
单点分割算法使用 R 树空间索引 (rbush) 进行高效段查找。它遵循以下步骤:
- 端点处理:如果分割点完全匹配任一端点,则返回原始线不变 packages/turf-line-split/index.js126-130
- 分段:使用
lineSegment将线转换为单独的两顶点段 packages/turf-line-split/index.js134 - 空间索引:将段加载到 rbush 树中以进行快速空间查询 packages/turf-line-split/index.js133-135
- 邻近搜索:搜索点边界框内的段 packages/turf-line-split/index.js138
- 最近匹配:当存在多个候选时,使用
nearestPointOnLine查找最近的段 packages/turf-line-split/index.js144 - 坐标累积:使用
featureReduce迭代段,累积坐标直到到达分割段 packages/turf-line-split/index.js148-170 - 分割构建:在交点处创建两个 LineString,避免坐标重复 packages/turf-line-split/index.js159-161
多点分割算法
多点分割算法在顺序处理每个点时维护动态空间索引:
- 初始化:创建一个空的 rbush 树来跟踪中间线段 packages/turf-line-split/index.js74
- 第一个点:分割原始线并将结果连同唯一 ID 加载到树中 packages/turf-line-split/index.js78-84
- 后续点:对于每个剩余点:
- 在树中搜索点 bbox 内的候选线 packages/turf-line-split/index.js88
- 使用
nearestPointOnLine找到最近的线 packages/turf-line-split/index.js92 - 从结果数组和树中删除最近的线 packages/turf-line-split/index.js96-99
- 将最近的线分割为两个新段 packages/turf-line-split/index.js102
- 将两个新段重新插入结果和树中 packages/turf-line-split/index.js103-105
该算法为 features 分配唯一 ID 以便高效过滤和删除 packages/turf-line-split/index.js78-80
辅助函数
lineSplit 模块包括实用函数:
findClosestFeature(point, lines) packages/turf-line-split/index.js186-202
- 从一组候选中选择最近的 feature
- 使用
nearestPointOnLine计算点到每条线的距离 - 返回具有最小距离的 feature
- 作为优化处理单 feature 集合
pointsEquals(pt1, pt2) packages/turf-line-split/index.js212-214
- 比较两个坐标数组是否完全相等
- 用于检测端点匹配并避免重复坐标
- 执行简单的坐标比较:
pt1[0] === pt2[0] && pt1[1] === pt2[1]
线交点操作
概述
@turf/line-intersect 模块使用 Bentley-Ottmann 扫描线算法(通过 sweepline-intersections 库)查找两个线或多边形 features 之间的所有交点。
关键特性:
- 处理 LineString、MultiLineString、Polygon 和 MultiPolygon 输入
- 返回交点的 FeatureCollection of Points
- 使用高效的扫描线算法处理大型几何体
- 可选的
ignoreSelfIntersections参数用于单 feature 分析
Dependencies: packages/turf-line-intersect/package.json71-76
@turf/helpers- GeoJSON constructionsweepline-intersections- Bentley-Ottmann algorithm implementation
扫描线算法实现 O((n+k) log n) 时间复杂度,其中 n 是段数,k 是交点数,使其对复杂几何体高效。
线段操作
概述
@turf/line-segment 模块将任何线或多边形几何体转换为两顶点 LineString 段的 FeatureCollection。每个段表示原始几何体中的单条边。
功能:
- 处理 LineString、MultiLineString、Polygon、MultiPolygon 和混合 FeatureCollections
- 提取所有坐标对作为单独的 LineString features
- 在段 features 上保留原始 feature 属性
- 使用
@turf/meta迭代实用程序进行几何遍历
Use Cases:
- Preprocessing for spatial indexing (as in
line-split) - Analyzing individual edges of complex geometries
- Input for algorithms requiring segment-level processing
Dependencies: packages/turf-line-segment/package.json64-70
@turf/helpers- LineString creation@turf/meta- Coordinate iteration withsegmentEach@turf/invariant- Type validation
该模块使用 @turf/meta 中的 segmentEach 高效迭代嵌套几何体中的所有坐标对。
线分块操作
概述
@turf/line-chunk 模块根据指定距离将 LineString 分割为等长段。与在每个顶点分割的 line-segment 不同,line-chunk 创建具有一致测量长度的段。
Algorithm:
- Calculate total line length using
@turf/length - Determine number of chunks based on segment length
- Use
@turf/line-slice-alongto extract each chunk at measured distances - Return FeatureCollection of length-based segments
Parameters:
- Input: LineString or MultiLineString
segmentLength: Desired length of each chunkunits: Distance units (miles, kilometers, meters, etc.)reverse: Optional flag to chunk from end to start
Dependencies: packages/turf-line-chunk/package.json73-79
@turf/length- Total distance calculation@turf/line-slice-along- Extract line portion between distances@turf/meta- Geometry iteration
使用 RBush 的空间索引
线处理模块使用 rbush 进行高效的空间查询。R 树数据结构为在边界框内查找几何体提供 O(log n) 搜索性能。
集成模式
@turf/geojson-rbush 包装器:
- 为 rbush 提供 GeoJSON 特定接口
- 自动从几何体计算边界框
- 从查询返回 GeoJSON FeatureCollection
- 支持
load、insert、remove和search操作
在线分割中的使用:packages/turf-line-split/index.js1
import { geojsonRbush as rbush } from "@turf/geojson-rbush";空间索引实现了候选段的高效过滤:
- Load Phase: Insert all line segments into tree packages/turf-line-split/index.js84
- Query Phase: Search for segments intersecting splitter's bbox packages/turf-line-split/index.js88
- Dynamic Updates: Remove and re-insert modified segments packages/turf-line-split/index.js99-104
边界情况和精度处理
线处理操作必须处理几个几何边界情况:
端点匹配
当分割点完全匹配线端点时,不应分割线 packages/turf-line-split/index.js126-130:
if (
pointsEquals(startPoint, getCoord(splitter)) ||
pointsEquals(endPoint, getCoord(splitter))
)
return featureCollection([line]);这防止创建退化的单顶点 LineString。
坐标重复预防
在与分割点匹配的顶点处分割时,避免在输出中重复坐标 packages/turf-line-split/index.js159-161:
// Don't duplicate splitter coordinate (Issue #688)
if (pointsEquals(splitterCoords, currentCoords))
return [splitterCoords];浮点精度
分割器几何体在空间索引之前被截断到 7 位小数,以避免 rbush 中的精度相关问题 packages/turf-line-split/index.js42-44:
// remove excessive decimals from splitter
// to avoid possible approximation issues in rbush
var truncatedSplitter = truncate(splitter, { precision: 7 });这解决了 packages/turf-line-split/test.ts153-191 中报告的问题,其中微小的坐标差异导致不正确的空间查询。
空结果处理
当在搜索 bbox 中未找到段时,返回原始线不变 packages/turf-line-split/index.js141。这发生在分割点实际上不在线上时。
测试覆盖和已知问题
测试组织
测试装置按输入/输出对组织:
- 输入:packages/turf-line-split/test/in/ - 带有线和分割器 features 的 GeoJSON
- 输出:packages/turf-line-split/test/out/ - 带有彩色段的预期分割结果
测试用例涵盖:
- Basic scenarios: Point, MultiPoint, LineString, Polygon splitters
- Edge cases: Endpoints, vertices, precision issues
- Complex geometries: MultiLineString, MultiPolygon, polygons with holes
- Historical bugs: Issues #688, #852, #1075, #1232, #2288
历史问题
问题 #688 - 坐标重复 packages/turf-line-split/test.ts125-151
- 问题:顶点上的分割点创建了 3 顶点线而不是 2 顶点段
- 解决方案:当分割点匹配段端点时跳过重复坐标
问题 #852 - 浮点精度 packages/turf-line-split/test.ts153-191
- 问题:具有许多小数位的坐标导致 rbush 查询失败
- 解决方案:在索引之前将分割器截断到 7 位小数精度
问题 #1075 - 线上的多个点 packages/turf-line-split/test.ts206-218
- 问题:多个点的顺序分割失败
- 解决方案:具有适当 ID 管理的动态空间索引更新
问题 #1232 - 复杂多边形分割 packages/turf-line-split/test.ts220-305
- 问题:线在多边形边界交点处未正确分割
- 解决方案:使用
ignoreSelfIntersections标志改进交点计算
问题 #2288 - 波浪线 packages/turf-line-split/test.ts307-336
- 问题:具有许多顶点的线在多边形交点处未分割
- 解决方案:增强对多段交点场景的处理
性能特征
| 操作 | 时间复杂度 | 空间复杂度 | 注释 |
|---|---|---|---|
| 线分割(单点) | O(n log n) | O(n) | n = 段数;由 rbush 操作主导 |
| 线分割(k 个点) | O(k·n log n) | O(n) | k 个点的顺序处理 |
| 线交点 | O((n+i) log n) | O(n) | n = 段,i = 交点;Bentley-Ottmann |
| 线段 | O(n) | O(n) | n = 坐标对数量 |
| 线分块 | O(n·c) | O(c) | n = 段,c = 块数 |
优化技术:
- 空间索引:RBush 将候选段搜索从 O(n) 减少到 O(log n)
- 提前终止:端点检查避免不必要的处理 packages/turf-line-split/index.js126-130
- 单 Feature 优化:当仅存在一个候选时跳过距离计算 packages/turf-line-split/index.js189
- 扫描线算法:线交点使用高效的 Bentley-Ottmann 而不是暴力 O(n²)
相关模块
线处理操作与其他 Turf.js 模块集成:
Measurement Dependencies:
@turf/length- Total line length for chunking operations@turf/distance- Point-to-point distance calculations@turf/nearest-point-on-line- Find closest point on line to given coordinate
Transformation Operations:
@turf/line-slice- Extract line portion between two points@turf/line-slice-along- Extract line portion between two distances@turf/truncate- Reduce coordinate precision
Analysis Operations:
@turf/line-overlap- Find shared segments between two lines@turf/point-to-line-distance- Shortest distance from point to line@turf/nearest-point-to-line- Closest point feature to a line