import { extend } from '../../core/util/common';
import { sign } from '../../core/util/util';
import Common, { type CommonProjectionType } from './Projection';
import Coordinate from '../Coordinate';
import { WGS84Sphere, type WGS84SphereType } from '../measurer';
const delta = 1E-7;
const EPSG3857Projection = {
/**
* "EPSG:3857", Code of the projection
* @constant
*/
code: 'EPSG:3857',
rad: Math.PI / 180,
metersPerDegree: 6378137 * Math.PI / 180,
maxLatitude: 85.0511287798,
project: function (lnglat: Coordinate, out?: Coordinate) {
const rad = this.rad,
metersPerDegree = this.metersPerDegree,
max = this.maxLatitude;
const lng = lnglat.x,
lat = Math.max(Math.min(max, lnglat.y), -max);
let c;
if (lat === 0) {
c = 0;
} else {
c = Math.log(Math.tan((90 + lat) * rad / 2)) / rad;
}
const x = lng * metersPerDegree;
const y = c * metersPerDegree;
const z = lnglat.z;
if (out) {
out.x = x;
out.y = y;
out.z = z;
return out;
}
return new Coordinate(x, y, z);
},
unproject: function (pLnglat: Coordinate, out?: Coordinate) {
const rad = this.rad;
const metersPerDegree = this.metersPerDegree;
let x = pLnglat.x / metersPerDegree;
const y = pLnglat.y;
let c;
if (y === 0) {
c = 0;
} else {
c = y / metersPerDegree;
c = (2 * Math.atan(Math.exp(c * rad)) - Math.PI / 2) / rad;
}
if (Math.abs(Math.abs(x) - 180) < delta) {
x = sign(x) * 180;
}
if (Math.abs(Math.abs(c) - this.maxLatitude) < delta) {
c = sign(c) * this.maxLatitude;
}
// const rx = wrap(x, -180, 180);
// const ry = wrap(c, -this.maxLatitude, this.maxLatitude);
const rx = x;
const ry = c;
const rz = pLnglat.z;
if (out) {
out.x = rx;
out.y = ry;
out.z = rz;
return out;
}
return new Coordinate(rx, ry, rz);
}
};
export type EPSG3857ProjectionType = CommonProjectionType & typeof EPSG3857Projection & WGS84SphereType;
/**
* Google 地图或 OSM 地图使用的常规投影,又名墨卡托投影。
* 这是地图的默认投影。
*
* @english
* Well-known projection used by Google maps or Open Street Maps, aka Mercator Projection.
* It is map's default projection.
*
* @category geo
* @protected
* @group projection
* @name EPSG3857
* {@inheritDoc projection.Common}
* {@inheritDoc measurer.WGS84Sphere}
*/
export default extend({} as EPSG3857ProjectionType, Common, EPSG3857Projection, WGS84Sphere);