diff --git a/CHANGELOG.md b/CHANGELOG.md index 40043638..528d7cf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +v0.6.102 +* Added Nicolosi Globular (nicol) projection. + v0.6.101 * Added -affine fit-bbox= option, for transforming data to fit within a bounding box. * Improved arrow symbols. diff --git a/package-lock.json b/package-lock.json index 63eb4b2e..072a35f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapshaper", - "version": "0.6.101", + "version": "0.6.102", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mapshaper", - "version": "0.6.101", + "version": "0.6.102", "license": "MPL-2.0", "dependencies": { "@placemarkio/tokml": "^0.3.3", @@ -25,7 +25,7 @@ "iconv-lite": "^0.6.3", "idb-keyval": "^6.2.0", "kdbush": "^3.0.0", - "mproj": "0.0.39", + "mproj": "0.0.40", "msgpackr": "^1.10.1", "opn": "^5.3.0", "rw": "~1.3.3", @@ -2684,9 +2684,9 @@ } }, "node_modules/mproj": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/mproj/-/mproj-0.0.39.tgz", - "integrity": "sha512-E0U/vCIbP2F+a6lhDkPEJzrGkUVir3fcwXcsbXngoo8ZeNN2l8zpphXPZgbe6WvBQ/L4wI+DGdUmHK2zi8RvzQ==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/mproj/-/mproj-0.0.40.tgz", + "integrity": "sha512-Fda92o5LkFUr0Tbz/5QsVhsIgbhnrnQf/eLkYRWGfKspbgvjA0VCk1FF5bT1TgpMHAP7000alBRkV7Q7hesnQg==", "dependencies": { "geographiclib": "1.48.0", "rw": "~1.3.2" @@ -5646,9 +5646,9 @@ } }, "mproj": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/mproj/-/mproj-0.0.39.tgz", - "integrity": "sha512-E0U/vCIbP2F+a6lhDkPEJzrGkUVir3fcwXcsbXngoo8ZeNN2l8zpphXPZgbe6WvBQ/L4wI+DGdUmHK2zi8RvzQ==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/mproj/-/mproj-0.0.40.tgz", + "integrity": "sha512-Fda92o5LkFUr0Tbz/5QsVhsIgbhnrnQf/eLkYRWGfKspbgvjA0VCk1FF5bT1TgpMHAP7000alBRkV7Q7hesnQg==", "requires": { "geographiclib": "1.48.0", "rw": "~1.3.2" diff --git a/package.json b/package.json index f79b0f8e..1ea899c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapshaper", - "version": "0.6.101", + "version": "0.6.102", "description": "A tool for editing vector datasets for mapping and GIS.", "keywords": [ "shapefile", @@ -56,7 +56,7 @@ "iconv-lite": "^0.6.3", "idb-keyval": "^6.2.0", "kdbush": "^3.0.0", - "mproj": "0.0.39", + "mproj": "0.0.40", "msgpackr": "^1.10.1", "opn": "^5.3.0", "rw": "~1.3.3", diff --git a/src/crs/mapshaper-proj-extents.mjs b/src/crs/mapshaper-proj-extents.mjs index 5f2a2831..ef714156 100644 --- a/src/crs/mapshaper-proj-extents.mjs +++ b/src/crs/mapshaper-proj-extents.mjs @@ -118,7 +118,7 @@ export function getClampBBox(P) { } export function isCircleClippedProjection(P) { - return inList(P, 'stere,sterea,ups,ortho,gnom,laea,nsper,tpers,geos'); + return inList(P, 'stere,sterea,ups,ortho,gnom,laea,nsper,tpers,geos,nicol'); } function getPerspectiveClipAngle(P) { @@ -143,6 +143,7 @@ export function getDefaultClipAngle(P) { laea: 179, //ortho: 89.9, // projection errors betwen lat +/-35 to 55 ortho: 89.85, // TODO: investigate + nicol: 89.85, stere: 142, sterea: 142, ups: 10.5 // TODO: should be 6.5 deg at north pole diff --git a/src/crs/mapshaper-proj-info.mjs b/src/crs/mapshaper-proj-info.mjs index 25c7f2f4..556b0434 100644 --- a/src/crs/mapshaper-proj-info.mjs +++ b/src/crs/mapshaper-proj-info.mjs @@ -17,7 +17,7 @@ export function isAxisAligned(P) { // TODO: consider projections that may or may not be aligned, // depending on parameters if (inList(P, 'cassini,gnom,bertin1953,chamb,ob_tran,tpeqd,healpix,rhealpix,' + - 'ocea,omerc,tmerc,etmerc')) { + 'ocea,omerc,tmerc,etmerc,nicol')) { return false; } if (isAzimuthal(P)) { diff --git a/www/modules.js b/www/modules.js index 2ccdca23..891e9bd1 100644 --- a/www/modules.js +++ b/www/modules.js @@ -20279,6 +20279,7 @@ function pj_phi2(ts, e) { pj_add(pj_merc, 'merc', 'Mercator', 'Cyl, Sph&Ell\nlat_ts='); +pj_add(pj_webmerc, 'webmerc', 'Web Mercator / Pseudo Mercator', 'Cyl, Ell'); function pj_merc(P) { var EPS10 = 1e-10; @@ -20333,6 +20334,26 @@ function pj_merc(P) { } } +function pj_webmerc(P) { + P.k0 = 1; + P.inv = s_inv; + P.fwd = s_fwd; + + function s_fwd(lp, xy) { + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + f_error(); + } + xy.x = P.k0 * lp.lam; + xy.y = P.k0 * log(tan(M_FORTPI + 0.5 * lp.phi)); + } + + function s_inv(xy, lp) { + lp.phi = M_HALFPI - 2 * atan(exp(-xy.y / P.k0)); + lp.lam = xy.x / P.k0; + } +} + + pj_add(pj_mill, 'mill', 'Miller Cylindrical', 'Cyl, Sph'); @@ -20790,6 +20811,45 @@ var NITER = 9, } +pj_add(pj_nicol, 'nicol', 'Nicolosi Globular', 'Misc Sph, no inv'); + +function pj_nicol(P) { + P.es = 0; + P.fwd = s_fwd; + + function s_fwd(lp, xy) { + var EPS = 1e-10; + if (fabs(lp.lam) < EPS) { + xy.x = 0; + xy.y = lp.phi; + } else if (fabs(lp.phi) < EPS) { + xy.x = lp.lam; + xy.y = 0; + } else if (fabs(fabs(lp.lam) - M_HALFPI) < EPS) { + xy.x = lp.lam * cos(lp.phi); + xy.y = M_HALFPI * sin(lp.phi); + } else if (fabs(fabs(lp.phi) - M_HALFPI) < EPS) { + xy.x = 0; + xy.y = lp.phi; + } else { + var tb = M_HALFPI / lp.lam - lp.lam / M_HALFPI; + var c = lp.phi / M_HALFPI; + var sp = sin(lp.phi); + var d = (1 - c * c) / (sp - c); + var r2 = tb / d; + r2 *= r2; + var m = (tb * sp / d - 0.5 * tb) / (1 + r2); + var n = (sp / r2 + 0.5 * d) / (1 + 1 / r2); + xy.x = cos(lp.phi); + xy.x = sqrt(m * m + xy.x * xy.x / (1 + r2)); + xy.x = M_HALFPI * (m + (lp.lam < 0. ? -xy.x : xy.x)); + xy.y = sqrt(n * n - (sp * sp / r2 + d * sp - 1) / (1 + 1 / r2)); + xy.y = M_HALFPI * (n + (lp.phi < 0. ? xy.y : -xy.y)); + } + } +} + + pj_add(pj_nsper, 'nsper', 'Near-sided perspective', 'Azi, Sph\nh='); pj_add(pj_tpers, 'tpers', 'Tilted perspective', 'Azi, Sph\ntilt= azi= h=');