南半球 UTM 少了 1000 万假北,悉尼的 y 变成负数
同一份投影代码,北半球的点正常,南半球的点 y 全是负的,排序时全跑到最前面。
现象
悉尼歌剧院 151.2093, -33.8688。
按 UTM 56 带南半球(EPSG:32756)投影,正确结果应是
x = 334300, y = 6252000 左右。
实际代码给出 y = -3748000,与正确值差 1000 万米。
写入 numeric(9,2) 或整型字段时,负值还常常触发约束报错
value out of range,或者被存成 0。
原因
UTM 为了不让南半球的 y 出现负值,规定南半球加 false northing = 10000000 米,
使赤道对应的 y 等于 10000000。北半球的 false northing 是 0。
+proj=utm +zone=56 默认按北半球处理,必须显式加 +south。
只改 EPSG 码但不改 PROJ 字符串,或者自定义定义时漏了 +south,
就会得到负的 y。
| EPSG | 名称 | false northing | 悉尼示例 y |
|---|---|---|---|
| 32656 | WGS84 / UTM 56N | 0 | -3748000(错用) |
| 32756 | WGS84 / UTM 56S | 10000000 | 6252000 |
排查过程
- 看纬度符号与 EPSG 的半球后缀是否一致:南纬必须用 327xx。
- 看 y 是否为负。UTM 的 y 在合法作业区内应在
0~10000000。 - 检查自定义 PROJ 字符串里有没有
+south。 - 用同一经度的北半球点做对照,若北半球正常南半球异常,就是半球参数问题。
// 错误的定义:缺 +south
const bad = '+proj=utm +zone=56 +datum=WGS84 +units=m +no_defs';
proj4.defs('UTM56_BAD', bad);
proj4('EPSG:4326', 'UTM56_BAD', [151.2093, -33.8688]);
// => [334300, -3748000]
// 正确
proj4('EPSG:4326', 'EPSG:32756', [151.2093, -33.8688]);
// => [334300, 6252000]
解决方案
南半球用 327xx,自定义定义加 +south。
数据库字段改为有符号且留足余量。
// 显式定义南半球 56 带
proj4.defs('EPSG:32756',
'+proj=utm +zone=56 +south +datum=WGS84 +units=m +no_defs');
-- 字段至少要容纳 0~10000000 的 y
ALTER TABLE survey_pt
ALTER COLUMN y TYPE numeric(12,3); -- 原来 numeric(9,2) 最大 9999999.99
验证
悉尼点投影后 y 应为 6252000 左右,x 在 334300 附近;
反投影回经纬度应恢复 151.2093, -33.8688。
const xy = proj4('EPSG:4326', 'EPSG:32756', [151.2093, -33.8688]);
console.assert(xy[1] > 6000000 && xy[1] < 6500000, 'y 仍不在南半球合法区间');
const ll = proj4('EPSG:32756', 'EPSG:4326', xy);
console.assert(Math.abs(ll[0] - 151.2093) < 1e-4, '回算经度不对');
适用版本
| 工具 | 版本 | 说明 |
|---|---|---|
| proj4js | 2.9 及以上 | +south 必须显式声明 |
| GeoServer | 2.20 及以上 | 用 EPSG:327xx 即自动带 false northing |
| PostGIS | 3.x | ST_Transform(geom, 32756) 语义正确 |
经纬志(2026)。《南半球 UTM 少了 1000 万假北,悉尼的 y 变成负数》。https://www.jingweizhi.com/cookbook/utm-south-false-northing.html(访问日期 2026-11-03)。