preface

This is a detailed instruction on latitude and longitude conversion. For those of you who are working or planning to work on map-related projects, this is a great way to help you understand and solve latitude and longitude transitions.

1. Common map coordinate system

WGS84

Maps: Google (abroad), OSM, ArcgisOnline.

Description: Geodetic coordinate system, is also widely used GPS global positioning system used in the coordinate system.

CGCS2000

Map: Map of heaven and earth.

Explanation: The national geodetic coordinate system can be directly replaced by the WGS84 coordinate system in many cases, because the definition of the WGS84 coordinate system is the same and the reference ellipsoid used is very close. The latitude and height of the ellipsoid vary up to 0.1mm due to the flattening difference. Within the range of current measurement accuracy, this difference is negligible.

GCJ-02

Map: Autonavi map, Tencent Map, Google (domestic).

Description: Mars coordinate system is a geographic coordinate system customized by The National Bureau of Surveying and Mapping of China, obtained by WGS84 coordinates once encrypted.

BD-09

Map: Baidu Map.

Baidu coordinate system, Baidu and others are not the same, on the basis of the GCJ-02 coordinate system and a encryption, cattle! Wherein, BD-09LL represents Baidu latitude and longitude coordinates, and BD-09MC represents Baidu Web Mercator projection coordinates.

The diagram

Knowing this is a prerequisite for coordinate transformation.

2. Basic concepts

projection

The process of converting geographic coordinates to projected coordinates by converting an irregular surface of the earth into a plane.

Geographic coordinate system

Is spherical coordinates, the reference plane is an ellipsoid, and the coordinate unit is latitude and longitude.

Projection coordinate system

Is plane coordinate, the reference plane is horizontal plane, coordinate unit: meter, kilometer, etc.

EPSG

The European Petroleum Survey Group. Maintain the space reference system, which is the OGC standard. All of the individual pieces of content have corresponding ids. For example, EPSG:4326 and EPSG:3857.

EPSG:4326

A geographic coordinate system, which by default means WGS84.

EPSG:3857

A projection coordinate system, which by default is Google’s Mercator coordinate system.

Of course, there are more standards, such as EPSG:4479, EPSG:4480 and so on.

3. Coordinate transformation in Openlayers

Proj4

In OpenLayers, Proj4 library tools are used for coordinate transformations by default. This process is: source coordinate system (geographic or projection) >WGS84– > target coordinate system (geographic or projection). Thus, WGS84 acts as a bridge here, but accuracy may be lost in the actual conversion process.

Note that since coordinates GCJ-02 and BD-09 are not included in the EPSG system, Proj4 does not have conversion methods for these two coordinates by default. That is to say, if the transformation rules are not changed when OpenLayers is used, the coordinates of GCJ-02 and BD-09 need to be manually converted to the coordinates of WGS84.

Built-in conversion methods

  • toLonLat(coordinate,projection)

    Coordinate: array of projected coordinates;

    Projection: coordinate projection, default is Web Mercator, i.e. “EPSG:3857”.

  • fromLonLat(coordinate,projection)

    Coordinate: latitude and longitude coordinate array;

    Projection: target projection, default is Web Mercator, i.e. “EPSG:3857”.

  • transform(coordinate,source,destination)

    Coordinate: array of coordinates;

    Source: source projection;

    Destination: projection of the target.

  • transformExtent(extent,source,destination,stops)

    Extent: range array, similar to [120,30,120,30];

    Source: source projection;

    Destination: target projection;

    Stops: Number of stops per side used for the transform. By default only the corners are used.

Of course, without modifying and defining new conversion rules, the above built-in conversion method is not enough for our use. For the coordinate data of Autonavi, Baidu and other maps, we need to transform and correct them before we can use them, otherwise large errors will be generated.

The difference between

  • EPSG:4326 coordinates are usually used for data storage, because EPSG:3857 coordinates have poor readability and occupy memory due to their large value.
  • Rendering is usually done using EPSG:3857, because EPSG:4326 causes the page to be distorted (as shown below, the map is compressed in EPSG:4326 coordinates).

Mercator projection (EPSG:3857) in the upper right corner, isometric projection (EPSG:4326) in the lower right corner

Typically, data is stored in EPSG:4326 and displayed in EPSG:3857.

4. Conversion algorithm

Latitude and longitude to latitude and longitude

BD – 09 ll turn GCJ – 02

