GIS数据GIS DATA

村面标注点放哪才准:三种质心算法实测

技术专栏 · 数据可视化 · 2026-10-22

给村级面配标注点,是地图产品里最常见的隐性需求:点位标签、定位锚点、专题图配点都用它。最省事的写法是取包围盒中心,最常被推荐的是面积加权质心——两者差多少?本站拿成都、蓟州、从化三份村界包共 4,060 个村级面实测:包围盒中心最高 11.1% 掉在村外,面积加权质心稳在 94.7% 到 97.9% 的内点率。数字之外,这篇还附一个真实的反例村,三种算法的三颗点摆在同一张图上。

三种算法,三种性格

包围盒中心是很多人无意中在用的写法——取坐标极值的平均值。它的致命伤是只看包围盒不看形状:弯月形、L 形、带大缺口的多边形,中心点天然落在缺口里。顶点均值把每个顶点当等权重,实现也简单,但顶点在边界弯曲处密、直线段上疏,密度偏置会把质心拽向细节多的一侧。面积加权质心按有向面积求质心,洞自动按负面积扣除,是三者中唯一显式利用「面」信息的算法:

function polyCentroid(rings) {          // 外环正、内环(洞)负,自动扣洞
  let A = 0, cx = 0, cy = 0;
  for (const r of rings) {
    let a = 0, px = 0, py = 0;
    for (let i = 0, j = r.length - 1; i < r.length; j = i++) {
      const f = r[j][0] * r[i][1] - r[i][0] * r[j][1];
      a += f; px += (r[j][0] + r[i][0]) * f; py += (r[j][1] + r[i][1]) * f;
    }
    a /= 2; A += a; cx += px / (6 * a) * a; cy += py / (6 * a) * a;
  }
  return [cx / A, cy / A];              // 有向面积加权合成
}

实测:4,060 个面的内点率

每种算法给每个村级面生成一个点,再用射线法判定「这个点是否落在本村自己的面里」(MultiPolygon 摊环、洞按扣减),三份包的结果:

样本村级面包围盒中心顶点均值面积加权质心
成都市(平原)2,81694.6%95.0%97.9%
蓟州区(山地)97488.9%91.8%94.7%
从化区(丘陵水网)27090.7%94.1%95.6%

反例村的形状最有说服力:同一个成都平原上的村,936 个顶点、轮廓弯折多段,包围盒中心明晃晃掉在村外的缺口里,顶点均值也偏出一侧,只有面积加权质心安安稳稳待在村内——三种算法的性格差异一张图看尽。

三种质心算法的内点率对比与反例村三点标注图
左:反例村三点标注(包围盒中心在村外)· 右:三份包 × 三算法内点率,面积加权质心全面占优。

为什么质心也会偏,怎么办

面积加权质心并非万能:弯月形与环形面的质心会落进空腔。实测剩下的 2.1% 到 5.3% 未命中里,大部分就是这类形状。兜底的写法是「质心失败就用面内最近点」:从质心向面内方向外推,或直接用 polylabel(不可入点)算法——在面内找距边界最远的点,对细长破碎面效果最好,代价是二分加距离场的计算量。常规村界标注不必升级:面积加权质心加一次自检,未命中再回退,代码量与效果刚好平衡。

标注点之外,村界数据还有不少同类小坑:面积公式选错会虚胖三成(见《村界面积怎么算才准:三种公式的实测差距》),MultiPolygon 层级处理不当会静默零命中(见《村界里的飞地与洞:MultiPolygon 解剖实测》),把这三篇与本文凑成一套「村界数据处理的坑位手册」正好。本文实测的村界包出自本站村界商品线,按市在村界数据 · 按市页取用。

常见问题

村面标注点为什么不能用包围盒中心?
包围盒中心只保证在包围盒内,不保证在面内。实测 4,060 个村级面:成都 94.6% 的包围盒中心落在自己村内,蓟州只有 88.9%——每 9 到 11 个村就有一个标注点掉在村外,弯月形、L 形、带缺口的多边形最容易中招。
面积加权质心就一定在面内吗?
不绝对,但实测最稳:成都 97.9%、蓟州 94.7%、从化 95.6% 的面积加权质心落在自己村内,三份包全部优于包围盒中心与顶点均值。弯月形与环形面仍可能让质心落在面外的空腔里,这类极少数面可回退到「取面内最近点」兜底。
顶点均值质心为什么偏差大?
顶点均值把每个顶点当等权重的点,而村界顶点在边界弯曲处天然密、直线段上天然疏,密度偏置会把质心拽向细节丰富的一侧。实测其内点率(95%–94.1%)略优于包围盒中心,但整体仍劣于面积加权质心,且偏差方向不可控。
带洞的面怎么算标注点?
按有向面积处理:外环面积取正、内环(洞)面积取负,质心按有向面积加权合成——洞在公式里自动被扣除。点位生成后仍要做一次射线法自检,落在洞里的点沿质心到外环质心的连线外推,直到进入有效区域。
标注点还有更讲究的放法吗?
有。地图学里的「不可入点」(pole of inaccessibility):在面内找距边界最远的点,对细长、破碎的多边形效果最好,polylabel 算法是其常用实现,代价是要做二分加距离场计算。常规村界标注用面积加权质心即可,只在标注挤到面外时升级。