ol-proj-ch
Version:
china's gcj02 for openlayers
303 lines • 9.72 kB
JavaScript
/**
* GCJ02 Projection on basis of WGS84(EGPS:4326)
* <p>
* GCJ02 is not a projection strictly. In fact, it is a
* confidential algorithm to offset real coordinate in China
*
* @author Ke Wang (wkgreat@outlook.com)
*
* </p>
* */
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import Projection from 'ol/proj/Projection';
import { fromEPSG4326 as from4326to3857, PROJECTIONS as EPSG3857_PROJECTIONS, toEPSG4326 as from3857to4326 } from 'ol/proj/epsg3857';
import { PROJECTIONS as EPSG4326_PROJECTIONS } from 'ol/proj/epsg4326';
import { addEquivalentProjections, addEquivalentTransforms } from 'ol/proj';
import Units from 'ol/proj/Units';
/*eslint-enable */
/**
* radius of WGS84 ellipsoid
* @const
* @type {number}
* */
export var RADIUS = 6378137;
/**
* extent of gcj02
* @const
* @type {ol/Extent}
* */
export var EXTENT = [73.62, 18.11, 134.77, 53.56];
/**
* coefficient between degree and radian
* @const
* @type {number}
* */
export var METERS_PER_UNIT = (Math.PI * RADIUS) / 180;
/**
* @classdesc
* Projection object definition of GCJ02
* */
var GCJ02Projection = /** @class */ (function (_super) {
__extends(GCJ02Projection, _super);
/**
* @constructor
* @param {string} code of gcj02
* @param {string} opt_axisOrientation Axis orientation.
* */
function GCJ02Projection(code, opt_axisOrientation) {
return _super.call(this, {
code: code,
units: Units.METERS,
extent: EXTENT,
axisOrientation: opt_axisOrientation,
global: false,
metersPerUnit: METERS_PER_UNIT,
worldExtent: EXTENT
}) || this;
}
return GCJ02Projection;
}(Projection));
/**
* default code of gcj02, used as identifier of gcj02
* @const
* @type {string}
* */
export var CODE = 'GCJ02';
/**
* all code of GCJ02Projection, 'GCJ02', 'GCJ:02' and 'ZH:MARS'
* @const
* @type {GCJ02Projection[]}
* */
export var PROJECTIONS = [
new GCJ02Projection(CODE),
new GCJ02Projection('GCJ:02'),
new GCJ02Projection('ZH:MARS')
];
/**
* transform coordinate from GCJ02 to EPSG:3857
* @function
* @param {number[]} input input coordinate
* @param {number[]} opt_output output coordinate
* @param {number} opt_dimension dimension of coordinate
* @return {number[]} tranformed coordinate
* */
export function toEPSG3857(input, opt_output, opt_dimension) {
var the4326 = toEPSG4326(input, opt_output, opt_dimension);
return from4326to3857(the4326, opt_output, opt_dimension);
}
/**
* transform coordinate from EPSG:3857 to GCJ02
* @function
* @param {number[]} input input coordinate
* @param {number[]} opt_output output coordinate
* @param {number} opt_dimension dimension of coordinate
* @return {number[]} tranformed coordinate
* */
export function fromEPSG3857(input, opt_output, opt_dimension) {
var the4326 = from3857to4326(input, opt_output, opt_dimension);
return fromEPSG4326(the4326, opt_output, opt_dimension);
}
/**
* transform coordinate from GCJ02 to EPSG:4326
* @function
* @param {number[]} input input coordinate
* @param {number[]} opt_output output coordinate
* @param {number} opt_dimension dimension of coordinate
* @return {number[]} tranformed coordinate
* */
export function toEPSG4326(input, opt_output, opt_dimension) {
var length = input.length;
var dimension = opt_dimension > 1 ? opt_dimension : 2;
var output = opt_output;
if (output === undefined) {
if (dimension > 2) {
// preserve values beyond second dimension
output = input.slice();
}
else {
output = new Array(length);
}
}
for (var i = 0; i < length; i += dimension) {
var coord = gcj2WGS(input.slice(i, i + 2));
output[i] = coord[i];
output[i + 1] = coord[i + 1];
}
return output;
}
/**
* transform coordinate from EPSG:4326 to GCJ02
* @function
* @param {number[]} input input coordinate
* @param {number[]} opt_output output coordinate
* @param {number} opt_dimension dimension of coordinate
* @return {number[]} tranformed coordinate
* */
export function fromEPSG4326(input, opt_output, opt_dimension) {
var length = input.length;
var dimension = opt_dimension > 1 ? opt_dimension : 2;
var output = opt_output;
if (output === undefined) {
if (dimension > 2) {
// preserve values beyond second dimension
output = input.slice();
}
else {
output = new Array(length);
}
}
for (var i = 0; i < length; i += dimension) {
var coord = wgs2GCJ(input.slice(i, i + 2));
output[i] = coord[i];
output[i + 1] = coord[i + 1];
}
return output;
}
/**
* transform coordinate from GCJ02 to EPSG:4326, this algorithm is more precise.
* @function
* @param {number[]} coord coordinate
* @return {number[]} tranformed coordinate
* */
export function gcj02WGSExactly(coord) {
var gcjLon = coord[0];
var gcjLat = coord[1];
var initDelta = 0.01;
var threshold = 0.000000001;
var dLat = initDelta;
var dLon = initDelta;
var mLat = gcjLat - dLat;
var mLon = gcjLon - dLon;
var pLat = gcjLat + dLat;
var pLon = gcjLon + dLon;
var wgsLat;
var wgsLon;
var i = 0;
while (true) {
wgsLat = (mLat + pLat) / 2;
wgsLon = (mLon + pLon) / 2;
var tmp = wgs2GCJ([wgsLat, wgsLon]);
dLat = tmp[0] - gcjLat;
dLon = tmp[1] - gcjLon;
if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold)) {
break;
}
if (dLat > 0) {
pLat = wgsLat;
}
else {
mLat = wgsLat;
}
if (dLon > 0) {
pLon = wgsLon;
}
else {
mLon = wgsLon;
}
if (++i > 10000) {
break;
}
}
return [wgsLon, wgsLat];
}
/**
* transform coordinate from EPSG:4326 to GCJ02
* @function
* @param {number[]} coord coordinate
* @return {number[]} tranformed coordinate
* */
export function wgs2GCJ(coord) {
var wgLon = coord[0];
var wgLat = coord[1];
if (outOfChina(coord)) {
return coord;
}
var deltaD = delta(coord);
return [wgLon + deltaD[0], wgLat + deltaD[1]];
}
/**
* transform coordinate from GCJ02 to EPSG:4326
* @function
* @param {number[]} coord coordinate
* @return {number[]} tranformed coordinate
* */
export function gcj2WGS(coord) {
var glon = coord[0];
var glat = coord[1];
if (outOfChina(coord)) {
return coord;
}
var deltaD = delta(coord);
return [glon - deltaD[0], glat - deltaD[1]];
}
/**
* whether a coordinate is nout of area of china
* @param {number[]} coord the coordinate
* @return {boolean} whether is out of china
* */
export function outOfChina(coord) {
var lon = coord[0];
var lat = coord[1];
if (lon < 72.004 || lon > 137.8347) {
return true;
}
if (lat < 0.8293 || lat > 55.8271) {
return true;
}
return false;
}
function delta(coord) {
var wgLon = coord[0];
var wgLat = coord[1];
var dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
var dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
var radLat = wgLat / 180.0 * Math.PI;
var magic = Math.sin(radLat);
magic = 1 - 0.00669342162296594323 * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtMagic) * Math.PI);
dLon = (dLon * 180.0) / (6378245.0 / sqrtMagic * Math.cos(radLat) * Math.PI);
return [dLon, dLat];
}
function transformLat(x, y) {
var 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 * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
return ret;
}
function transformLon(x, y) {
var 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 * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
return ret;
}
/**
* add gcj02 and its transformations to openlayers
* it is added when this module is imported automatically
* @function
* */
function addGcj02() {
// Add transformations that don't alter coordinates to convert within set of
// projections with equal meaning.
addEquivalentProjections(PROJECTIONS);
// Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like
// coordinates and back.
addEquivalentTransforms(PROJECTIONS, EPSG3857_PROJECTIONS, toEPSG3857, fromEPSG3857);
addEquivalentTransforms(PROJECTIONS, EPSG4326_PROJECTIONS, toEPSG4326, fromEPSG4326);
}
addGcj02();
//# sourceMappingURL=gcj02.js.map