GIS数据GIS DATA

村界面积怎么算才准:三种公式的实测差距

技术专栏 · 数据处理 · 2026-10-16

村界数据最常见的用途是算面积:耕地占比、人居密度、补贴核算,第一步都是把每个村的面变成平方公里。算法选错,数字会以肉眼无感的方式错下去——本文拿三份不同纬度的真实村界包实测三种算法:广州从化(23.65°N)、江西铜鼓(28.55°N)、天津蓟州(40.05°N),共 1,342 个村、约 5,000 平方公里的面。同样的边界,Web 墨卡托坐标直接算,蓟州能「胖」出 70.2%。

三种算法差在哪

GeoJSON 里存的是经纬度角度,不是长度,算面积必须先过换算这一关,三种算法的区别就在换算方式。球面公式把边界面元当球面处理,是本文的基准;平面近似把经差乘以当地纬度的余弦系数、纬差乘以固定米数;Web 墨卡托平面则先把坐标投进墨卡托的米制世界再套鞋带公式——问题恰恰出在这:墨卡托为了保角度,把每个纬度带的地面都放大了 1/cosφ 倍,面积就被放大了 1/cos²φ 倍。

球面公式实现极短,十几行纯 JavaScript,本文 3 份包约 5,700 个环的计算秒级完成:

const R = 6371008.8;                        // 地球平均半径(米)
function sphereArea(ring) {                  // 单环,弧度鞋带
  let s = 0;
  for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
    const [lon1, lat1] = ring[j], [lon2, lat2] = ring[i];
    s += (lon2 - lon1) * Math.PI / 180
       * (2 + Math.sin(lat1 * Math.PI / 180) + Math.sin(lat2 * Math.PI / 180));
  }
  return Math.abs(s * R * R / 2);            // 平方米
}
// 面面积 = 外环面积 − 各内环(洞)面积;MultiPolygon 各面求和

实测:纬度越高,墨卡托越虚胖

三份包逐村计算再合计,结果如下:

样本村级面球面基准平面近似Web 墨卡托墨卡托虚胖
从化区(23.65°N)2701,932.0 km²1,923.2(−0.46%)2,308.7+19.5%
铜鼓县(28.55°N)971,554.1 km²1,547.6(−0.42%)2,021.1+30.0%
蓟州区(40.05°N)9751,558.0 km²1,543.9(−0.91%)2,651.5+70.2%

把三个实测点画到理论曲线 1/cos²φ − 1 上,严丝合缝:

Web 墨卡托面积膨胀的实测点与理论曲线:从化 +19.5%、铜鼓 +30.0%、蓟州 +70.2%
实线为理论膨胀 1/cos²φ−1,理论值 +19.2%/+29.7%/+70.7% 与实测 +19.5%/+30.0%/+70.2% 几乎重合。

两个锚点值得背下来:北纬 30 度约虚胖 30%,北纬 40 度约虚胖 70%。手头若有一份在墨卡托坐标上算出来的行政区划面积表,拿这两个数一除,虚胖程度立刻现形。

平面近似什么时候能用:看范围,也看单村

平面近似的总量表现比想象中好——三份包的合计误差都不到 1%,因为取当地余弦已经抵掉了大头。但它的误差在单村层面会放大:蓟州区 975 个村里,实测有单个村对球面基准偏差 11.3%——南北跨度大的村,境内纬度变化让「固定余弦」失真。所以结论分两层:县域总量做趋势分析,平面近似够用;单村级别的精细统计(补贴按亩、红线核算),回到球面公式,边际成本只是十几行代码。

落地清单:面积统计的三条军规

第一,永远别在 Web 墨卡托投影坐标上直接套鞋带公式——它给出的不是面积,是面积乘以 1/cos²φ 的虚数;前端显示归显示,统计前把坐标送回经纬度或等积坐标系。第二,数据库里 st_Area 一类函数要分清参数类型:PostGIS 对 geography 类型走球面椭球计算,对 geometry 类型按投影坐标平面计算,图层存成 3857 再量面积,误差与本文实测一致。第三,对外发布数字前抽三五个村,用第二种工具交叉复核一次,两位小数内的差异可以放过,多一位数就要回头查公式。数据源在村界数据 · 按市各页按市取用,村级码与面积的关联统计见《12位村级代码怎么读:逐段拆解与真数据验证》;算完面积要给面瘦身提速的,方法在《GeoJSON 太大?先抽点,再谈小数位》;分档配色的完整实测见《填色图配色一次做对:分档、选色与对比度》。

常见问题

用经纬度 GeoJSON 直接算面积,为什么会算错?
经纬度是角度不是长度,必须换算成米再算。换算方式决定了误差:把每一度经线的长度当作固定值乘以当地余弦,总量误差不足百分之一;但在 Web 墨卡托投影坐标上直接套鞋带公式,等于用被拉伸过的米数算面积,虚胖比例等于 1/cos²φ−1——本文三份村界包实测从化 +19.5%、铜鼓 +30.0%、蓟州 +70.2%,与理论曲线重合。
球面面积公式是哪个?需要装库吗?
球面上的鞋带公式(Chamberlain 与 Duquette 给 NASA 的形式):把环上相邻点的经纬度转成弧度,累加经度差乘以 2 加两端纬度正弦之和,再乘以地球半径的平方除以二。十几行纯 JavaScript 即可实现,本文 3 份包约 5,700 个环的面积计算秒级完成,不需要安装任何 GIS 库。
平面近似公式什么时候能用?
范围小、精度要求低时能用。实测三份包的村级面积合计,用「经差乘 111,320 乘当地余弦、纬差乘 110,540」的平面近似,总量误差只有 −0.46% 到 −0.91%。但单村的误差会因南北跨度放大——蓟州区实测有单村偏差 11.3%,所以县域总量可用近似,单村精细统计仍应回到球面公式。
Web 墨卡托的面积误差有规律吗?
有,且可预测:虚胖比例 = 1/cos²φ − 1,φ 为纬度。本文三份实测(纬度 23.65°、28.55°、40.05°)分别得到 +19.5%、+30.0%、+70.2%,与理论值 +19.2%、+29.7%、+70.7% 几乎重合。单村最大误差也从 22.7% 攀到 72%。记住 30° 纬度约 +30%、40° 约 +70% 两个锚点,足以快速估算手头数据的虚胖程度。
在 QGIS 或数据库里量面积也受这些误差影响吗?
取决于图层坐标系与量测函数。QGIS 对 WGS84 图层的测面积默认走椭球计算,结果可靠;PostGIS 里 st_Area 对 geography 类型走球面/椭球,对 geometry 类型则按投影坐标平面计算——若图层存的是 Web 墨卡托投影,误差与本文实测一致。原则就一条:统计面积时让坐标回到经纬度或等积坐标系。