Atlaslog / Field Notes / Coordinates & projections
Field note · Coordinates & projections
Foreign coordinates encrypted too: 600 m cliff at the Shenzhen River
Quick answer
A GCJ-02 implementation without the outOfChina guard encrypts coordinates anywhere on Earth, so the mainland side of a border moves while the Hong Kong side does not. Tokyo shifts more than 400 m even though Japan is outside the GCJ-02 area.
Symptom
- A continuous WGS84 border line breaks at the Shenzhen River: the mainland side moves 606.6 m east while the Hong Kong side stays put.
- Tokyo 139.767125, 35.681236 shifts more than 400 m even though Japan is outside the GCJ-02 area.
- The jump appears only on the mainland side of the line, so the seam looks like missing data.
Checklist
- Convert a point that is clearly abroad (Tokyo, Seoul, Singapore) and check whether the output equals the input.
- Inspect the top of the function for a guard that returns the input when the point is outside China.
- Check whether the guard joins its four bounds with && instead of ||.
- Use the correct bounds: lon 72.004~137.8347, lat 0.8293~55.8271.
- Densify a cross-border line to one point every 100 m and look for a jump after conversion.
Fix
Restore the outOfChina guard at the top of the function with all four bounds joined by ||, or switch to gcoord, which ships the check; for cross-border projects render on a WGS84 basemap or convert the whole dataset uniformly.
Code
const before = [139.767125, 35.681236];
const after = wgs84ToGcj02(before[0], before[1]);
console.log(after); // [139.7718, 35.6809] 左右,偏了 400+ 米function outOfChina(lng, lat) {
return lng < 72.004 || lng > 137.8347 ||
lat < 0.8293 || lat > 55.8271;
}
function wgs84ToGcj02(lng, lat) {
if (outOfChina(lng, lat)) return [lng, lat]; // 原样返回
const dLat = transformLat(lng - 105.0, lat - 35.0);
const dLng = transformLng(lng - 105.0, lat - 35.0);
const radLat = lat / 180.0 * Math.PI;
let magic = Math.sin(radLat);
magic = 1 - 0.00669342162296594323 * magic * magic;
const sqrtMagic = Math.sqrt(magic);
const dLatFinal = (dLat * 180.0) / ((6335552.717000426 / (magic * sqrtMagic)) * Math.PI);
const dLngFinal = (dLng * 180.0) / ((6378245.0 / sqrtMagic * Math.cos(radLat)) * Math.PI);
return [lng + dLngFinal, lat + dLatFinal];
}
Watch out
- Writing the guard as a check on only the east and north edges, which leaves the west and south unprotected.
- Expecting the guard to remove the seam; it only stops foreign points from moving, and the 600 m discontinuity at the border remains.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). Foreign coordinates encrypted too: 600 m cliff at the Shenzhen River. https://www.jingweizhi.com/en/cookbook/gcj02-out-of-china.html (accessed 2026-11-03).