村面标注点放哪才准:三种质心算法实测
技术专栏 · 数据可视化 · 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,816 | 94.6% | 95.0% | 97.9% |
| 蓟州区(山地) | 974 | 88.9% | 91.8% | 94.7% |
| 从化区(丘陵水网) | 270 | 90.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 算法是其常用实现,代价是要做二分加距离场计算。常规村界标注用面积加权质心即可,只在标注挤到面外时升级。