☰
@turf/bbox-clip 实战指南:用 Turf.js 将 GeoJSON 要素精确裁剪到包围盒
2026/9/25 2:40:24 网站建设 项目流程
  • 数据分析

【免费下载链接】turf

A modular geospatial engine written in JavaScript and TypeScript

项目地址:https://gitcode.com/gh_mirrors/tu/turf
点击查看免费下载

bboxClip是 Turf.js 地理空间引擎中的一个轻量级裁剪模块,它接收一个LineString、MultiLineString、Polygon或MultiPolygon要素,以及一个[minX, minY, maxX, maxY]顺序的包围盒(BBox),将该要素严格裁剪到包围盒范围内。本文将以 packages/turf-bbox-clip/README.md 为骨架,结合 模块入口源码 与 底层裁剪算法,完整讲解bboxClip的 API 用法、四类几何体的处理逻辑、经典算法原理、边界行为与测试验证,帮助你在数据预处理、地图可视范围裁剪、空间索引加速等场景中直接落地使用。

bboxClip 函数概览

bboxClip接收一个要素和包围盒,将要素裁剪到包围盒内,底层基于 lineclip 算法实现。官方文档明确指出一个重要的注意事项:裁剪 Polygon 时可能产生退化边(degenerate edges),即裁剪结果可能包含自相交或无效环,使用前需要评估数据质量影响。

参数说明

参数类型说明
featureFeature<LineString \| MultiLineString \| Polygon \| MultiPolygon>需要裁剪到包围盒的要素(也支持直接传入 Geometry 对象)
bboxBBox按[minX, minY, maxX, maxY]顺序排列的范围

返回值:裁剪后的Feature<LineString | MultiLineString | Polygon | MultiPolygon>,并保留原要素的properties属性(从源码看,属性透传逻辑 会取feature.properties原样赋给输出要素)。

官方示例

var bbox = [0, 0, 10, 10]; var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]); var clipped = turf.bboxClip(poly, bbox); //addToMap var addToMap = [bbox, poly, clipped]

示例中,多边形poly的顶点[12, 8]超出了x <= 10的包围盒右边界,bboxClip会在右边界处求出交点并生成新的边界顶点,最终返回完全落在[0, 0, 10, 10]范围内的裁剪结果clipped。

安装与引入方式

该模块既可以单独安装,也可以作为@turf/turf全家桶的一部分使用。

单独安装(推荐,按需引入)

$ npm install @turf/bbox-clip

安装后在 ESM 项目中引入:

import { bboxClip } from "@turf/bbox-clip";

也可以使用默认导出:

import bboxClip from "@turf/bbox-clip";

从 package.json 可以看到,该包声明为"type": "module",通过exports字段将./dist/index.js暴露为默认入口,并标记"sideEffects": false,可被打包器安全地 tree-shaking。

安装全家桶

$ npm install @turf/turf

安装后通过turf.bboxClip(poly, bbox)调用,即文档示例中的使用方式。

源码级实现剖析

bboxClip的核心实现位于 packages/turf-bbox-clip/index.ts,整体流程非常清晰:

  1. 通过getGeom(feature)(来自@turf/invariant)提取几何对象,因此传入 Feature 或纯 Geometry 对象均可;
  2. 读取几何类型与properties;
  3. 按类型分发到不同的裁剪逻辑:
    • LineString/MultiLineString→ 逐条调用lineclip
    • Polygon→ 调用clipPolygon
    • MultiPolygon→ 对每个 Polygon 分别调用clipPolygon
    • 其他类型 → 抛出geometry <type> not supported错误。

线的裁剪:按结果条数决定返回类型

对于线要素,源码先统一成"多条线"的形式(LineString会被包一层数组),再逐条执行lineclip:

if (lines.length === 1) { return lineString(lines[0], properties); } return multiLineString(lines, properties);

也就是说:裁剪后如果只剩一条线段,返回LineString;若产生多条不相连的线段,则返回MultiLineString。当一条长线横穿包围盒多次(例如 test/in/linestring.geojson 中的跨区域线状数据),bboxClip会自动把落在窗口内的多段线段组装成多线要素。

