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_latShifting 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