经纬志
首页 / Turf.js / 教程

点线面之间的关系判断

先看结论

这类函数统一以 boolean 开头,返回 true 或 false。 语义看着直白,真正容易出错的是边界:落在多边形边线上的点算不算在内部, 不同函数的答案并不一致。

最后验证 2026-11-03 · Turf.js 7.x · 更新 2026-10-27 · 引用本文

按输入的几何组合选函数

函数输入组合回答的问题
booleanPointInPolygon点 + 面点是否在面内
booleanPointOnLine点 + 线点是否落在线段上
booleanContains面 + 点/线/面前者是否完全包含后者
booleanWithin点/线/面 + 面前者是否完全位于后者内部
booleanIntersects任意两种是否存在任何公共部分
booleanDisjoint任意两种是否完全没有公共部分
booleanTouches任意两种是否只有边界接触,内部不相交
booleanOverlap同类型是否部分重叠但不完全包含

点在面内:边界算内部

函数名在 7.x 里正式写法是 booleanPointInPolygon, pointInPolygon 是同一实现的别名。默认情况下, 落在边线或顶点上的点返回 true。 需要严格排除边界时传 ignoreBoundary: true。

var poly = turf.polygon([[[116.35, 39.86], [116.45, 39.86], [116.45, 39.94],
                          [116.35, 39.94], [116.35, 39.86]]]);

var onEdge = turf.point([116.35, 39.90]);

console.log(turf.booleanPointInPolygon(onEdge, poly));                          // true
console.log(turf.booleanPointInPolygon(onEdge, poly, { ignoreBoundary: true })); // false

判断范围时这个差异会带来实际后果:按行政边界统计站点数量, 边界上的点可能被相邻两个区各算一次。要么统一 ignoreBoundary: true, 要么在数据层面给每个点指定唯一归属。

面可以带洞,也可以是多面。带洞时落在洞里的点返回 false, 这部分由函数内部处理,不需要自己拆环。

包含与位于:一对反向关系

booleanContains(poly, point) 与 booleanWithin(point, poly) 在很多情况下答案相同, 但参数顺序固定:包含关系的「大」在前,「小」在后。 两者都要求「小」完全落在「大」内部,线只要有一个顶点在外, 就返回 false。

因此用 booleanWithin(line, poly) 判断一条道路是否完全在园区内, 结果通常偏严格:道路穿过边界一点点就会失败。需要「大部分在内」这种语义时, 自己按长度加权计算更合适。

相交、相离、接触

  • booleanIntersects 只要有任何公共部分就为 true,包括只贴着一个角。
  • booleanDisjoint 是它的取反,两者对同一输入必然一真一假。
  • booleanTouches 更严格:只有边界接触、内部不相交才为 true, 比如两个相邻的行政区块。
var x = turf.polygon([[[116.40, 39.88], [116.48, 39.88], [116.48, 39.96],
                      [116.40, 39.96], [116.40, 39.88]]]);

console.log(turf.booleanIntersects(poly, x));   // true,有重叠
console.log(turf.booleanDisjoint(poly, x));     // false
console.log(turf.booleanTouches(poly, x));      // false,重叠不在边界

批量判断怎么不卡

一万个点对一个面逐个调用,看起来是线性复杂度,实际开销主要在两件事: 每次调用都要遍历面的所有顶点,以及频繁构造 Feature 对象。 两个改动能显著降低耗时:

  • 先用外包矩形粗筛。点不在面的 bbox 内,可以直接判 false,不必进入多边形判断。
  • 面只读取一次,复用同一个引用;点用坐标数组循环,最后再包装成 Feature。
var box = turf.bbox(poly);

function inside(coords) {
  if (coords[0] < box[0] || coords[0] > box[2] ||
      coords[1] < box[1] || coords[1] > box[3]) return false;
  return turf.booleanPointInPolygon(turf.point(coords), poly);
}

var hits = points.filter(function (p) { return inside(p); });

更高数量级时,把面拆成网格索引,或者把判断放到后端与空间数据库里做。 前端 Turf 的定位是几十万次以内的交互式判断。

常见错误

用点在面内判断落在线上

点与线的关系要用 booleanPointOnLine,它还提供 ignoreEndPoint 选项来排除端点。反过来,用点线判断去处理面, 结果是 false 而不是报错,很容易被误读成「不相交」。

忽略坐标顺序

从后端拿到的坐标常是 [lat, lng]。面与点的顺序如果一边反了, 判断会稳定地返回 false,看起来像「数据没问题但永远不在范围内」。

拿细长面做包含判断

细长面(比如道路中心线两侧各 1 米形成的面)在浮点误差下容易出现 「点明明在图上却判 false」。把半径放大到米级以上,或者改用点到线距离判断。

引用本文

经纬志(2026)。《点线面之间的关系判断》。https://www.jingweizhi.com/turf/tutorial/relations.html(访问日期 2026-11-03)。