面的裁剪:闭合环并过滤退化环

多边形裁剪由内部函数clipPolygon完成,逐环调用polygonclip后还有两个关键的后处理步骤:

  1. 闭合处理:若裁剪结果的首尾点不一致,则把首点追加到末尾,保证环闭合;
  2. 退化过滤:仅当裁剪后的环点数>= 4时才保留(clipped.length >= 4),从而剔除被包围盒完全裁掉或退化成线段的无效环。

这两条规则正对应文档中"裁剪 Polygon 可能产生退化边"的提示——算法本身不会做拓扑修复,如果需要干净的多边形拓扑,建议裁剪后配合 Turf 的turf-rewind、turf-clean-coords等模块做后处理。

底层裁剪算法:两种经典计算机图形学算法

裁剪逻辑并非 Turf 自研,而是将 mapbox/lineclip 的算法内联进了 packages/turf-bbox-clip/lib/lineclip.ts。理解这两种算法有助于把握bboxClip的性能与边界行为。

Cohen-Sutherland 线裁剪(lineclip)

lineclip是经典的 Cohen-Sutherland 线段裁剪算法,但被优化为直接处理整条折线(polyline)而非逐段处理,避免了对相邻线段共享端点的重复计算。

其核心是bitCode函数:将点相对于包围盒的位置编码为一个 4 位二进制码,位 1 表示左侧、位 2 表示右侧、位 4 表示下侧、位 8 表示上侧:

left mid right top 1001 1000 1010 mid 0001 0000 0010 bottom 0101 0100 0110

对每个线段端点对(a, b):

  • codeA | codeB === 0:两端都在窗口内,直接接受;
  • codeA & codeB !== 0:两端同在窗口外的某一侧,平凡拒绝;
  • 否则沿裁剪边求交点(intersect函数按位运算插值出与左/右/下/上四条边的交点),迭代直到落入上述两种情况。

intersect使用线性插值公式计算线段与包围盒四边的交点,例如右边界(edge & 2):

[bbox[2], a[1] + ((b[1] - a[1]) * (bbox[2] - a[0])) / (b[0] - a[0])]

由于只有纯算术运算(比较、位运算、一次除法和乘法),该算法非常高效,适合对海量线要素做批量裁剪。

Sutherland-Hodgeman 多边形裁剪(polygonclip)

polygonclip采用 Sutherland-Hodgeman 算法:依次用包围盒的四条边(左、右、下、上)对多边形逐边裁剪,每轮遍历所有顶点,判断每个顶点相对当前裁剪边的内外状态,并在状态切换处插入交点。源码中以edge = 1, 2, 4, 8位掩码遍历四边,inside = !(bitCode(p, bbox) & edge)判断顶点是否在该边内侧。

该算法对凸多边形和凹多边形都能正确处理,是图形学教材中的标准实现。

边界行为与测试验证

仓库在 packages/turf-bbox-clip/test.ts 中用 tape 编写了完整的验证用例,覆盖了正常裁剪与异常输入两类场景。

正常裁剪:fixture 对比测试

测试读取 test/in 目录 下的 8 个 GeoJSON fixture,每个 fixture 是包含两个要素的 FeatureCollection:第一个为待裁剪要素,第二个用于通过@turf/bbox计算裁剪框。裁剪结果与test/out中预生成的期望结果逐字节对比(t.deepEquals)。

fixture 覆盖了全部四类几何形态:

fixture几何类型测试要点
linestring-single-lineLineString单条线全部落在框内
linestringLineString长线多次进出窗口
multi-linestringMultiLineString多线同时裁剪
polygonPolygon普通多边形裁剪
polygon-holesPolygon带洞多边形裁剪
polygon-crossing-holePolygon环与洞同时跨越边界
polygon-point-intersectionPolygon顶点恰好落在边界上
multi-polygonMultiPolygon多面分别裁剪