Scope of application: Baidu coordinates to Mars coordinates (Autonavi, Tencent, Google domestic, etc.).

Algorithm code:

bdToGcj(lon, lat) {
    let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
    let x = lon - 0.0065;
    let y = lat - 0.006;
    let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
    let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
    return [z * Math.cos(theta), z * Math.sin(theta)];
}
Copy the code

BD – 09 ll GCJ – 02

Scope of application: Mars coordinates (Autonavi, Tencent, Google, etc.) to 100 degree coordinates.

Algorithm code:

gcjToBd(lon, lat) {
    let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
    const latlng = [];
    const x = lon;
    const y = lat;
    const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
    const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
    latlng[0] = z * Math.cos(theta) + 0.0065;
    latlng[1] = z * Math.sin(theta) + 0.006;
    return latlng;
}
Copy the code

Turn WGS84 GCJ – 02

Scope of application: Mars coordinates (Autonavi, Tencent, Google, etc.) to geodetic coordinates (Google abroad, OSM, ArcGISOnline, etc.).

Algorithm code:

gcjToWgs(lon, lat) {
    let PI = 3.14159265358979324;
    function transformGCJ2WGS(gcjLon, gcjLat) {
        let d = delta(gcjLon, gcjLat)
        return [gcjLon - d.lon, gcjLat - d.lat]
    }

    function delta(x, y) {
        let a = 6378245.0 // a: The projection factor of the satellite ellipsoidal coordinates into the plane map coordinate system.
        let ee = 0.00669342162296594323 // EE: eccentricity of ellipsoid
        let dLat = transformLat(x - 105.0, y - 35.0)
        let dLon = transformLon(x - 105.0, y - 35.0)
        let radLat = y / 180.0 * PI
        let magic = Math.sin(radLat)
        magic = 1 - ee * magic * magic
        let sqrtMagic = Math.sqrt(magic)
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI)
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI)
        return {
            'lat': dLat,
            'lon': dLon
        }
    }
    function transformLat(x, y) {
        let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x))
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0
        ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0
        ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0
        return ret
    }
    function transformLon(x, y) {
        let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x))
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0
        ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0
        ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0
        return ret
    }

    return transformGCJ2WGS(lon, lat);
}
Copy the code

WGS84 转 GCJ-02

Scope of application: geodetic coordinates (Google overseas, OSM, ArcGISOnline, etc.) to Mars coordinates (Autonavi, Tencent, Google domestic, etc.).

Algorithm code:

