Geographic Coordinate System Transformations

Spatial Reference Systems

WGS-84: The standard geodetic reference system used globally. It serves as the foundation for GPS and is adopted by international mapping platforms like Google Maps.

GCJ-02: Often referred to as the Mars coordinate system. It is an obfuscated version of WGS-84 implemented for regulatory compliance, utilized by services such as Amap (Gaode) and Alibaba.

BD-09: The Baidu coordinate system. It adds a further layer of encryption on top of the GCJ-02 standard, primarily used by Baidu Maps.

Coordinate Conversion Implementations

Reverting GCJ-02 to WGS-84

Because the GCJ-02 system applies an offset to WGS-84, reversing this process involves calculating the applied offset and subtracting it from the given GCJ-02 coordinates. This approach uses a symmetrical deduction to approximate the original values.

import math

EARTH_RADIUS = 6378245.0
ECCENTRICITY_SQ = 0.00669342162296594323
PI = math.pi

def is_offshore(longitude, latitude):
    return not (72.004 <= longitude <= 137.8347 and 0.8293 <= latitude <= 55.8271)

def calc_latitude_delta(x, y):
    val = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y**2 + 0.1 * x * y + 0.2 * math.sqrt(abs(x))
    val += (20.0 * math.sin(6.0 * x * PI) + 20.0 * math.sin(2.0 * x * PI)) * 2.0 / 3.0
    val += (20.0 * math.sin(y * PI) + 40.0 * math.sin(y / 3.0 * PI)) * 2.0 / 3.0
    val += (160.0 * math.sin(y / 12.0 * PI) + 320 * math.sin(y * PI / 30.0)) * 2.0 / 3.0
    return val

def calc_longitude_delta(x, y):
    val = 300.0 + x + 2.0 * y + 0.1 * x**2 + 0.1 * x * y + 0.1 * math.sqrt(abs(x))
    val += (20.0 * math.sin(6.0 * x * PI) + 20.0 * math.sin(2.0 * x * PI)) * 2.0 / 3.0
    val += (20.0 * math.sin(x * PI) + 40.0 * math.sin(x / 3.0 * PI)) * 2.0 / 3.0
    val += (150.0 * math.sin(x / 12.0 * PI) + 300.0 * math.sin(x / 30.0 * PI)) * 2.0 / 3.0
    return val

def revert_gcj02_to_wgs84(gcj_lon, gcj_lat):
    if is_offshore(gcj_lon, gcj_lat):
        return gcj_lon, gcj_lat
        
    dlat = calc_latitude_delta(gcj_lon - 105.0, gcj_lat - 35.0)
    dlon = calc_longitude_delta(gcj_lon - 105.0, gcj_lat - 35.0)
    
    rad_lat = gcj_lat / 180.0 * PI
    sin_lat = math.sin(rad_lat)
    magic = 1 - ECCENTRICITY_SQ * sin_lat**2
    sqrt_magic = math.sqrt(magic)
    
    dlat = (dlat * 180.0) / ((EARTH_RADIUS * (1 - ECCENTRICITY_SQ)) / (magic * sqrt_magic) * PI)
    dlon = (dlon * 180.0) / (EARTH_RADIUS / sqrt_magic * math.cos(rad_lat) * PI)
    
    offset_lat = gcj_lat + dlat
    offset_lon = gcj_lon + dlon
    
    wgs_lon = 2 * gcj_lon - offset_lon
    wgs_lat = 2 * gcj_lat - offset_lat
    
    return wgs_lon, wgs_lat

Shifting WGS-84 to GCJ-02

Converting standard GPS coordinates to the GCJ-02 system requires computing latitude and longitude offsets based on a non-linear mathematical model. Since the exact GCJ-02 obfuscation algorithm is not publicly documented, these computations are reverse-engineered approximations and may exhibit minor deviations in certain edge cases.

def shift_wgs84_to_gcj02(wgs_lon, wgs_lat):
    if is_offshore(wgs_lon, wgs_lat):
        return wgs_lon, wgs_lat
        
    dlat = calc_latitude_delta(wgs_lon - 105.0, wgs_lat - 35.0)
    dlon = calc_longitude_delta(wgs_lon - 105.0, wgs_lat - 35.0)
    
    rad_lat = wgs_lat / 180.0 * PI
    sin_lat = math.sin(rad_lat)
    magic = 1 - ECCENTRICITY_SQ * sin_lat**2
    sqrt_magic = math.sqrt(magic)
    
    dlat = (dlat * 180.0) / ((EARTH_RADIUS * (1 - ECCENTRICITY_SQ)) / (magic * sqrt_magic) * PI)
    dlon = (dlon * 180.0) / (EARTH_RADIUS / sqrt_magic * math.cos(rad_lat) * PI)
    
    gcj_lon = wgs_lon + dlon
    gcj_lat = wgs_lat + dlat
    
    return gcj_lon, gcj_lat

Tags: geospatial Coordinate Transformation WGS84 GCJ02

Posted on Sat, 23 May 2026 21:24:11 +0000 by Allen4172