diff --git a/Gruntfile.js b/Gruntfile.js index 777ae3b..76fe861 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -32,7 +32,8 @@ var projs = [ 'robin', 'geocent', 'tpers', - 'geos' + 'geos', + 'eqearth' ]; module.exports = function (grunt) { grunt.initConfig({ diff --git a/index.js b/index.js new file mode 100644 index 0000000..2508747 --- /dev/null +++ b/index.js @@ -0,0 +1,4 @@ +const proj4 = require('./dist/proj4-src.js'); + +const coords = proj4("+proj=stere +lat_0=90 +lat_ts=60 +lon_0=10 +x_0=0 +y_0=0 +a=6370040 +b=6370040 +to_meter=1000 +no_defs", "WGS84", [-217.962000,-4331.145000]); +console.log(coords); diff --git a/lib/includedProjections.js b/lib/includedProjections.js index 22039ba..99c6c1c 100644 --- a/lib/includedProjections.js +++ b/lib/includedProjections.js @@ -26,6 +26,7 @@ import robin from './projections/robin'; import geocent from './projections/geocent'; import tpers from './projections/tpers'; import geos from './projections/geos'; +import eqearth from "./projections/eqearth"; var projs = [ tmerc, @@ -56,6 +57,7 @@ var projs = [ geocent, tpers, geos, + eqearth ]; export default function (proj4) { diff --git a/lib/projString.js b/lib/projString.js index a03f18e..7f52a73 100644 --- a/lib/projString.js +++ b/lib/projString.js @@ -70,6 +70,9 @@ export default function(defData) { b: function(v) { self.b = parseFloat(v); }, + r: function(v) { + self.a = self.b = parseFloat(v); + }, r_a: function() { self.R_A = true; }, diff --git a/lib/projections/eqearth.js b/lib/projections/eqearth.js new file mode 100644 index 0000000..e407e1b --- /dev/null +++ b/lib/projections/eqearth.js @@ -0,0 +1,93 @@ +/** + * Copyright 2018 Bernie Jenny, Monash University, Melbourne, Australia. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Equal Earth is a projection inspired by the Robinson projection, but unlike + * the Robinson projection retains the relative size of areas. The projection + * was designed in 2018 by Bojan Savric, Tom Patterson and Bernhard Jenny. + * + * Publication: + * Bojan Savric, Tom Patterson & Bernhard Jenny (2018). The Equal Earth map + * projection, International Journal of Geographical Information Science, + * DOI: 10.1080/13658816.2018.1504949 + * + * Code released August 2018 + * Ported to JavaScript and adapted for mapshaper-proj by Matthew Bloch August 2018 + * Modified for proj4js by Andreas Hocevar by Andreas Hocevar March 2024 + */ + +import adjust_lon from "../common/adjust_lon"; + +var A1 = 1.340264, + A2 = -0.081106, + A3 = 0.000893, + A4 = 0.003796, + M = Math.sqrt(3) / 2.0; + +export function init() { + this.es = 0; + this.long0 = this.long0 !== undefined ? this.long0 : 0; +} + +export function forward(p) { + var lam = adjust_lon(p.x - this.long0); + var phi = p.y; + var paramLat = Math.asin(M * Math.sin(phi)), + paramLatSq = paramLat * paramLat, + paramLatPow6 = paramLatSq * paramLatSq * paramLatSq; + p.x = lam * Math.cos(paramLat) / + (M * (A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq))); + p.y = paramLat * (A1 + A2 * paramLatSq + paramLatPow6 * (A3 + A4 * paramLatSq)); + + p.x = this.a * p.x + this.x0; + p.y = this.a * p.y + this.y0; + return p; +} + +export function inverse(p) { + p.x = (p.x - this.x0) / this.a; + p.y = (p.y - this.y0) / this.a; + + var EPS = 1e-9, + NITER = 12, + paramLat = p.y, + paramLatSq, paramLatPow6, fy, fpy, dlat, i; + + for (i = 0; i < NITER; ++i) { + paramLatSq = paramLat * paramLat; + paramLatPow6 = paramLatSq * paramLatSq * paramLatSq; + fy = paramLat * (A1 + A2 * paramLatSq + paramLatPow6 * (A3 + A4 * paramLatSq)) - p.y; + fpy = A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq); + paramLat -= dlat = fy / fpy; + if (Math.abs(dlat) < EPS) { + break; + } + } + paramLatSq = paramLat * paramLat; + paramLatPow6 = paramLatSq * paramLatSq * paramLatSq; + p.x = M * p.x * (A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq)) / + Math.cos(paramLat); + p.y = Math.asin(Math.sin(paramLat) / M); + + p.x = adjust_lon(p.x + this.long0); + return p; +} + +export var names = ["eqearth", "Equal Earth", "Equal_Earth"]; +export default { + init: init, + forward: forward, + inverse: inverse, + names: names +}; \ No newline at end of file diff --git a/projs.js b/projs.js index 5209f54..38440a8 100644 --- a/projs.js +++ b/projs.js @@ -27,6 +27,7 @@ import robin from './lib/projections/robin'; import geocent from './lib/projections/geocent'; import tpers from './lib/projections/tpers'; import geos from './lib/projections/geos'; +import eqearth from './lib/projections/eqearth'; export default function(proj4){ proj4.Proj.projections.add(tmerc); proj4.Proj.projections.add(etmerc); @@ -57,4 +58,5 @@ export default function(proj4){ proj4.Proj.projections.add(geocent); proj4.Proj.projections.add(tpers); proj4.Proj.projections.add(geos); + proj4.Proj.projections.add(eqearth); } \ No newline at end of file diff --git a/test/testData.js b/test/testData.js index eba7b97..7e3c993 100644 --- a/test/testData.js +++ b/test/testData.js @@ -856,6 +856,16 @@ var testPoints = [ ll: [0, 0], xy: [0, 12367396.218459858], }, + { + code: '+proj=eqearth +lon_0=0 +x_0=0 +y_0=0 +R=6371008.7714 +units=m +no_defs +type=crs', + ll: [16, 48], + xy: [1284600.7230114893, 5794915.366010354] + }, + { + code: '+proj=eqearth +lon_0=150 +x_0=0 +y_0=0 +R=6371008.7714 +units=m +no_defs +type=crs', + ll: [16, 48], + xy: [-10758531.055221224, 5794915.366010354] + } ]; if (typeof module !== 'undefined') { module.exports = testPoints;