Skip to content

线处理

目的和范围

本文档介绍 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 几何体:

ModulePackagePrimary FunctionKey Dependencies
Line Split@turf/line-splitSplits a LineString by another feature@turf/geojson-rbush, @turf/line-intersect, @turf/line-segment
Line Intersect@turf/line-intersectFinds intersection points between linessweepline-intersections
Line Segment@turf/line-segmentCreates segments from line coordinates@turf/meta
Line Chunk@turf/line-chunkDivides lines into distance-based chunks@turf/length, @turf/line-slice-along
Line Overlap@turf/line-overlapFinds overlapping segments@turf/line-segment
Line Offset@turf/line-offsetOffsets lines perpendicular to direction@turf/meta

线处理模块依赖

SVG
100%

线分割操作

概述

lineSplit 函数在与分割器 feature 的交点处将 LineString 分割为多个段。分割器可以是 Point、MultiPoint、LineString、MultiLineString、Polygon 或 MultiPolygon。

Entry Point: packages/turf-line-split/index.js29-62

输入验证和类型处理

SVG
100%

该函数执行类型检查以确保 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

单点分割算法

SVG
100%

单点分割算法使用 R 树空间索引 (rbush) 进行高效段查找。它遵循以下步骤:

  1. 端点处理:如果分割点完全匹配任一端点,则返回原始线不变 packages/turf-line-split/index.js126-130
  2. 分段:使用 lineSegment 将线转换为单独的两顶点段 packages/turf-line-split/index.js134
  3. 空间索引:将段加载到 rbush 树中以进行快速空间查询 packages/turf-line-split/index.js133-135
  4. 邻近搜索:搜索点边界框内的段 packages/turf-line-split/index.js138
  5. 最近匹配:当存在多个候选时,使用 nearestPointOnLine 查找最近的段 packages/turf-line-split/index.js144
  6. 坐标累积:使用 featureReduce 迭代段,累积坐标直到到达分割段 packages/turf-line-split/index.js148-170
  7. 分割构建:在交点处创建两个 LineString,避免坐标重复 packages/turf-line-split/index.js159-161

多点分割算法

SVG
100%

多点分割算法在顺序处理每个点时维护动态空间索引:

  1. 初始化:创建一个空的 rbush 树来跟踪中间线段 packages/turf-line-split/index.js74
  2. 第一个点:分割原始线并将结果连同唯一 ID 加载到树中 packages/turf-line-split/index.js78-84
  3. 后续点:对于每个剩余点:

该算法为 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 construction
  • sweepline-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 with segmentEach
  • @turf/invariant - Type validation

该模块使用 @turf/meta 中的 segmentEach 高效迭代嵌套几何体中的所有坐标对。

线分块操作

概述

@turf/line-chunk 模块根据指定距离将 LineString 分割为等长段。与在每个顶点分割的 line-segment 不同,line-chunk 创建具有一致测量长度的段。

Algorithm:

  1. Calculate total line length using @turf/length
  2. Determine number of chunks based on segment length
  3. Use @turf/line-slice-along to extract each chunk at measured distances
  4. Return FeatureCollection of length-based segments

Parameters:

  • Input: LineString or MultiLineString
  • segmentLength: Desired length of each chunk
  • units: 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) 搜索性能。

集成模式

SVG
100%

@turf/geojson-rbush 包装器

  • 为 rbush 提供 GeoJSON 特定接口
  • 自动从几何体计算边界框
  • 从查询返回 GeoJSON FeatureCollection
  • 支持 loadinsertremovesearch 操作

在线分割中的使用packages/turf-line-split/index.js1

import { geojsonRbush as rbush } from "@turf/geojson-rbush";

空间索引实现了候选段的高效过滤:

  1. Load Phase: Insert all line segments into tree packages/turf-line-split/index.js84
  2. Query Phase: Search for segments intersecting splitter's bbox packages/turf-line-split/index.js88
  3. 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。这发生在分割点实际上不在线上时。

测试覆盖和已知问题

测试组织

测试装置按输入/输出对组织:

测试用例涵盖:

  • 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 = 块数

优化技术

相关模块

线处理操作与其他 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

对于坐标处理和变换,请参见 坐标处理。对于使用基于线的 features 的聚类和空间分析,请参见 空间分析