China Map With Google and Autonavi

These days I am investigating the map used in Hongkong and China mainland since it uses the different standard according to Chinese law. There are some several interesting points can be discussed here:

Chinese Coordinate System GCJ-02 vs GPS WGS-84

Today most of the world uses the World Geodetic System WGS-84, where 84 is the latest vision of the standard applied in 1984. It's definitely created by US and used by GPS, and apparently google uses this standard for its map.

However, Chinese regulators added an obfuscation algorithm to the WGS-84, which would add an offset to the coordinate to protect its geographic data. Since the standard is created by (Chinese: 国测局; pinyin: guó-cè-jú) in 2002, so it's called GCJ-02, or Mars coordinates. And according to Chinese law, there is no official API to convert GCJ-02 to WGS-84.

So conversation between GCJ-02 and WGS-84 is illegal to be published, it has to be approved by SBSM. However, we still can find some open-source implementation, here is the js one. I won't say it's 100% accurate, but enough for the everyday usage.

To simplify the work, we would not use Baidu map since it has its own offset algorithm to distinguish its geodata, instead Autonavi/amap/高德 is a good alternative. It provides every good geo data and layer, also is my first choice when I am in China. Currently, instead of using its official web API, we only need its layer data, which can be achieved by its url directly with leaflet, such as for map type street map/roadmap:

 1{
 2  roadmap: {
 3    url: '//webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
 4    attribution:
 5      "&copy; <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors",
 6    subdomains: ['1', '2', '3', '4'],
 7  },
 8  satellite: {
 9    url: '//webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
10    attribution:
11      "&copy; <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors",
12    subdomains: ['1', '2', '3', '4'],
13  },
14}

It looks like this:

Autonavi roadmap within leaflet

HongKong and Macau in Google Map

What about Hongkong and Macau? As China applies the One country, two systems in Hongkong and Macau, so google map is available in these two places. But, the standards applied by Google and Chinese map provider are different. Gaode states that GCJ-02 would be applied in Hongkong and Macau, while WGS-84 is used by google map. It means when we switch the map provider in Hongkong/Macau, we need to convert the standard.

GCJ-02 in Google Map

There is one exception for Google map, according to Wikipedia:

Google has worked with Chinese location-based service provider AutoNavi since 2006 to source its maps in China.[44] Google uses GCJ-02 data for the street map, but does not shift the satellite imagery layer, which continues to use WGS-84 coordinates,[45] with the benefit that WGS-84 positions can still be overlaid correctly on the satellite image (but not the street map). Google Earth also uses WGS-84 to display the satellite imagery.

The consequence would be no conversation is required if the coordinate(s) are created based on the google's street map (roadmap), such as Point of interest or Geofences. And also the map type switching also needs to consider the conversion.

And for the hybrid type map, it would be combined by the street map with GCJ and satellite with WGS:

Google hybrid map in China Mainland

How to check if a coordinate is in an closed region

Now we have one coordinate already, how could we check if it's inside of Mainland, Hongkong or Macau? One way would be calling map provider's API, the answer would be accurate, but the down side is it's asynchronous, which would increase the complexity of the codes. Is it possible to check the coordinate synchronously?

Yes, we have. If we can get the coordinates of these regions' borders with the closed polygon format in advance, we can check if the given coordinate is inside the given polygon.

GeoJson data

We can find these places' geojson format data in GitHub: China, Hongkong and Macau. To check the shape of these regions, we can copy/paste this json file to the Geojson and check the result.

Pre-handling

Before we calculate the geojson data, we need to pre handle the data. Since WGS is also applied in Taiwan, so we need to remove this region from our China geojson data. Find the word 台湾省 in the file and remove the whole province data from the file.

Extract the outermost border coordinates

Now we have all geojson data for these regions, but what we need is only the coordinates of the border. All the internal coordinates should be removed. To achieve this, we can use a python script (with help of Microsoft copilot) to convert them:

 1import json
 2from shapely.geometry import Polygon, mapping
 3from shapely.ops import unary_union
 4
 5# Load GeoJSON file
 6with open('GEOJSON_FILE', 'r') as f:
 7    data = json.load(f)
 8
 9# Extract Polygons and convert them to Shapely objects
10polygons = []
11for feature in data['features']:
12    geometry = feature['geometry']
13    if geometry['type'] == 'Polygon':
14        polygons.append(Polygon(geometry['coordinates'][0]))
15
16# Compute the union of all polygons
17union = unary_union(polygons)
18
19# Prepare the GeoJSON data
20geojson_data = {
21    "type": "Feature",
22    "properties": {},
23    "geometry": mapping(union)
24}
25
26# Save the GeoJSON data to a file
27with open('output.geojson', 'w') as f:
28    json.dump(geojson_data, f)

Replace GEOJSON_FILE with your real geojson data file. The result should be in the generated file output.geojson. To verify the generated data, we can copy/paste it to the Geojson. Sometimes the generated polygon is not perfect, we can clean it simply by hand.

Checking if a coordinate is inside of a polygon

Install the two @turf subset packages with pnpm, (you can use your own package manager):

1pnpm i @turf/boolean-point-in-polygon @turf/helpers

Then the method isPointInPolygon can be used to check if the coordinate is inside of the given polygon.

 1import * as turf from '@turf/helpers'
 2import booleanPointInPolygon from '@turf/boolean-point-in-polygon'
 3
 4type LatLng = {
 5  lat: number
 6  lng: number
 7}
 8
 9export function isPointInPolygon(
10  { lat, lng }: LatLng,
11  polygon: Array<[lng: number, lat: number]>,
12) {
13  const point = turf.point([lng, lat])
14
15  // Define your polygon
16  const polygonTurf = turf.polygon([polygon])
17
18  // Check if the point is inside the polygon
19  return booleanPointInPolygon(point, polygonTurf)
20}

NOTE: There is one thing we need to be careful. According to the turf:

Use Turf

The coordinate sent to turf has to be WGS standard.

China Mainland is swallowed by HongKong in the border

There is one more thing we need to consider when using google map in China mainland. Because of two coordinate systems in Mainland and Hongkong/Macau, the border between them is twisted:

The border in Google map:

China Mainland Border is swallowed by Hongkong

The border in Autonavi:

The correct mainland and hongkong border

You can see the Mainland border is swallowed by HongKong, which would cause the overlapping of the maps and confusion of the point or path lines above it.

comments powered by Disqus