其中polygon-crossing-hole是极具代表性的用例:当外环与内洞同时被包围盒切割时,算法必须分别独立裁剪两个环,并正确处理洞与外部区域的包含关系。对这类复杂用例,bboxClip的裁剪结果完全取决于polygonclip对每个环独立处理后的组合,因此输出几何的合法性(如洞必须位于外环内部)需要使用者自行校验。

异常输入:主动抛错

测试明确验证了两类异常输入会抛出错误:

test("turf-bbox-clip -- throws", (t) => { t.throws( () => bboxClip(point([5, 10]), [-180, -90, 180, 90]), /geometry Point not supported/ ); t.end(); }); test("turf-bbox-clip -- null geometries", (t) => { t.throws( () => bboxClip(feature(null), [-180, -90, 180, 90]), "coords must be GeoJSON Feature, Geometry Object or an Array" ); t.end(); });
  • Point等非线面类型:抛出geometry Point not supported。bboxClip不支持点要素,若需求是裁剪点集,应改用其他空间查询手段(如turf-boolean-point-in-polygon过滤);
  • null几何:抛出coords must be GeoJSON Feature, Geometry Object or an Array,该错误由@turf/invariant的getGeom抛出。

这提醒我们:调用前应先判断要素类型,或用try/catch兜底,避免线上环境崩溃。

性能基准

bench.ts 内置了基于 benchmark.js 的基准测试,对 7 类 fixture 逐一压测,注释中记录了各场景的吞吐量(如linestring-single-line约百万级 ops/sec、polygon约两万级 ops/sec,具体数值随运行环境波动)。可以看出,线要素的裁剪成本显著低于多边形,这与 Cohen-Sutherland 逐点线性遍历的特性一致。

完整可运行示例

下面给出一个 Node.js(ESM)环境下的完整示例,演示从构造要素到输出裁剪结果的完整链路:

import { bboxClip } from "@turf/bbox-clip"; import { polygon, lineString, featureCollection } from "@turf/helpers"; // 1. 定义一个跨越包围盒边界的多边形 const poly = polygon([ [ [2, 2], [8, 4], [12, 8], [3, 7], [2, 2], ], ]); // 2. 定义裁剪范围 [minX, minY, maxX, maxY] const bbox = [0, 0, 10, 10]; // 3. 执行裁剪 const clipped = bboxClip(poly, bbox); console.log(clipped.geometry.type); // "Polygon" console.log(JSON.stringify(clipped.geometry.coordinates, null, 2)); // 输出顶点中不再存在 x > 10 或 y > 10 的点,且环已闭合 // 4. 线要素同样适用:线穿过窗口时返回 MultiLineString const line = lineString([ [0, 5], [5, 5], [10, 5], [15, 5], ]); const clippedLine = bboxClip(line, bbox); console.log(clippedLine.geometry.type); // "LineString"

典型应用场景

  • 地图可视范围裁剪:在渲染超大范围线面数据时,先用当前视野的 bbox 裁剪要素,减少传给渲染引擎的顶点数量,降低绘制开销;
  • 空间索引预处理:为 R-tree(如@turf/geojson-rbush)入库前,把跨越索引瓦片边界的要素裁剪到瓦片 bbox 内,保证索引查询的正确性;
  • 数据分块与切片:将河流、行政区等大要素按网格 bbox 切分,便于分布式存储或按需加载;
  • 与 Turf 管线组合:裁剪后接@turf/clean-coords清理坐标、@turf/rewind统一环方向、@turf/boolean-valid校验拓扑,可构建稳健的预处理流水线。

小结

bboxClip用两个经典图形学算法(Cohen-Sutherland 与 Sutherland-Hodgeman)为 Turf 生态提供了高性能的包围盒裁剪能力,支持四类线面几何、自动完成多边形环闭合与退化过滤,并通过 测试套件 覆盖了带洞多边形、边界交点等关键边界情况。使用时只需牢记两点:只支持线/面类型(Point 会抛错)、多边形裁剪可能产生退化边(建议搭配拓扑清理模块使用),即可在数据预处理管线中稳定落地。

  • 数据分析

【免费下载链接】turf

A modular geospatial engine written in JavaScript and TypeScript

项目地址:https://gitcode.com/gh_mirrors/tu/turf
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询