wgsToGcj(lon, lat) {
    let pi = 3.14159265358979324;
    let a = 6378245.0;
    let ee = 0.00669342162296594323;

    /* Determine whether the map is in the country or not, do not offset, because the foreign Google map coordinate system is in accordance with WGS84 */
    function outOfChina(lon, lat) {
        if ((lon < 72.004 || lon > 137.8347) && (lat < 0.8293 || lat > 55.8271)) {
            return true;
        } else {
            return false; }}function transformLat(x, y) {
        let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    function transformLon(x, y) {
        let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
        return ret;
    }

    function transformLonLat(wgLon, wgLat) {
        // If in a foreign country, return directly without processing
        if (outOfChina(wgLon, wgLat)) {
            return [wgLon, wgLat];
        }
        let dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        let dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        let radLat = wgLat / 180.0 * pi;
        let magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        let sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        return [wgLon + dLon, wgLat + dLat]
    }
    return transformLonLat(lon, lat)
}
Copy the code

Latitude and longitude to Mercator

Latitude and longitude to Mercator

Applicable scope: Mars longitude and latitude to Mars Mercator, WGS84 longitude and latitude to WGS84 Mercator.

Algorithm code:

lonlatToMercator(lon, lat) {
    let mercator = [0.0]
    let x = lon * 20037508.34 / 180;
    let y = Math.log(Math.tan((90 + lat) * Math.PI / 360))/(Math.PI / 180);
    y = y * 20037508.34 / 180;

    mercator = [x, y]
    return mercator;
}
Copy the code

Mercator turns latitude and longitude

Scope of application: Mars Mercator to Mars longitude and latitude, WGS84 Mercator to WGS84 longitude and latitude.

Algorithm code:

mercatorToLonlat(mercatorX, mercatorY) {
    let lonlat = [0.0]
    var x = mercatorX / 20037508.34 * 180;
    var y = mercatorY / 20037508.34 * 180;
    y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
    lonlat = [x, y]
    return lonlat;
}
Copy the code

BD – 09 ll turn BD – 09 MC

Application: Baidu latitude and longitude to Baidu Mercator.

Algorithm code:

bdllToBdmc(lon, lat) {
    let LLBAND = [75.60.45.30.15.0];
    let LL2MC = [
        [-0.0015702102444.111320.7020616939.1704480524535203, -10338987376042340.26112667856603880, -35149669176653700.26595700718403920, -10725012454188240.1800819912950474.82.5],
        [0.0008277824516172526.111320.7020463578.647795574.6671607, -4082003173.641316.10774905663.51142, -15171875531.51559.12053065338.62167, -5124939663.577472.913311935.9512032.67.5],
        [0.00337398766765.111320.7020202162.4481351.045890365, -23393751.19931662.79682215.47186455, -115964993.2797253.97236711.15602145, -43661946.33752821.8477230.501135234.52.5],
        [0.00220636496208.111320.7020209128.51751.86112841131.3796837.749470245.992013.7397791013, -1221952.21711287.1340652.697009075, -620943.6990984312.144416.9293806241.37.5], [...0.0003441963504368392.111320.7020576856.278.2353980772752.2485758.690035394.6070.750963243378.54821.18345352118.9540.606633304236, -2710.55326746645.1405.483844121726.22.5], [...0.0003218135878613132.111320.7020701615.0.00369383431289.823725.6402795718.0.46104986909093.2351.343141331292.1.58060784298199.8.77738589078284.0.37238884252424.7.45]].function getRange(cC, cB, T) {
        if(cB ! =null) {
            cC = Math.max(cC, cB);
        }
        if(T ! =null) {
            cC = Math.min(cC, T);
        }
        return cC;
    }
    function getLoop(cC, cB, T) {
        while (cC > T) {
            cC -= T - cB;
        }
        while (cC < cB) {
            cC += T - cB;
        }
        return cC;
    }
    function convertor(cC, cD) {
        if(! cC || ! cD) {return null;
        }
        let T = cD[0] + cD[1] * Math.abs(cC.x);
        const cB = Math.abs(cC.y) / cD[9];
        let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
            cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
            cD[7] * cB * cB * cB * cB * cB +
            cD[8] * cB * cB * cB * cB * cB * cB;
        T *= (cC.x < 0 ? -1 : 1);
        cE *= (cC.y < 0 ? -1 : 1);
        return [T, cE];
    }
    function convertLL2MC(T) {
        let cD, cC, len;
        T.x = getLoop(T.x, -180.180);
        T.y = getRange(T.y, -74.74);
        const cB = T;
        for (cC = 0, len = LLBAND.length; cC < len; cC++) {
            if (cB.y >= LLBAND[cC]) {
                cD = LL2MC[cC];
                break; }}if(! cD) {for (cC = LLBAND.length - 1; cC >= 0; cC--) {
                if (cB.y <= -LLBAND[cC]) {
                    cD = LL2MC[cC];
                    break; }}}const cE = convertor(T, cD);
        return cE;
    }
    return convertLL2MC({
        x: lon,
        y: lat
    });
}
Copy the code

BD – 9 BD – 09 ll MC

Scope of application: Baidu Mercator to Baidu latitude and longitude.

Algorithm code:

bdmcToBdll(lon, lat) {
    let MCBAND = [12890594.86.8362377.87.5591021.3481989.83.1678043.12.0]
    let MC2LL = [
        [1.410526172116255 e-8.0.00000898305509648872, -1.9939833816331.200.9824383106796, -187.2403703815547.91.6087516669843, -23.38765649603339.2.57121317296198, -0.03801003308653.17337981.2], [...7.435856389565537 e-9.0.000008983055097726239, -0.78625201886289.96.32687599759846, -1.85204757529826, -59.36935905485877.47.40033549296737, -16.50741931063887.2.28786674699375.10260144.86], [...3.030883460898826 e-8.0.00000898305509983578.0.30071316287616.59.74293618442277.7.357984074871, -25.38371002664745.13.45380521110908, -3.29883767235584.0.32710905363475.6856817.37], [...1.981981304930552 e-8.0.000008983055099779535.0.03278182852591.40.31678527705744.0.65659298677277, -4.44255534477492.0.85341911805263.0.12923347998204, -0.04625736007561.4482777.06],
        [3.09191371068437 e-9.0.000008983055096812155.0.00006995724062.23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273.0.03430082397953, -0.00466043876332.2555164.4],
        [2.890871144776878 e-9.0.000008983055095805407, -3.068298 e-8.7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596.0.00010322952773, -0.00000323890364.826088.5]]function convertor(cC, cD) {
        if(! cC || ! cD) {return null;
        }
        let T = cD[0] + cD[1] * Math.abs(cC.x);
        const cB = Math.abs(cC.y) / cD[9];
        let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
            cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
            cD[7] * cB * cB * cB * cB * cB +
            cD[8] * cB * cB * cB * cB * cB * cB;
        T *= (cC.x < 0 ? -1 : 1);
        cE *= (cC.y < 0 ? -1 : 1);
        return [T, cE];
    }

    function convertMC2LL(cB) {
        const cC = {
            x: Math.abs(cB.x),
            y: Math.abs(cB.y)
        };
        let cE;
        for (let cD = 0, len = MCBAND.length; cD < len; cD++) {
            if (cC.y >= MCBAND[cD]) {
                cE = MC2LL[cD];
                break; }}const T = convertor(cB, cE);
        return T;
    }
    return convertMC2LL({
        x: lon,
        y: lat
    });
}
Copy the code

5. A picture

Use a picture to see how you need to convert the current coordinate value:

Dry stuff!!

6. Sample

The key point

In a project, a few key points should be made clear:

  1. Storage of data.

    Firstly, it is necessary to clarify and unify the type of coordinate data stored in the background. It is recommended to use WGS84 latitude and longitude coordinates, which are equivalent to CGCS2000 latitude and longitude coordinates.

    Generally speaking, the unified storage in the background is WGS84 latitude and longitude coordinates or CGCS2000 latitude and longitude coordinates (heaven and Earth map).

  2. Map used.

    It is not necessary to specify which coordinate system you are using, for example autonavi, Google, etc.

    Allows the use of any map type, can be effectively used for map heaven and Earth, Autonavi, Baidu, Google, etc.

  3. The selected coordinate system.

    Determine which coordinate system is currently in use, latitude and longitude or Mercator. Or you could view it as 4326 or 3857.

    In general, Mercator coordinate system is used more.

  4. The actual operation.

    In addition to the three points mentioned above, another factor affecting coordinate transformation is the actual map manipulation. There are two cases:

    • Render according to latitude and longitude coordinates. For example: point rendering.
    • Get latitude and longitude coordinates by map manipulation. For example, select by circled.

    This key point requires different processing of the data according to Point 3. If I choose to use the Mercator coordinate system, then I get the Mercator coordinate by selecting the box; If I select the latitude and longitude coordinate system, then the box gets the latitude and longitude coordinates.

Concrete example

Here’s an example.

Identify key points:

  1. Data storage for latitude and longitude coordinates of heaven and earth map;
  2. Use Baidu Map;
  3. Choose Mercator coordinate system;
  4. Operation: point rendering, box selection circle selection.

Point rendering

Convert the obtained latitude and longitude coordinates of the map into baidu Mercator coordinates.

It can be seen from the figure that the coordinate transformation sequence is 1->2->3->6, and the methods to be called are as follows: wgsToGcj(LON, LOAT), gcjToBd(Lon, LOAT), bdllToBdmc(LON, LAT).

Box to choose circle

The function is to draw a rectangle or circle on a map and then get the boundary range of the graph, usually the longitude and latitude data. Because the Mercator coordinate system is selected, so in the operation of drawing graphics, the first thing to get is the Mercator coordinates of the map, here is the Mercator coordinates of Baidu.

Step by step elaboration is:

  1. Drawing operation;

  2. Obtain the Mercator coordinates of the selected map, here is the Mercator coordinates of Baidu;

  3. Convert Baidu Mercator coordinates to latitude and longitude coordinates of map of heaven and earth.

    Generally speaking, the resulting coordinates are in the same format as the stored data, which is convenient for background use. Of course, the specific situation should also be analyzed, for example, part of the demand is to get the coordinates through the circled box, to the background for data screening.

According to the figure, the coordinate conversion sequence is 6->3->2->1, and the methods to be called are bdmcToBdll(LON, LAT), bdToGcj(LON, LOAT), and gcjToWgs(LON, LOAT).

7. To summarize

Sorting is not easy, but allow white piao ~

Come on, strangers!