From 445df7abd643cf7ee6760f7b9c73fa888463dad9 Mon Sep 17 00:00:00 2001 From: "Calvin W. Metcalf B.S" Date: Thu, 1 Aug 2024 15:48:21 -0400 Subject: [PATCH] better export options --- README.md | 15 +- dist/shp.esm.js | 8094 +++++++++++++++++++++++++++++++++++++++++++ dist/shp.esm.min.js | 1 + package.json | 14 +- rollup.config.js | 30 +- test/fixtures.js | 21 + test/index.html | 20 +- test/server.js | 38 +- 8 files changed, 8206 insertions(+), 27 deletions(-) create mode 100644 dist/shp.esm.js create mode 100644 dist/shp.esm.min.js create mode 100644 test/fixtures.js diff --git a/README.md b/README.md index 3f33708..4c1a61e 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,19 @@ If you need a stand alone file to include in your webpage the old fashioned way https://unpkg.com/shpjs@latest/dist/shp.js -NOTE: as of V5 the version you get though npm is an ES module, so make sure you import it instead of requiring it. +or + + https://unpkg.com/shpjs@latest/dist/shp.min.js + When using this library in some sort of bundler for the browser, no polyfills for node apis are required, the only thing needed is some sort of dependency resolver plugin like [rollup node-resolve](https://www.npmjs.com/package/@rollup/plugin-node-resolve) if your bundler doesn't have it, you are almost certainly already using one to get this library anyway. +Addtionally you can import it directly into an esm based web script with + +```js +import shp from 'https://unpkg.com/shpjs@latest/dist/shp.esm.js' +``` + ## API There are 3 ways to use it: @@ -70,6 +79,7 @@ const geojson = await shp(object) If there is only one shp in the zipefile it returns geojson, if there are multiple then it will be an array. All of the geojson objects have an extra key `fileName` the value of which is the name of the shapefile minus the extension (I.E. the part of the name that's the same for all of them). + # links - [wikipedia article](https://en.wikipedia.org/wiki/Shapefile) @@ -82,11 +92,10 @@ name of the shapefile minus the extension (I.E. the part of the name that's the - [Google maps](http://calvinmetcalf.github.io/shapefile-js/site/map.html) - [Local Zipfile](http://leaflet.calvinmetcalf.com) - [Projected big with web workers](http://calvinmetcalf.github.io/shapefile-js/site/proj.html) -- [Projected small]( ## About -Descended in a shipe of theseus way from [RandomEtc's shapefile library](https://github.com/RandomEtc/shapefile-js) no code is shared. +Descended in a ship of theseus way from [RandomEtc's shapefile library](https://github.com/RandomEtc/shapefile-js) no code is shared. - [World Borders shapefile](http://thematicmapping.org/downloads/world_borders.php) is CC-BY-SA 3.0. - Park and Ride shapefile is from [MassDOT](http://mass.gov/massdot) and is public domain. diff --git a/dist/shp.esm.js b/dist/shp.esm.js new file mode 100644 index 0000000..8ecbf45 --- /dev/null +++ b/dist/shp.esm.js @@ -0,0 +1,8094 @@ +function globals(defs) { + defs('EPSG:4326', "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"); + defs('EPSG:4269', "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees"); + defs('EPSG:3857', "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"); + + defs.WGS84 = defs['EPSG:4326']; + defs['EPSG:3785'] = defs['EPSG:3857']; // maintain backward compat, official code is 3857 + defs.GOOGLE = defs['EPSG:3857']; + defs['EPSG:900913'] = defs['EPSG:3857']; + defs['EPSG:102113'] = defs['EPSG:3857']; +} + +var PJD_3PARAM = 1; +var PJD_7PARAM = 2; +var PJD_GRIDSHIFT = 3; +var PJD_WGS84 = 4; // WGS84 or equivalent +var PJD_NODATUM = 5; // WGS84 or equivalent +var SRS_WGS84_SEMIMAJOR = 6378137.0; // only used in grid shift transforms +var SRS_WGS84_SEMIMINOR = 6356752.314; // only used in grid shift transforms +var SRS_WGS84_ESQUARED = 0.0066943799901413165; // only used in grid shift transforms +var SEC_TO_RAD = 4.84813681109535993589914102357e-6; +var HALF_PI = Math.PI/2; +// ellipoid pj_set_ell.c +var SIXTH = 0.1666666666666666667; +/* 1/6 */ +var RA4 = 0.04722222222222222222; +/* 17/360 */ +var RA6 = 0.02215608465608465608; +var EPSLN = 1.0e-10; +// you'd think you could use Number.EPSILON above but that makes +// Mollweide get into an infinate loop. + +var D2R$1 = 0.01745329251994329577; +var R2D = 57.29577951308232088; +var FORTPI = Math.PI/4; +var TWO_PI = Math.PI * 2; +// SPI is slightly greater than Math.PI, so values that exceed the -180..180 +// degree range by a tiny amount don't get wrapped. This prevents points that +// have drifted from their original location along the 180th meridian (due to +// floating point error) from changing their sign. +var SPI = 3.14159265359; + +var exports$2 = {}; + +exports$2.greenwich = 0.0; //"0dE", +exports$2.lisbon = -9.131906111111; //"9d07'54.862\"W", +exports$2.paris = 2.337229166667; //"2d20'14.025\"E", +exports$2.bogota = -74.080916666667; //"74d04'51.3\"W", +exports$2.madrid = -3.687938888889; //"3d41'16.58\"W", +exports$2.rome = 12.452333333333; //"12d27'8.4\"E", +exports$2.bern = 7.439583333333; //"7d26'22.5\"E", +exports$2.jakarta = 106.807719444444; //"106d48'27.79\"E", +exports$2.ferro = -17.666666666667; //"17d40'W", +exports$2.brussels = 4.367975; //"4d22'4.71\"E", +exports$2.stockholm = 18.058277777778; //"18d3'29.8\"E", +exports$2.athens = 23.7163375; //"23d42'58.815\"E", +exports$2.oslo = 10.722916666667; //"10d43'22.5\"E" + +var units = { + ft: {to_meter: 0.3048}, + 'us-ft': {to_meter: 1200 / 3937} +}; + +var ignoredChar = /[\s_\-\/\(\)]/g; +function match(obj, key) { + if (obj[key]) { + return obj[key]; + } + var keys = Object.keys(obj); + var lkey = key.toLowerCase().replace(ignoredChar, ''); + var i = -1; + var testkey, processedKey; + while (++i < keys.length) { + testkey = keys[i]; + processedKey = testkey.toLowerCase().replace(ignoredChar, ''); + if (processedKey === lkey) { + return obj[testkey]; + } + } +} + +function projStr(defData) { + var self = {}; + var paramObj = defData.split('+').map(function(v) { + return v.trim(); + }).filter(function(a) { + return a; + }).reduce(function(p, a) { + var split = a.split('='); + split.push(true); + p[split[0].toLowerCase()] = split[1]; + return p; + }, {}); + var paramName, paramVal, paramOutname; + var params = { + proj: 'projName', + datum: 'datumCode', + rf: function(v) { + self.rf = parseFloat(v); + }, + lat_0: function(v) { + self.lat0 = v * D2R$1; + }, + lat_1: function(v) { + self.lat1 = v * D2R$1; + }, + lat_2: function(v) { + self.lat2 = v * D2R$1; + }, + lat_ts: function(v) { + self.lat_ts = v * D2R$1; + }, + lon_0: function(v) { + self.long0 = v * D2R$1; + }, + lon_1: function(v) { + self.long1 = v * D2R$1; + }, + lon_2: function(v) { + self.long2 = v * D2R$1; + }, + alpha: function(v) { + self.alpha = parseFloat(v) * D2R$1; + }, + gamma: function(v) { + self.rectified_grid_angle = parseFloat(v); + }, + lonc: function(v) { + self.longc = v * D2R$1; + }, + x_0: function(v) { + self.x0 = parseFloat(v); + }, + y_0: function(v) { + self.y0 = parseFloat(v); + }, + k_0: function(v) { + self.k0 = parseFloat(v); + }, + k: function(v) { + self.k0 = parseFloat(v); + }, + a: function(v) { + self.a = parseFloat(v); + }, + b: function(v) { + self.b = parseFloat(v); + }, + r_a: function() { + self.R_A = true; + }, + zone: function(v) { + self.zone = parseInt(v, 10); + }, + south: function() { + self.utmSouth = true; + }, + towgs84: function(v) { + self.datum_params = v.split(",").map(function(a) { + return parseFloat(a); + }); + }, + to_meter: function(v) { + self.to_meter = parseFloat(v); + }, + units: function(v) { + self.units = v; + var unit = match(units, v); + if (unit) { + self.to_meter = unit.to_meter; + } + }, + from_greenwich: function(v) { + self.from_greenwich = v * D2R$1; + }, + pm: function(v) { + var pm = match(exports$2, v); + self.from_greenwich = (pm ? pm : parseFloat(v)) * D2R$1; + }, + nadgrids: function(v) { + if (v === '@null') { + self.datumCode = 'none'; + } + else { + self.nadgrids = v; + } + }, + axis: function(v) { + var legalAxis = "ewnsud"; + if (v.length === 3 && legalAxis.indexOf(v.substr(0, 1)) !== -1 && legalAxis.indexOf(v.substr(1, 1)) !== -1 && legalAxis.indexOf(v.substr(2, 1)) !== -1) { + self.axis = v; + } + }, + approx: function() { + self.approx = true; + } + }; + for (paramName in paramObj) { + paramVal = paramObj[paramName]; + if (paramName in params) { + paramOutname = params[paramName]; + if (typeof paramOutname === 'function') { + paramOutname(paramVal); + } + else { + self[paramOutname] = paramVal; + } + } + else { + self[paramName] = paramVal; + } + } + if(typeof self.datumCode === 'string' && self.datumCode !== "WGS84"){ + self.datumCode = self.datumCode.toLowerCase(); + } + return self; +} + +var NEUTRAL = 1; +var KEYWORD = 2; +var NUMBER = 3; +var QUOTED = 4; +var AFTERQUOTE = 5; +var ENDED = -1; +var whitespace = /\s/; +var latin = /[A-Za-z]/; +var keyword = /[A-Za-z84_]/; +var endThings = /[,\]]/; +var digets = /[\d\.E\-\+]/; +// const ignoredChar = /[\s_\-\/\(\)]/g; +function Parser(text) { + if (typeof text !== 'string') { + throw new Error('not a string'); + } + this.text = text.trim(); + this.level = 0; + this.place = 0; + this.root = null; + this.stack = []; + this.currentObject = null; + this.state = NEUTRAL; +} +Parser.prototype.readCharicter = function() { + var char = this.text[this.place++]; + if (this.state !== QUOTED) { + while (whitespace.test(char)) { + if (this.place >= this.text.length) { + return; + } + char = this.text[this.place++]; + } + } + switch (this.state) { + case NEUTRAL: + return this.neutral(char); + case KEYWORD: + return this.keyword(char) + case QUOTED: + return this.quoted(char); + case AFTERQUOTE: + return this.afterquote(char); + case NUMBER: + return this.number(char); + case ENDED: + return; + } +}; +Parser.prototype.afterquote = function(char) { + if (char === '"') { + this.word += '"'; + this.state = QUOTED; + return; + } + if (endThings.test(char)) { + this.word = this.word.trim(); + this.afterItem(char); + return; + } + throw new Error('havn\'t handled "' +char + '" in afterquote yet, index ' + this.place); +}; +Parser.prototype.afterItem = function(char) { + if (char === ',') { + if (this.word !== null) { + this.currentObject.push(this.word); + } + this.word = null; + this.state = NEUTRAL; + return; + } + if (char === ']') { + this.level--; + if (this.word !== null) { + this.currentObject.push(this.word); + this.word = null; + } + this.state = NEUTRAL; + this.currentObject = this.stack.pop(); + if (!this.currentObject) { + this.state = ENDED; + } + + return; + } +}; +Parser.prototype.number = function(char) { + if (digets.test(char)) { + this.word += char; + return; + } + if (endThings.test(char)) { + this.word = parseFloat(this.word); + this.afterItem(char); + return; + } + throw new Error('havn\'t handled "' +char + '" in number yet, index ' + this.place); +}; +Parser.prototype.quoted = function(char) { + if (char === '"') { + this.state = AFTERQUOTE; + return; + } + this.word += char; + return; +}; +Parser.prototype.keyword = function(char) { + if (keyword.test(char)) { + this.word += char; + return; + } + if (char === '[') { + var newObjects = []; + newObjects.push(this.word); + this.level++; + if (this.root === null) { + this.root = newObjects; + } else { + this.currentObject.push(newObjects); + } + this.stack.push(this.currentObject); + this.currentObject = newObjects; + this.state = NEUTRAL; + return; + } + if (endThings.test(char)) { + this.afterItem(char); + return; + } + throw new Error('havn\'t handled "' +char + '" in keyword yet, index ' + this.place); +}; +Parser.prototype.neutral = function(char) { + if (latin.test(char)) { + this.word = char; + this.state = KEYWORD; + return; + } + if (char === '"') { + this.word = ''; + this.state = QUOTED; + return; + } + if (digets.test(char)) { + this.word = char; + this.state = NUMBER; + return; + } + if (endThings.test(char)) { + this.afterItem(char); + return; + } + throw new Error('havn\'t handled "' +char + '" in neutral yet, index ' + this.place); +}; +Parser.prototype.output = function() { + while (this.place < this.text.length) { + this.readCharicter(); + } + if (this.state === ENDED) { + return this.root; + } + throw new Error('unable to parse string "' +this.text + '". State is ' + this.state); +}; + +function parseString(txt) { + var parser = new Parser(txt); + return parser.output(); +} + +function mapit(obj, key, value) { + if (Array.isArray(key)) { + value.unshift(key); + key = null; + } + var thing = key ? {} : obj; + + var out = value.reduce(function(newObj, item) { + sExpr(item, newObj); + return newObj + }, thing); + if (key) { + obj[key] = out; + } +} + +function sExpr(v, obj) { + if (!Array.isArray(v)) { + obj[v] = true; + return; + } + var key = v.shift(); + if (key === 'PARAMETER') { + key = v.shift(); + } + if (v.length === 1) { + if (Array.isArray(v[0])) { + obj[key] = {}; + sExpr(v[0], obj[key]); + return; + } + obj[key] = v[0]; + return; + } + if (!v.length) { + obj[key] = true; + return; + } + if (key === 'TOWGS84') { + obj[key] = v; + return; + } + if (key === 'AXIS') { + if (!(key in obj)) { + obj[key] = []; + } + obj[key].push(v); + return; + } + if (!Array.isArray(key)) { + obj[key] = {}; + } + + var i; + switch (key) { + case 'UNIT': + case 'PRIMEM': + case 'VERT_DATUM': + obj[key] = { + name: v[0].toLowerCase(), + convert: v[1] + }; + if (v.length === 3) { + sExpr(v[2], obj[key]); + } + return; + case 'SPHEROID': + case 'ELLIPSOID': + obj[key] = { + name: v[0], + a: v[1], + rf: v[2] + }; + if (v.length === 4) { + sExpr(v[3], obj[key]); + } + return; + case 'PROJECTEDCRS': + case 'PROJCRS': + case 'GEOGCS': + case 'GEOCCS': + case 'PROJCS': + case 'LOCAL_CS': + case 'GEODCRS': + case 'GEODETICCRS': + case 'GEODETICDATUM': + case 'EDATUM': + case 'ENGINEERINGDATUM': + case 'VERT_CS': + case 'VERTCRS': + case 'VERTICALCRS': + case 'COMPD_CS': + case 'COMPOUNDCRS': + case 'ENGINEERINGCRS': + case 'ENGCRS': + case 'FITTED_CS': + case 'LOCAL_DATUM': + case 'DATUM': + v[0] = ['name', v[0]]; + mapit(obj, key, v); + return; + default: + i = -1; + while (++i < v.length) { + if (!Array.isArray(v[i])) { + return sExpr(v, obj[key]); + } + } + return mapit(obj, key, v); + } +} + +var D2R = 0.01745329251994329577; + + + +function rename(obj, params) { + var outName = params[0]; + var inName = params[1]; + if (!(outName in obj) && (inName in obj)) { + obj[outName] = obj[inName]; + if (params.length === 3) { + obj[outName] = params[2](obj[outName]); + } + } +} + +function d2r(input) { + return input * D2R; +} + +function cleanWKT(wkt) { + if (wkt.type === 'GEOGCS') { + wkt.projName = 'longlat'; + } else if (wkt.type === 'LOCAL_CS') { + wkt.projName = 'identity'; + wkt.local = true; + } else { + if (typeof wkt.PROJECTION === 'object') { + wkt.projName = Object.keys(wkt.PROJECTION)[0]; + } else { + wkt.projName = wkt.PROJECTION; + } + } + if (wkt.AXIS) { + var axisOrder = ''; + for (var i = 0, ii = wkt.AXIS.length; i < ii; ++i) { + var axis = [wkt.AXIS[i][0].toLowerCase(), wkt.AXIS[i][1].toLowerCase()]; + if (axis[0].indexOf('north') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'north')) { + axisOrder += 'n'; + } else if (axis[0].indexOf('south') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'south')) { + axisOrder += 's'; + } else if (axis[0].indexOf('east') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'east')) { + axisOrder += 'e'; + } else if (axis[0].indexOf('west') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'west')) { + axisOrder += 'w'; + } + } + if (axisOrder.length === 2) { + axisOrder += 'u'; + } + if (axisOrder.length === 3) { + wkt.axis = axisOrder; + } + } + if (wkt.UNIT) { + wkt.units = wkt.UNIT.name.toLowerCase(); + if (wkt.units === 'metre') { + wkt.units = 'meter'; + } + if (wkt.UNIT.convert) { + if (wkt.type === 'GEOGCS') { + if (wkt.DATUM && wkt.DATUM.SPHEROID) { + wkt.to_meter = wkt.UNIT.convert*wkt.DATUM.SPHEROID.a; + } + } else { + wkt.to_meter = wkt.UNIT.convert; + } + } + } + var geogcs = wkt.GEOGCS; + if (wkt.type === 'GEOGCS') { + geogcs = wkt; + } + if (geogcs) { + //if(wkt.GEOGCS.PRIMEM&&wkt.GEOGCS.PRIMEM.convert){ + // wkt.from_greenwich=wkt.GEOGCS.PRIMEM.convert*D2R; + //} + if (geogcs.DATUM) { + wkt.datumCode = geogcs.DATUM.name.toLowerCase(); + } else { + wkt.datumCode = geogcs.name.toLowerCase(); + } + if (wkt.datumCode.slice(0, 2) === 'd_') { + wkt.datumCode = wkt.datumCode.slice(2); + } + if (wkt.datumCode === 'new_zealand_geodetic_datum_1949' || wkt.datumCode === 'new_zealand_1949') { + wkt.datumCode = 'nzgd49'; + } + if (wkt.datumCode === 'wgs_1984' || wkt.datumCode === 'world_geodetic_system_1984') { + if (wkt.PROJECTION === 'Mercator_Auxiliary_Sphere') { + wkt.sphere = true; + } + wkt.datumCode = 'wgs84'; + } + if (wkt.datumCode.slice(-6) === '_ferro') { + wkt.datumCode = wkt.datumCode.slice(0, - 6); + } + if (wkt.datumCode.slice(-8) === '_jakarta') { + wkt.datumCode = wkt.datumCode.slice(0, - 8); + } + if (~wkt.datumCode.indexOf('belge')) { + wkt.datumCode = 'rnb72'; + } + if (geogcs.DATUM && geogcs.DATUM.SPHEROID) { + wkt.ellps = geogcs.DATUM.SPHEROID.name.replace('_19', '').replace(/[Cc]larke\_18/, 'clrk'); + if (wkt.ellps.toLowerCase().slice(0, 13) === 'international') { + wkt.ellps = 'intl'; + } + + wkt.a = geogcs.DATUM.SPHEROID.a; + wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf, 10); + } + + if (geogcs.DATUM && geogcs.DATUM.TOWGS84) { + wkt.datum_params = geogcs.DATUM.TOWGS84; + } + if (~wkt.datumCode.indexOf('osgb_1936')) { + wkt.datumCode = 'osgb36'; + } + if (~wkt.datumCode.indexOf('osni_1952')) { + wkt.datumCode = 'osni52'; + } + if (~wkt.datumCode.indexOf('tm65') + || ~wkt.datumCode.indexOf('geodetic_datum_of_1965')) { + wkt.datumCode = 'ire65'; + } + if (wkt.datumCode === 'ch1903+') { + wkt.datumCode = 'ch1903'; + } + if (~wkt.datumCode.indexOf('israel')) { + wkt.datumCode = 'isr93'; + } + } + if (wkt.b && !isFinite(wkt.b)) { + wkt.b = wkt.a; + } + + function toMeter(input) { + var ratio = wkt.to_meter || 1; + return input * ratio; + } + var renamer = function(a) { + return rename(wkt, a); + }; + var list = [ + ['standard_parallel_1', 'Standard_Parallel_1'], + ['standard_parallel_1', 'Latitude of 1st standard parallel'], + ['standard_parallel_2', 'Standard_Parallel_2'], + ['standard_parallel_2', 'Latitude of 2nd standard parallel'], + ['false_easting', 'False_Easting'], + ['false_easting', 'False easting'], + ['false-easting', 'Easting at false origin'], + ['false_northing', 'False_Northing'], + ['false_northing', 'False northing'], + ['false_northing', 'Northing at false origin'], + ['central_meridian', 'Central_Meridian'], + ['central_meridian', 'Longitude of natural origin'], + ['central_meridian', 'Longitude of false origin'], + ['latitude_of_origin', 'Latitude_Of_Origin'], + ['latitude_of_origin', 'Central_Parallel'], + ['latitude_of_origin', 'Latitude of natural origin'], + ['latitude_of_origin', 'Latitude of false origin'], + ['scale_factor', 'Scale_Factor'], + ['k0', 'scale_factor'], + ['latitude_of_center', 'Latitude_Of_Center'], + ['latitude_of_center', 'Latitude_of_center'], + ['lat0', 'latitude_of_center', d2r], + ['longitude_of_center', 'Longitude_Of_Center'], + ['longitude_of_center', 'Longitude_of_center'], + ['longc', 'longitude_of_center', d2r], + ['x0', 'false_easting', toMeter], + ['y0', 'false_northing', toMeter], + ['long0', 'central_meridian', d2r], + ['lat0', 'latitude_of_origin', d2r], + ['lat0', 'standard_parallel_1', d2r], + ['lat1', 'standard_parallel_1', d2r], + ['lat2', 'standard_parallel_2', d2r], + ['azimuth', 'Azimuth'], + ['alpha', 'azimuth', d2r], + ['srsCode', 'name'] + ]; + list.forEach(renamer); + if (!wkt.long0 && wkt.longc && (wkt.projName === 'Albers_Conic_Equal_Area' || wkt.projName === 'Lambert_Azimuthal_Equal_Area')) { + wkt.long0 = wkt.longc; + } + if (!wkt.lat_ts && wkt.lat1 && (wkt.projName === 'Stereographic_South_Pole' || wkt.projName === 'Polar Stereographic (variant B)')) { + wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90); + wkt.lat_ts = wkt.lat1; + } else if (!wkt.lat_ts && wkt.lat0 && wkt.projName === 'Polar_Stereographic') { + wkt.lat_ts = wkt.lat0; + wkt.lat0 = d2r(wkt.lat0 > 0 ? 90 : -90); + } +} +function wkt(wkt) { + var lisp = parseString(wkt); + var type = lisp.shift(); + var name = lisp.shift(); + lisp.unshift(['name', name]); + lisp.unshift(['type', type]); + var obj = {}; + sExpr(lisp, obj); + cleanWKT(obj); + return obj; +} + +function defs(name) { + /*global console*/ + var that = this; + if (arguments.length === 2) { + var def = arguments[1]; + if (typeof def === 'string') { + if (def.charAt(0) === '+') { + defs[name] = projStr(arguments[1]); + } + else { + defs[name] = wkt(arguments[1]); + } + } else { + defs[name] = def; + } + } + else if (arguments.length === 1) { + if (Array.isArray(name)) { + return name.map(function(v) { + if (Array.isArray(v)) { + defs.apply(that, v); + } + else { + defs(v); + } + }); + } + else if (typeof name === 'string') { + if (name in defs) { + return defs[name]; + } + } + else if ('EPSG' in name) { + defs['EPSG:' + name.EPSG] = name; + } + else if ('ESRI' in name) { + defs['ESRI:' + name.ESRI] = name; + } + else if ('IAU2000' in name) { + defs['IAU2000:' + name.IAU2000] = name; + } + else { + console.log(name); + } + return; + } + + +} +globals(defs); + +function testObj(code){ + return typeof code === 'string'; +} +function testDef(code){ + return code in defs; +} +var codeWords = ['PROJECTEDCRS', 'PROJCRS', 'GEOGCS','GEOCCS','PROJCS','LOCAL_CS', 'GEODCRS', 'GEODETICCRS', 'GEODETICDATUM', 'ENGCRS', 'ENGINEERINGCRS']; +function testWKT(code){ + return codeWords.some(function (word) { + return code.indexOf(word) > -1; + }); +} +var codes = ['3857', '900913', '3785', '102113']; +function checkMercator(item) { + var auth = match(item, 'authority'); + if (!auth) { + return; + } + var code = match(auth, 'epsg'); + return code && codes.indexOf(code) > -1; +} +function checkProjStr(item) { + var ext = match(item, 'extension'); + if (!ext) { + return; + } + return match(ext, 'proj4'); +} +function testProj(code){ + return code[0] === '+'; +} +function parse(code){ + if (testObj(code)) { + //check to see if this is a WKT string + if (testDef(code)) { + return defs[code]; + } + if (testWKT(code)) { + var out = wkt(code); + // test of spetial case, due to this being a very common and often malformed + if (checkMercator(out)) { + return defs['EPSG:3857']; + } + var maybeProjStr = checkProjStr(out); + if (maybeProjStr) { + return projStr(maybeProjStr); + } + return out; + } + if (testProj(code)) { + return projStr(code); + } + }else { + return code; + } +} + +function extend(destination, source) { + destination = destination || {}; + var value, property; + if (!source) { + return destination; + } + for (property in source) { + value = source[property]; + if (value !== undefined) { + destination[property] = value; + } + } + return destination; +} + +function msfnz(eccent, sinphi, cosphi) { + var con = eccent * sinphi; + return cosphi / (Math.sqrt(1 - con * con)); +} + +function sign(x) { + return x<0 ? -1 : 1; +} + +function adjust_lon(x) { + return (Math.abs(x) <= SPI) ? x : (x - (sign(x) * TWO_PI)); +} + +function tsfnz(eccent, phi, sinphi) { + var con = eccent * sinphi; + var com = 0.5 * eccent; + con = Math.pow(((1 - con) / (1 + con)), com); + return (Math.tan(0.5 * (HALF_PI - phi)) / con); +} + +function phi2z(eccent, ts) { + var eccnth = 0.5 * eccent; + var con, dphi; + var phi = HALF_PI - 2 * Math.atan(ts); + for (var i = 0; i <= 15; i++) { + con = eccent * Math.sin(phi); + dphi = HALF_PI - 2 * Math.atan(ts * (Math.pow(((1 - con) / (1 + con)), eccnth))) - phi; + phi += dphi; + if (Math.abs(dphi) <= 0.0000000001) { + return phi; + } + } + //console.log("phi2z has NoConvergence"); + return -9999; +} + +function init$v() { + var con = this.b / this.a; + this.es = 1 - con * con; + if(!('x0' in this)){ + this.x0 = 0; + } + if(!('y0' in this)){ + this.y0 = 0; + } + this.e = Math.sqrt(this.es); + if (this.lat_ts) { + if (this.sphere) { + this.k0 = Math.cos(this.lat_ts); + } + else { + this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)); + } + } + else { + if (!this.k0) { + if (this.k) { + this.k0 = this.k; + } + else { + this.k0 = 1; + } + } + } +} + +/* Mercator forward equations--mapping lat,long to x,y + --------------------------------------------------*/ + +function forward$u(p) { + var lon = p.x; + var lat = p.y; + // convert to radians + if (lat * R2D > 90 && lat * R2D < -90 && lon * R2D > 180 && lon * R2D < -180) { + return null; + } + + var x, y; + if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) { + return null; + } + else { + if (this.sphere) { + x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0); + y = this.y0 + this.a * this.k0 * Math.log(Math.tan(FORTPI + 0.5 * lat)); + } + else { + var sinphi = Math.sin(lat); + var ts = tsfnz(this.e, lat, sinphi); + x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0); + y = this.y0 - this.a * this.k0 * Math.log(ts); + } + p.x = x; + p.y = y; + return p; + } +} + +/* Mercator inverse equations--mapping x,y to lat/long + --------------------------------------------------*/ +function inverse$u(p) { + + var x = p.x - this.x0; + var y = p.y - this.y0; + var lon, lat; + + if (this.sphere) { + lat = HALF_PI - 2 * Math.atan(Math.exp(-y / (this.a * this.k0))); + } + else { + var ts = Math.exp(-y / (this.a * this.k0)); + lat = phi2z(this.e, ts); + if (lat === -9999) { + return null; + } + } + lon = adjust_lon(this.long0 + x / (this.a * this.k0)); + + p.x = lon; + p.y = lat; + return p; +} + +var names$w = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "merc"]; +var merc = { + init: init$v, + forward: forward$u, + inverse: inverse$u, + names: names$w +}; + +function init$u() { + //no-op for longlat +} + +function identity(pt) { + return pt; +} +var names$v = ["longlat", "identity"]; +var longlat = { + init: init$u, + forward: identity, + inverse: identity, + names: names$v +}; + +var projs = [merc, longlat]; +var names$u = {}; +var projStore = []; + +function add(proj, i) { + var len = projStore.length; + if (!proj.names) { + console.log(i); + return true; + } + projStore[len] = proj; + proj.names.forEach(function(n) { + names$u[n.toLowerCase()] = len; + }); + return this; +} + +function get(name) { + if (!name) { + return false; + } + var n = name.toLowerCase(); + if (typeof names$u[n] !== 'undefined' && projStore[names$u[n]]) { + return projStore[names$u[n]]; + } +} + +function start() { + projs.forEach(add); +} +var projections = { + start: start, + add: add, + get: get +}; + +var exports$1 = {}; +exports$1.MERIT = { + a: 6378137.0, + rf: 298.257, + ellipseName: "MERIT 1983" +}; + +exports$1.SGS85 = { + a: 6378136.0, + rf: 298.257, + ellipseName: "Soviet Geodetic System 85" +}; + +exports$1.GRS80 = { + a: 6378137.0, + rf: 298.257222101, + ellipseName: "GRS 1980(IUGG, 1980)" +}; + +exports$1.IAU76 = { + a: 6378140.0, + rf: 298.257, + ellipseName: "IAU 1976" +}; + +exports$1.airy = { + a: 6377563.396, + b: 6356256.910, + ellipseName: "Airy 1830" +}; + +exports$1.APL4 = { + a: 6378137, + rf: 298.25, + ellipseName: "Appl. Physics. 1965" +}; + +exports$1.NWL9D = { + a: 6378145.0, + rf: 298.25, + ellipseName: "Naval Weapons Lab., 1965" +}; + +exports$1.mod_airy = { + a: 6377340.189, + b: 6356034.446, + ellipseName: "Modified Airy" +}; + +exports$1.andrae = { + a: 6377104.43, + rf: 300.0, + ellipseName: "Andrae 1876 (Den., Iclnd.)" +}; + +exports$1.aust_SA = { + a: 6378160.0, + rf: 298.25, + ellipseName: "Australian Natl & S. Amer. 1969" +}; + +exports$1.GRS67 = { + a: 6378160.0, + rf: 298.2471674270, + ellipseName: "GRS 67(IUGG 1967)" +}; + +exports$1.bessel = { + a: 6377397.155, + rf: 299.1528128, + ellipseName: "Bessel 1841" +}; + +exports$1.bess_nam = { + a: 6377483.865, + rf: 299.1528128, + ellipseName: "Bessel 1841 (Namibia)" +}; + +exports$1.clrk66 = { + a: 6378206.4, + b: 6356583.8, + ellipseName: "Clarke 1866" +}; + +exports$1.clrk80 = { + a: 6378249.145, + rf: 293.4663, + ellipseName: "Clarke 1880 mod." +}; + +exports$1.clrk80ign = { + a: 6378249.2, + b: 6356515, + rf: 293.4660213, + ellipseName: "Clarke 1880 (IGN)" +}; + +exports$1.clrk58 = { + a: 6378293.645208759, + rf: 294.2606763692654, + ellipseName: "Clarke 1858" +}; + +exports$1.CPM = { + a: 6375738.7, + rf: 334.29, + ellipseName: "Comm. des Poids et Mesures 1799" +}; + +exports$1.delmbr = { + a: 6376428.0, + rf: 311.5, + ellipseName: "Delambre 1810 (Belgium)" +}; + +exports$1.engelis = { + a: 6378136.05, + rf: 298.2566, + ellipseName: "Engelis 1985" +}; + +exports$1.evrst30 = { + a: 6377276.345, + rf: 300.8017, + ellipseName: "Everest 1830" +}; + +exports$1.evrst48 = { + a: 6377304.063, + rf: 300.8017, + ellipseName: "Everest 1948" +}; + +exports$1.evrst56 = { + a: 6377301.243, + rf: 300.8017, + ellipseName: "Everest 1956" +}; + +exports$1.evrst69 = { + a: 6377295.664, + rf: 300.8017, + ellipseName: "Everest 1969" +}; + +exports$1.evrstSS = { + a: 6377298.556, + rf: 300.8017, + ellipseName: "Everest (Sabah & Sarawak)" +}; + +exports$1.fschr60 = { + a: 6378166.0, + rf: 298.3, + ellipseName: "Fischer (Mercury Datum) 1960" +}; + +exports$1.fschr60m = { + a: 6378155.0, + rf: 298.3, + ellipseName: "Fischer 1960" +}; + +exports$1.fschr68 = { + a: 6378150.0, + rf: 298.3, + ellipseName: "Fischer 1968" +}; + +exports$1.helmert = { + a: 6378200.0, + rf: 298.3, + ellipseName: "Helmert 1906" +}; + +exports$1.hough = { + a: 6378270.0, + rf: 297.0, + ellipseName: "Hough" +}; + +exports$1.intl = { + a: 6378388.0, + rf: 297.0, + ellipseName: "International 1909 (Hayford)" +}; + +exports$1.kaula = { + a: 6378163.0, + rf: 298.24, + ellipseName: "Kaula 1961" +}; + +exports$1.lerch = { + a: 6378139.0, + rf: 298.257, + ellipseName: "Lerch 1979" +}; + +exports$1.mprts = { + a: 6397300.0, + rf: 191.0, + ellipseName: "Maupertius 1738" +}; + +exports$1.new_intl = { + a: 6378157.5, + b: 6356772.2, + ellipseName: "New International 1967" +}; + +exports$1.plessis = { + a: 6376523.0, + rf: 6355863.0, + ellipseName: "Plessis 1817 (France)" +}; + +exports$1.krass = { + a: 6378245.0, + rf: 298.3, + ellipseName: "Krassovsky, 1942" +}; + +exports$1.SEasia = { + a: 6378155.0, + b: 6356773.3205, + ellipseName: "Southeast Asia" +}; + +exports$1.walbeck = { + a: 6376896.0, + b: 6355834.8467, + ellipseName: "Walbeck" +}; + +exports$1.WGS60 = { + a: 6378165.0, + rf: 298.3, + ellipseName: "WGS 60" +}; + +exports$1.WGS66 = { + a: 6378145.0, + rf: 298.25, + ellipseName: "WGS 66" +}; + +exports$1.WGS7 = { + a: 6378135.0, + rf: 298.26, + ellipseName: "WGS 72" +}; + +var WGS84 = exports$1.WGS84 = { + a: 6378137.0, + rf: 298.257223563, + ellipseName: "WGS 84" +}; + +exports$1.sphere = { + a: 6370997.0, + b: 6370997.0, + ellipseName: "Normal Sphere (r=6370997)" +}; + +function eccentricity(a, b, rf, R_A) { + var a2 = a * a; // used in geocentric + var b2 = b * b; // used in geocentric + var es = (a2 - b2) / a2; // e ^ 2 + var e = 0; + if (R_A) { + a *= 1 - es * (SIXTH + es * (RA4 + es * RA6)); + a2 = a * a; + es = 0; + } else { + e = Math.sqrt(es); // eccentricity + } + var ep2 = (a2 - b2) / b2; // used in geocentric + return { + es: es, + e: e, + ep2: ep2 + }; +} +function sphere(a, b, rf, ellps, sphere) { + if (!a) { // do we have an ellipsoid? + var ellipse = match(exports$1, ellps); + if (!ellipse) { + ellipse = WGS84; + } + a = ellipse.a; + b = ellipse.b; + rf = ellipse.rf; + } + + if (rf && !b) { + b = (1.0 - 1.0 / rf) * a; + } + if (rf === 0 || Math.abs(a - b) < EPSLN) { + sphere = true; + b = a; + } + return { + a: a, + b: b, + rf: rf, + sphere: sphere + }; +} + +var exports = {}; +exports.wgs84 = { + towgs84: "0,0,0", + ellipse: "WGS84", + datumName: "WGS84" +}; + +exports.ch1903 = { + towgs84: "674.374,15.056,405.346", + ellipse: "bessel", + datumName: "swiss" +}; + +exports.ggrs87 = { + towgs84: "-199.87,74.79,246.62", + ellipse: "GRS80", + datumName: "Greek_Geodetic_Reference_System_1987" +}; + +exports.nad83 = { + towgs84: "0,0,0", + ellipse: "GRS80", + datumName: "North_American_Datum_1983" +}; + +exports.nad27 = { + nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat", + ellipse: "clrk66", + datumName: "North_American_Datum_1927" +}; + +exports.potsdam = { + towgs84: "598.1,73.7,418.2,0.202,0.045,-2.455,6.7", + ellipse: "bessel", + datumName: "Potsdam Rauenberg 1950 DHDN" +}; + +exports.carthage = { + towgs84: "-263.0,6.0,431.0", + ellipse: "clark80", + datumName: "Carthage 1934 Tunisia" +}; + +exports.hermannskogel = { + towgs84: "577.326,90.129,463.919,5.137,1.474,5.297,2.4232", + ellipse: "bessel", + datumName: "Hermannskogel" +}; + +exports.militargeographische_institut = { + towgs84: "577.326,90.129,463.919,5.137,1.474,5.297,2.4232", + ellipse: "bessel", + datumName: "Militar-Geographische Institut" +}; + +exports.osni52 = { + towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", + ellipse: "airy", + datumName: "Irish National" +}; + +exports.ire65 = { + towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", + ellipse: "mod_airy", + datumName: "Ireland 1965" +}; + +exports.rassadiran = { + towgs84: "-133.63,-157.5,-158.62", + ellipse: "intl", + datumName: "Rassadiran" +}; + +exports.nzgd49 = { + towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", + ellipse: "intl", + datumName: "New Zealand Geodetic Datum 1949" +}; + +exports.osgb36 = { + towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", + ellipse: "airy", + datumName: "Airy 1830" +}; + +exports.s_jtsk = { + towgs84: "589,76,480", + ellipse: 'bessel', + datumName: 'S-JTSK (Ferro)' +}; + +exports.beduaram = { + towgs84: '-106,-87,188', + ellipse: 'clrk80', + datumName: 'Beduaram' +}; + +exports.gunung_segara = { + towgs84: '-403,684,41', + ellipse: 'bessel', + datumName: 'Gunung Segara Jakarta' +}; + +exports.rnb72 = { + towgs84: "106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1", + ellipse: "intl", + datumName: "Reseau National Belge 1972" +}; + +function datum(datumCode, datum_params, a, b, es, ep2, nadgrids) { + var out = {}; + + if (datumCode === undefined || datumCode === 'none') { + out.datum_type = PJD_NODATUM; + } else { + out.datum_type = PJD_WGS84; + } + + if (datum_params) { + out.datum_params = datum_params.map(parseFloat); + if (out.datum_params[0] !== 0 || out.datum_params[1] !== 0 || out.datum_params[2] !== 0) { + out.datum_type = PJD_3PARAM; + } + if (out.datum_params.length > 3) { + if (out.datum_params[3] !== 0 || out.datum_params[4] !== 0 || out.datum_params[5] !== 0 || out.datum_params[6] !== 0) { + out.datum_type = PJD_7PARAM; + out.datum_params[3] *= SEC_TO_RAD; + out.datum_params[4] *= SEC_TO_RAD; + out.datum_params[5] *= SEC_TO_RAD; + out.datum_params[6] = (out.datum_params[6] / 1000000.0) + 1.0; + } + } + } + + if (nadgrids) { + out.datum_type = PJD_GRIDSHIFT; + out.grids = nadgrids; + } + out.a = a; //datum object also uses these values + out.b = b; + out.es = es; + out.ep2 = ep2; + return out; +} + +/** + * Resources for details of NTv2 file formats: + * - https://web.archive.org/web/20140127204822if_/http://www.mgs.gov.on.ca:80/stdprodconsume/groups/content/@mgs/@iandit/documents/resourcelist/stel02_047447.pdf + * - http://mimaka.com/help/gs/html/004_NTV2%20Data%20Format.htm + */ + +var loadedNadgrids = {}; + +/** + * Load a binary NTv2 file (.gsb) to a key that can be used in a proj string like +nadgrids=. Pass the NTv2 file + * as an ArrayBuffer. + */ +function nadgrid(key, data) { + var view = new DataView(data); + var isLittleEndian = detectLittleEndian(view); + var header = readHeader(view, isLittleEndian); + var subgrids = readSubgrids(view, header, isLittleEndian); + var nadgrid = {header: header, subgrids: subgrids}; + loadedNadgrids[key] = nadgrid; + return nadgrid; +} + +/** + * Given a proj4 value for nadgrids, return an array of loaded grids + */ +function getNadgrids(nadgrids) { + // Format details: http://proj.maptools.org/gen_parms.html + if (nadgrids === undefined) { return null; } + var grids = nadgrids.split(','); + return grids.map(parseNadgridString); +} + +function parseNadgridString(value) { + if (value.length === 0) { + return null; + } + var optional = value[0] === '@'; + if (optional) { + value = value.slice(1); + } + if (value === 'null') { + return {name: 'null', mandatory: !optional, grid: null, isNull: true}; + } + return { + name: value, + mandatory: !optional, + grid: loadedNadgrids[value] || null, + isNull: false + }; +} + +function secondsToRadians(seconds) { + return (seconds / 3600) * Math.PI / 180; +} + +function detectLittleEndian(view) { + var nFields = view.getInt32(8, false); + if (nFields === 11) { + return false; + } + nFields = view.getInt32(8, true); + if (nFields !== 11) { + console.warn('Failed to detect nadgrid endian-ness, defaulting to little-endian'); + } + return true; +} + +function readHeader(view, isLittleEndian) { + return { + nFields: view.getInt32(8, isLittleEndian), + nSubgridFields: view.getInt32(24, isLittleEndian), + nSubgrids: view.getInt32(40, isLittleEndian), + shiftType: decodeString(view, 56, 56 + 8).trim(), + fromSemiMajorAxis: view.getFloat64(120, isLittleEndian), + fromSemiMinorAxis: view.getFloat64(136, isLittleEndian), + toSemiMajorAxis: view.getFloat64(152, isLittleEndian), + toSemiMinorAxis: view.getFloat64(168, isLittleEndian), + }; +} + +function decodeString(view, start, end) { + return String.fromCharCode.apply(null, new Uint8Array(view.buffer.slice(start, end))); +} + +function readSubgrids(view, header, isLittleEndian) { + var gridOffset = 176; + var grids = []; + for (var i = 0; i < header.nSubgrids; i++) { + var subHeader = readGridHeader(view, gridOffset, isLittleEndian); + var nodes = readGridNodes(view, gridOffset, subHeader, isLittleEndian); + var lngColumnCount = Math.round( + 1 + (subHeader.upperLongitude - subHeader.lowerLongitude) / subHeader.longitudeInterval); + var latColumnCount = Math.round( + 1 + (subHeader.upperLatitude - subHeader.lowerLatitude) / subHeader.latitudeInterval); + // Proj4 operates on radians whereas the coordinates are in seconds in the grid + grids.push({ + ll: [secondsToRadians(subHeader.lowerLongitude), secondsToRadians(subHeader.lowerLatitude)], + del: [secondsToRadians(subHeader.longitudeInterval), secondsToRadians(subHeader.latitudeInterval)], + lim: [lngColumnCount, latColumnCount], + count: subHeader.gridNodeCount, + cvs: mapNodes(nodes) + }); + gridOffset += 176 + subHeader.gridNodeCount * 16; + } + return grids; +} + +function mapNodes(nodes) { + return nodes.map(function (r) {return [secondsToRadians(r.longitudeShift), secondsToRadians(r.latitudeShift)];}); +} + +function readGridHeader(view, offset, isLittleEndian) { + return { + name: decodeString(view, offset + 8, offset + 16).trim(), + parent: decodeString(view, offset + 24, offset + 24 + 8).trim(), + lowerLatitude: view.getFloat64(offset + 72, isLittleEndian), + upperLatitude: view.getFloat64(offset + 88, isLittleEndian), + lowerLongitude: view.getFloat64(offset + 104, isLittleEndian), + upperLongitude: view.getFloat64(offset + 120, isLittleEndian), + latitudeInterval: view.getFloat64(offset + 136, isLittleEndian), + longitudeInterval: view.getFloat64(offset + 152, isLittleEndian), + gridNodeCount: view.getInt32(offset + 168, isLittleEndian) + }; +} + +function readGridNodes(view, offset, gridHeader, isLittleEndian) { + var nodesOffset = offset + 176; + var gridRecordLength = 16; + var gridShiftRecords = []; + for (var i = 0; i < gridHeader.gridNodeCount; i++) { + var record = { + latitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength, isLittleEndian), + longitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength + 4, isLittleEndian), + latitudeAccuracy: view.getFloat32(nodesOffset + i * gridRecordLength + 8, isLittleEndian), + longitudeAccuracy: view.getFloat32(nodesOffset + i * gridRecordLength + 12, isLittleEndian), + }; + gridShiftRecords.push(record); + } + return gridShiftRecords; +} + +function Projection(srsCode,callback) { + if (!(this instanceof Projection)) { + return new Projection(srsCode); + } + callback = callback || function(error){ + if(error){ + throw error; + } + }; + var json = parse(srsCode); + if(typeof json !== 'object'){ + callback(srsCode); + return; + } + var ourProj = Projection.projections.get(json.projName); + if(!ourProj){ + callback(srsCode); + return; + } + if (json.datumCode && json.datumCode !== 'none') { + var datumDef = match(exports, json.datumCode); + if (datumDef) { + json.datum_params = json.datum_params || (datumDef.towgs84 ? datumDef.towgs84.split(',') : null); + json.ellps = datumDef.ellipse; + json.datumName = datumDef.datumName ? datumDef.datumName : json.datumCode; + } + } + json.k0 = json.k0 || 1.0; + json.axis = json.axis || 'enu'; + json.ellps = json.ellps || 'wgs84'; + json.lat1 = json.lat1 || json.lat0; // Lambert_Conformal_Conic_1SP, for example, needs this + + var sphere_ = sphere(json.a, json.b, json.rf, json.ellps, json.sphere); + var ecc = eccentricity(sphere_.a, sphere_.b, sphere_.rf, json.R_A); + var nadgrids = getNadgrids(json.nadgrids); + var datumObj = json.datum || datum(json.datumCode, json.datum_params, sphere_.a, sphere_.b, ecc.es, ecc.ep2, + nadgrids); + + extend(this, json); // transfer everything over from the projection because we don't know what we'll need + extend(this, ourProj); // transfer all the methods from the projection + + // copy the 4 things over we calculated in deriveConstants.sphere + this.a = sphere_.a; + this.b = sphere_.b; + this.rf = sphere_.rf; + this.sphere = sphere_.sphere; + + // copy the 3 things we calculated in deriveConstants.eccentricity + this.es = ecc.es; + this.e = ecc.e; + this.ep2 = ecc.ep2; + + // add in the datum object + this.datum = datumObj; + + // init the projection + this.init(); + + // legecy callback from back in the day when it went to spatialreference.org + callback(null, this); + +} +Projection.projections = projections; +Projection.projections.start(); + +function compareDatums(source, dest) { + if (source.datum_type !== dest.datum_type) { + return false; // false, datums are not equal + } else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) { + // the tolerance for es is to ensure that GRS80 and WGS84 + // are considered identical + return false; + } else if (source.datum_type === PJD_3PARAM) { + return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]); + } else if (source.datum_type === PJD_7PARAM) { + return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]); + } else { + return true; // datums are equal + } +} // cs_compare_datums() + +/* + * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates + * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), + * according to the current ellipsoid parameters. + * + * Latitude : Geodetic latitude in radians (input) + * Longitude : Geodetic longitude in radians (input) + * Height : Geodetic height, in meters (input) + * X : Calculated Geocentric X coordinate, in meters (output) + * Y : Calculated Geocentric Y coordinate, in meters (output) + * Z : Calculated Geocentric Z coordinate, in meters (output) + * + */ +function geodeticToGeocentric(p, es, a) { + var Longitude = p.x; + var Latitude = p.y; + var Height = p.z ? p.z : 0; //Z value not always supplied + + var Rn; /* Earth radius at location */ + var Sin_Lat; /* Math.sin(Latitude) */ + var Sin2_Lat; /* Square of Math.sin(Latitude) */ + var Cos_Lat; /* Math.cos(Latitude) */ + + /* + ** Don't blow up if Latitude is just a little out of the value + ** range as it may just be a rounding issue. Also removed longitude + ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001. + */ + if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) { + Latitude = -HALF_PI; + } else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) { + Latitude = HALF_PI; + } else if (Latitude < -HALF_PI) { + /* Latitude out of range */ + //..reportError('geocent:lat out of range:' + Latitude); + return { x: -Infinity, y: -Infinity, z: p.z }; + } else if (Latitude > HALF_PI) { + /* Latitude out of range */ + return { x: Infinity, y: Infinity, z: p.z }; + } + + if (Longitude > Math.PI) { + Longitude -= (2 * Math.PI); + } + Sin_Lat = Math.sin(Latitude); + Cos_Lat = Math.cos(Latitude); + Sin2_Lat = Sin_Lat * Sin_Lat; + Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat)); + return { + x: (Rn + Height) * Cos_Lat * Math.cos(Longitude), + y: (Rn + Height) * Cos_Lat * Math.sin(Longitude), + z: ((Rn * (1 - es)) + Height) * Sin_Lat + }; +} // cs_geodetic_to_geocentric() + +function geocentricToGeodetic(p, es, a, b) { + /* local defintions and variables */ + /* end-criterium of loop, accuracy of sin(Latitude) */ + var genau = 1e-12; + var genau2 = (genau * genau); + var maxiter = 30; + + var P; /* distance between semi-minor axis and location */ + var RR; /* distance between center and location */ + var CT; /* sin of geocentric latitude */ + var ST; /* cos of geocentric latitude */ + var RX; + var RK; + var RN; /* Earth radius at location */ + var CPHI0; /* cos of start or old geodetic latitude in iterations */ + var SPHI0; /* sin of start or old geodetic latitude in iterations */ + var CPHI; /* cos of searched geodetic latitude */ + var SPHI; /* sin of searched geodetic latitude */ + var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */ + var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */ + + var X = p.x; + var Y = p.y; + var Z = p.z ? p.z : 0.0; //Z value not always supplied + var Longitude; + var Latitude; + var Height; + + P = Math.sqrt(X * X + Y * Y); + RR = Math.sqrt(X * X + Y * Y + Z * Z); + + /* special cases for latitude and longitude */ + if (P / a < genau) { + + /* special case, if P=0. (X=0., Y=0.) */ + Longitude = 0.0; + + /* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis + * of ellipsoid (=center of mass), Latitude becomes PI/2 */ + if (RR / a < genau) { + Latitude = HALF_PI; + Height = -b; + return { + x: p.x, + y: p.y, + z: p.z + }; + } + } else { + /* ellipsoidal (geodetic) longitude + * interval: -PI < Longitude <= +PI */ + Longitude = Math.atan2(Y, X); + } + + /* -------------------------------------------------------------- + * Following iterative algorithm was developped by + * "Institut for Erdmessung", University of Hannover, July 1988. + * Internet: www.ife.uni-hannover.de + * Iterative computation of CPHI,SPHI and Height. + * Iteration of CPHI and SPHI to 10**-12 radian resp. + * 2*10**-7 arcsec. + * -------------------------------------------------------------- + */ + CT = Z / RR; + ST = P / RR; + RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST); + CPHI0 = ST * (1.0 - es) * RX; + SPHI0 = CT * RX; + iter = 0; + + /* loop to find sin(Latitude) resp. Latitude + * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */ + do { + iter++; + RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0); + + /* ellipsoidal (geodetic) height */ + Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0); + + RK = es * RN / (RN + Height); + RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST); + CPHI = ST * (1.0 - RK) * RX; + SPHI = CT * RX; + SDPHI = SPHI * CPHI0 - CPHI * SPHI0; + CPHI0 = CPHI; + SPHI0 = SPHI; + } + while (SDPHI * SDPHI > genau2 && iter < maxiter); + + /* ellipsoidal (geodetic) latitude */ + Latitude = Math.atan(SPHI / Math.abs(CPHI)); + return { + x: Longitude, + y: Latitude, + z: Height + }; +} // cs_geocentric_to_geodetic() + +/****************************************************************/ +// pj_geocentic_to_wgs84( p ) +// p = point to transform in geocentric coordinates (x,y,z) + + +/** point object, nothing fancy, just allows values to be + passed back and forth by reference rather than by value. + Other point classes may be used as long as they have + x and y properties, which will get modified in the transform method. +*/ +function geocentricToWgs84(p, datum_type, datum_params) { + + if (datum_type === PJD_3PARAM) { + // if( x[io] === HUGE_VAL ) + // continue; + return { + x: p.x + datum_params[0], + y: p.y + datum_params[1], + z: p.z + datum_params[2], + }; + } else if (datum_type === PJD_7PARAM) { + var Dx_BF = datum_params[0]; + var Dy_BF = datum_params[1]; + var Dz_BF = datum_params[2]; + var Rx_BF = datum_params[3]; + var Ry_BF = datum_params[4]; + var Rz_BF = datum_params[5]; + var M_BF = datum_params[6]; + // if( x[io] === HUGE_VAL ) + // continue; + return { + x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF, + y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF, + z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF + }; + } +} // cs_geocentric_to_wgs84 + +/****************************************************************/ +// pj_geocentic_from_wgs84() +// coordinate system definition, +// point to transform in geocentric coordinates (x,y,z) +function geocentricFromWgs84(p, datum_type, datum_params) { + + if (datum_type === PJD_3PARAM) { + //if( x[io] === HUGE_VAL ) + // continue; + return { + x: p.x - datum_params[0], + y: p.y - datum_params[1], + z: p.z - datum_params[2], + }; + + } else if (datum_type === PJD_7PARAM) { + var Dx_BF = datum_params[0]; + var Dy_BF = datum_params[1]; + var Dz_BF = datum_params[2]; + var Rx_BF = datum_params[3]; + var Ry_BF = datum_params[4]; + var Rz_BF = datum_params[5]; + var M_BF = datum_params[6]; + var x_tmp = (p.x - Dx_BF) / M_BF; + var y_tmp = (p.y - Dy_BF) / M_BF; + var z_tmp = (p.z - Dz_BF) / M_BF; + //if( x[io] === HUGE_VAL ) + // continue; + + return { + x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp, + y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp, + z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp + }; + } //cs_geocentric_from_wgs84() +} + +function checkParams(type) { + return (type === PJD_3PARAM || type === PJD_7PARAM); +} + +function datum_transform(source, dest, point) { + // Short cut if the datums are identical. + if (compareDatums(source, dest)) { + return point; // in this case, zero is sucess, + // whereas cs_compare_datums returns 1 to indicate TRUE + // confusing, should fix this + } + + // Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest + if (source.datum_type === PJD_NODATUM || dest.datum_type === PJD_NODATUM) { + return point; + } + + // If this datum requires grid shifts, then apply it to geodetic coordinates. + var source_a = source.a; + var source_es = source.es; + if (source.datum_type === PJD_GRIDSHIFT) { + var gridShiftCode = applyGridShift(source, false, point); + if (gridShiftCode !== 0) { + return undefined; + } + source_a = SRS_WGS84_SEMIMAJOR; + source_es = SRS_WGS84_ESQUARED; + } + + var dest_a = dest.a; + var dest_b = dest.b; + var dest_es = dest.es; + if (dest.datum_type === PJD_GRIDSHIFT) { + dest_a = SRS_WGS84_SEMIMAJOR; + dest_b = SRS_WGS84_SEMIMINOR; + dest_es = SRS_WGS84_ESQUARED; + } + + // Do we need to go through geocentric coordinates? + if (source_es === dest_es && source_a === dest_a && !checkParams(source.datum_type) && !checkParams(dest.datum_type)) { + return point; + } + + // Convert to geocentric coordinates. + point = geodeticToGeocentric(point, source_es, source_a); + // Convert between datums + if (checkParams(source.datum_type)) { + point = geocentricToWgs84(point, source.datum_type, source.datum_params); + } + if (checkParams(dest.datum_type)) { + point = geocentricFromWgs84(point, dest.datum_type, dest.datum_params); + } + point = geocentricToGeodetic(point, dest_es, dest_a, dest_b); + + if (dest.datum_type === PJD_GRIDSHIFT) { + var destGridShiftResult = applyGridShift(dest, true, point); + if (destGridShiftResult !== 0) { + return undefined; + } + } + + return point; +} + +function applyGridShift(source, inverse, point) { + if (source.grids === null || source.grids.length === 0) { + console.log('Grid shift grids not found'); + return -1; + } + var input = {x: -point.x, y: point.y}; + var output = {x: Number.NaN, y: Number.NaN}; + var attemptedGrids = []; + outer: + for (var i = 0; i < source.grids.length; i++) { + var grid = source.grids[i]; + attemptedGrids.push(grid.name); + if (grid.isNull) { + output = input; + break; + } + grid.mandatory; + if (grid.grid === null) { + if (grid.mandatory) { + console.log("Unable to find mandatory grid '" + grid.name + "'"); + return -1; + } + continue; + } + var subgrids = grid.grid.subgrids; + for (var j = 0, jj = subgrids.length; j < jj; j++) { + var subgrid = subgrids[j]; + // skip tables that don't match our point at all + var epsilon = (Math.abs(subgrid.del[1]) + Math.abs(subgrid.del[0])) / 10000.0; + var minX = subgrid.ll[0] - epsilon; + var minY = subgrid.ll[1] - epsilon; + var maxX = subgrid.ll[0] + (subgrid.lim[0] - 1) * subgrid.del[0] + epsilon; + var maxY = subgrid.ll[1] + (subgrid.lim[1] - 1) * subgrid.del[1] + epsilon; + if (minY > input.y || minX > input.x || maxY < input.y || maxX < input.x ) { + continue; + } + output = applySubgridShift(input, inverse, subgrid); + if (!isNaN(output.x)) { + break outer; + } + } + } + if (isNaN(output.x)) { + console.log("Failed to find a grid shift table for location '"+ + -input.x * R2D + " " + input.y * R2D + " tried: '" + attemptedGrids + "'"); + return -1; + } + point.x = -output.x; + point.y = output.y; + return 0; +} + +function applySubgridShift(pin, inverse, ct) { + var val = {x: Number.NaN, y: Number.NaN}; + if (isNaN(pin.x)) { return val; } + var tb = {x: pin.x, y: pin.y}; + tb.x -= ct.ll[0]; + tb.y -= ct.ll[1]; + tb.x = adjust_lon(tb.x - Math.PI) + Math.PI; + var t = nadInterpolate(tb, ct); + if (inverse) { + if (isNaN(t.x)) { + return val; + } + t.x = tb.x - t.x; + t.y = tb.y - t.y; + var i = 9, tol = 1e-12; + var dif, del; + do { + del = nadInterpolate(t, ct); + if (isNaN(del.x)) { + console.log("Inverse grid shift iteration failed, presumably at grid edge. Using first approximation."); + break; + } + dif = {x: tb.x - (del.x + t.x), y: tb.y - (del.y + t.y)}; + t.x += dif.x; + t.y += dif.y; + } while (i-- && Math.abs(dif.x) > tol && Math.abs(dif.y) > tol); + if (i < 0) { + console.log("Inverse grid shift iterator failed to converge."); + return val; + } + val.x = adjust_lon(t.x + ct.ll[0]); + val.y = t.y + ct.ll[1]; + } else { + if (!isNaN(t.x)) { + val.x = pin.x + t.x; + val.y = pin.y + t.y; + } + } + return val; +} + +function nadInterpolate(pin, ct) { + var t = {x: pin.x / ct.del[0], y: pin.y / ct.del[1]}; + var indx = {x: Math.floor(t.x), y: Math.floor(t.y)}; + var frct = {x: t.x - 1.0 * indx.x, y: t.y - 1.0 * indx.y}; + var val= {x: Number.NaN, y: Number.NaN}; + var inx; + if (indx.x < 0 || indx.x >= ct.lim[0]) { + return val; + } + if (indx.y < 0 || indx.y >= ct.lim[1]) { + return val; + } + inx = (indx.y * ct.lim[0]) + indx.x; + var f00 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]}; + inx++; + var f10= {x: ct.cvs[inx][0], y: ct.cvs[inx][1]}; + inx += ct.lim[0]; + var f11 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]}; + inx--; + var f01 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]}; + var m11 = frct.x * frct.y, m10 = frct.x * (1.0 - frct.y), + m00 = (1.0 - frct.x) * (1.0 - frct.y), m01 = (1.0 - frct.x) * frct.y; + val.x = (m00 * f00.x + m10 * f10.x + m01 * f01.x + m11 * f11.x); + val.y = (m00 * f00.y + m10 * f10.y + m01 * f01.y + m11 * f11.y); + return val; +} + +function adjust_axis(crs, denorm, point) { + var xin = point.x, + yin = point.y, + zin = point.z || 0.0; + var v, t, i; + var out = {}; + for (i = 0; i < 3; i++) { + if (denorm && i === 2 && point.z === undefined) { + continue; + } + if (i === 0) { + v = xin; + if ("ew".indexOf(crs.axis[i]) !== -1) { + t = 'x'; + } else { + t = 'y'; + } + + } + else if (i === 1) { + v = yin; + if ("ns".indexOf(crs.axis[i]) !== -1) { + t = 'y'; + } else { + t = 'x'; + } + } + else { + v = zin; + t = 'z'; + } + switch (crs.axis[i]) { + case 'e': + out[t] = v; + break; + case 'w': + out[t] = -v; + break; + case 'n': + out[t] = v; + break; + case 's': + out[t] = -v; + break; + case 'u': + if (point[t] !== undefined) { + out.z = v; + } + break; + case 'd': + if (point[t] !== undefined) { + out.z = -v; + } + break; + default: + //console.log("ERROR: unknow axis ("+crs.axis[i]+") - check definition of "+crs.projName); + return null; + } + } + return out; +} + +function common (array){ + var out = { + x: array[0], + y: array[1] + }; + if (array.length>2) { + out.z = array[2]; + } + if (array.length>3) { + out.m = array[3]; + } + return out; +} + +function checkSanity (point) { + checkCoord(point.x); + checkCoord(point.y); +} +function checkCoord(num) { + if (typeof Number.isFinite === 'function') { + if (Number.isFinite(num)) { + return; + } + throw new TypeError('coordinates must be finite numbers'); + } + if (typeof num !== 'number' || num !== num || !isFinite(num)) { + throw new TypeError('coordinates must be finite numbers'); + } +} + +function checkNotWGS(source, dest) { + return ( + (source.datum.datum_type === PJD_3PARAM || source.datum.datum_type === PJD_7PARAM || source.datum.datum_type === PJD_GRIDSHIFT) && dest.datumCode !== 'WGS84') || + ((dest.datum.datum_type === PJD_3PARAM || dest.datum.datum_type === PJD_7PARAM || dest.datum.datum_type === PJD_GRIDSHIFT) && source.datumCode !== 'WGS84'); +} + +function transform(source, dest, point, enforceAxis) { + var wgs84; + if (Array.isArray(point)) { + point = common(point); + } else { + // Clone the point object so inputs don't get modified + point = { + x: point.x, + y: point.y, + z: point.z, + m: point.m + }; + } + var hasZ = point.z !== undefined; + checkSanity(point); + // Workaround for datum shifts towgs84, if either source or destination projection is not wgs84 + if (source.datum && dest.datum && checkNotWGS(source, dest)) { + wgs84 = new Projection('WGS84'); + point = transform(source, wgs84, point, enforceAxis); + source = wgs84; + } + // DGR, 2010/11/12 + if (enforceAxis && source.axis !== 'enu') { + point = adjust_axis(source, false, point); + } + // Transform source points to long/lat, if they aren't already. + if (source.projName === 'longlat') { + point = { + x: point.x * D2R$1, + y: point.y * D2R$1, + z: point.z || 0 + }; + } else { + if (source.to_meter) { + point = { + x: point.x * source.to_meter, + y: point.y * source.to_meter, + z: point.z || 0 + }; + } + point = source.inverse(point); // Convert Cartesian to longlat + if (!point) { + return; + } + } + // Adjust for the prime meridian if necessary + if (source.from_greenwich) { + point.x += source.from_greenwich; + } + + // Convert datums if needed, and if possible. + point = datum_transform(source.datum, dest.datum, point); + if (!point) { + return; + } + + // Adjust for the prime meridian if necessary + if (dest.from_greenwich) { + point = { + x: point.x - dest.from_greenwich, + y: point.y, + z: point.z || 0 + }; + } + + if (dest.projName === 'longlat') { + // convert radians to decimal degrees + point = { + x: point.x * R2D, + y: point.y * R2D, + z: point.z || 0 + }; + } else { // else project + point = dest.forward(point); + if (dest.to_meter) { + point = { + x: point.x / dest.to_meter, + y: point.y / dest.to_meter, + z: point.z || 0 + }; + } + } + + // DGR, 2010/11/12 + if (enforceAxis && dest.axis !== 'enu') { + return adjust_axis(dest, true, point); + } + + if (point && !hasZ) { + delete point.z; + } + return point; +} + +var wgs84 = Projection('WGS84'); + +function transformer(from, to, coords, enforceAxis) { + var transformedArray, out, keys; + if (Array.isArray(coords)) { + transformedArray = transform(from, to, coords, enforceAxis) || {x: NaN, y: NaN}; + if (coords.length > 2) { + if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) { + if (typeof transformedArray.z === 'number') { + return [transformedArray.x, transformedArray.y, transformedArray.z].concat(coords.splice(3)); + } else { + return [transformedArray.x, transformedArray.y, coords[2]].concat(coords.splice(3)); + } + } else { + return [transformedArray.x, transformedArray.y].concat(coords.splice(2)); + } + } else { + return [transformedArray.x, transformedArray.y]; + } + } else { + out = transform(from, to, coords, enforceAxis); + keys = Object.keys(coords); + if (keys.length === 2) { + return out; + } + keys.forEach(function (key) { + if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) { + if (key === 'x' || key === 'y' || key === 'z') { + return; + } + } else { + if (key === 'x' || key === 'y') { + return; + } + } + out[key] = coords[key]; + }); + return out; + } +} + +function checkProj(item) { + if (item instanceof Projection) { + return item; + } + if (item.oProj) { + return item.oProj; + } + return Projection(item); +} + +function proj4(fromProj, toProj, coord) { + fromProj = checkProj(fromProj); + var single = false; + var obj; + if (typeof toProj === 'undefined') { + toProj = fromProj; + fromProj = wgs84; + single = true; + } else if (typeof toProj.x !== 'undefined' || Array.isArray(toProj)) { + coord = toProj; + toProj = fromProj; + fromProj = wgs84; + single = true; + } + toProj = checkProj(toProj); + if (coord) { + return transformer(fromProj, toProj, coord); + } else { + obj = { + forward: function (coords, enforceAxis) { + return transformer(fromProj, toProj, coords, enforceAxis); + }, + inverse: function (coords, enforceAxis) { + return transformer(toProj, fromProj, coords, enforceAxis); + } + }; + if (single) { + obj.oProj = toProj; + } + return obj; + } +} + +/** + * UTM zones are grouped, and assigned to one of a group of 6 + * sets. + * + * {int} @private + */ +var NUM_100K_SETS = 6; + +/** + * The column letters (for easting) of the lower left value, per + * set. + * + * {string} @private + */ +var SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS'; + +/** + * The row letters (for northing) of the lower left value, per + * set. + * + * {string} @private + */ +var SET_ORIGIN_ROW_LETTERS = 'AFAFAF'; + +var A$1 = 65; // A +var I = 73; // I +var O = 79; // O +var V = 86; // V +var Z = 90; // Z +var mgrs = { + forward: forward$t, + inverse: inverse$t, + toPoint: toPoint +}; +/** + * Conversion of lat/lon to MGRS. + * + * @param {object} ll Object literal with lat and lon properties on a + * WGS84 ellipsoid. + * @param {int} accuracy Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for + * 100 m, 2 for 1000 m or 1 for 10000 m). Optional, default is 5. + * @return {string} the MGRS string for the given location and accuracy. + */ +function forward$t(ll, accuracy) { + accuracy = accuracy || 5; // default accuracy 1m + return encode(LLtoUTM({ + lat: ll[1], + lon: ll[0] + }), accuracy); +} +/** + * Conversion of MGRS to lat/lon. + * + * @param {string} mgrs MGRS string. + * @return {array} An array with left (longitude), bottom (latitude), right + * (longitude) and top (latitude) values in WGS84, representing the + * bounding box for the provided MGRS reference. + */ +function inverse$t(mgrs) { + var bbox = UTMtoLL(decode(mgrs.toUpperCase())); + if (bbox.lat && bbox.lon) { + return [bbox.lon, bbox.lat, bbox.lon, bbox.lat]; + } + return [bbox.left, bbox.bottom, bbox.right, bbox.top]; +} +function toPoint(mgrs) { + var bbox = UTMtoLL(decode(mgrs.toUpperCase())); + if (bbox.lat && bbox.lon) { + return [bbox.lon, bbox.lat]; + } + return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2]; +}/** + * Conversion from degrees to radians. + * + * @private + * @param {number} deg the angle in degrees. + * @return {number} the angle in radians. + */ +function degToRad(deg) { + return (deg * (Math.PI / 180.0)); +} + +/** + * Conversion from radians to degrees. + * + * @private + * @param {number} rad the angle in radians. + * @return {number} the angle in degrees. + */ +function radToDeg(rad) { + return (180.0 * (rad / Math.PI)); +} + +/** + * Converts a set of Longitude and Latitude co-ordinates to UTM + * using the WGS84 ellipsoid. + * + * @private + * @param {object} ll Object literal with lat and lon properties + * representing the WGS84 coordinate to be converted. + * @return {object} Object literal containing the UTM value with easting, + * northing, zoneNumber and zoneLetter properties, and an optional + * accuracy property in digits. Returns null if the conversion failed. + */ +function LLtoUTM(ll) { + var Lat = ll.lat; + var Long = ll.lon; + var a = 6378137.0; //ellip.radius; + var eccSquared = 0.00669438; //ellip.eccsq; + var k0 = 0.9996; + var LongOrigin; + var eccPrimeSquared; + var N, T, C, A, M; + var LatRad = degToRad(Lat); + var LongRad = degToRad(Long); + var LongOriginRad; + var ZoneNumber; + // (int) + ZoneNumber = Math.floor((Long + 180) / 6) + 1; + + //Make sure the longitude 180.00 is in Zone 60 + if (Long === 180) { + ZoneNumber = 60; + } + + // Special zone for Norway + if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) { + ZoneNumber = 32; + } + + // Special zones for Svalbard + if (Lat >= 72.0 && Lat < 84.0) { + if (Long >= 0.0 && Long < 9.0) { + ZoneNumber = 31; + } + else if (Long >= 9.0 && Long < 21.0) { + ZoneNumber = 33; + } + else if (Long >= 21.0 && Long < 33.0) { + ZoneNumber = 35; + } + else if (Long >= 33.0 && Long < 42.0) { + ZoneNumber = 37; + } + } + + LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin + // in middle of + // zone + LongOriginRad = degToRad(LongOrigin); + + eccPrimeSquared = (eccSquared) / (1 - eccSquared); + + N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad)); + T = Math.tan(LatRad) * Math.tan(LatRad); + C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad); + A = Math.cos(LatRad) * (LongRad - LongOriginRad); + + M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad)); + + var UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0) + 500000.0); + + var UTMNorthing = (k0 * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720.0))); + if (Lat < 0.0) { + UTMNorthing += 10000000.0; //10000000 meter offset for + // southern hemisphere + } + + return { + northing: Math.round(UTMNorthing), + easting: Math.round(UTMEasting), + zoneNumber: ZoneNumber, + zoneLetter: getLetterDesignator(Lat) + }; +} + +/** + * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience + * class where the Zone can be specified as a single string eg."60N" which + * is then broken down into the ZoneNumber and ZoneLetter. + * + * @private + * @param {object} utm An object literal with northing, easting, zoneNumber + * and zoneLetter properties. If an optional accuracy property is + * provided (in meters), a bounding box will be returned instead of + * latitude and longitude. + * @return {object} An object literal containing either lat and lon values + * (if no accuracy was provided), or top, right, bottom and left values + * for the bounding box calculated according to the provided accuracy. + * Returns null if the conversion failed. + */ +function UTMtoLL(utm) { + + var UTMNorthing = utm.northing; + var UTMEasting = utm.easting; + var zoneLetter = utm.zoneLetter; + var zoneNumber = utm.zoneNumber; + // check the ZoneNummber is valid + if (zoneNumber < 0 || zoneNumber > 60) { + return null; + } + + var k0 = 0.9996; + var a = 6378137.0; //ellip.radius; + var eccSquared = 0.00669438; //ellip.eccsq; + var eccPrimeSquared; + var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared)); + var N1, T1, C1, R1, D, M; + var LongOrigin; + var mu, phi1Rad; + + // remove 500,000 meter offset for longitude + var x = UTMEasting - 500000.0; + var y = UTMNorthing; + + // We must know somehow if we are in the Northern or Southern + // hemisphere, this is the only time we use the letter So even + // if the Zone letter isn't exactly correct it should indicate + // the hemisphere correctly + if (zoneLetter < 'N') { + y -= 10000000.0; // remove 10,000,000 meter offset used + // for southern hemisphere + } + + // There are 60 zones with zone 1 being at West -180 to -174 + LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin + // in middle of + // zone + + eccPrimeSquared = (eccSquared) / (1 - eccSquared); + + M = y / k0; + mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256)); + + phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu); + // double phi1 = ProjMath.radToDeg(phi1Rad); + + N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad)); + T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad); + C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad); + R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5); + D = x / (N1 * k0); + + var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720); + lat = radToDeg(lat); + + var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad); + lon = LongOrigin + radToDeg(lon); + + var result; + if (utm.accuracy) { + var topRight = UTMtoLL({ + northing: utm.northing + utm.accuracy, + easting: utm.easting + utm.accuracy, + zoneLetter: utm.zoneLetter, + zoneNumber: utm.zoneNumber + }); + result = { + top: topRight.lat, + right: topRight.lon, + bottom: lat, + left: lon + }; + } + else { + result = { + lat: lat, + lon: lon + }; + } + return result; +} + +/** + * Calculates the MGRS letter designator for the given latitude. + * + * @private + * @param {number} lat The latitude in WGS84 to get the letter designator + * for. + * @return {char} The letter designator. + */ +function getLetterDesignator(lat) { + //This is here as an error flag to show that the Latitude is + //outside MGRS limits + var LetterDesignator = 'Z'; + + if ((84 >= lat) && (lat >= 72)) { + LetterDesignator = 'X'; + } + else if ((72 > lat) && (lat >= 64)) { + LetterDesignator = 'W'; + } + else if ((64 > lat) && (lat >= 56)) { + LetterDesignator = 'V'; + } + else if ((56 > lat) && (lat >= 48)) { + LetterDesignator = 'U'; + } + else if ((48 > lat) && (lat >= 40)) { + LetterDesignator = 'T'; + } + else if ((40 > lat) && (lat >= 32)) { + LetterDesignator = 'S'; + } + else if ((32 > lat) && (lat >= 24)) { + LetterDesignator = 'R'; + } + else if ((24 > lat) && (lat >= 16)) { + LetterDesignator = 'Q'; + } + else if ((16 > lat) && (lat >= 8)) { + LetterDesignator = 'P'; + } + else if ((8 > lat) && (lat >= 0)) { + LetterDesignator = 'N'; + } + else if ((0 > lat) && (lat >= -8)) { + LetterDesignator = 'M'; + } + else if ((-8 > lat) && (lat >= -16)) { + LetterDesignator = 'L'; + } + else if ((-16 > lat) && (lat >= -24)) { + LetterDesignator = 'K'; + } + else if ((-24 > lat) && (lat >= -32)) { + LetterDesignator = 'J'; + } + else if ((-32 > lat) && (lat >= -40)) { + LetterDesignator = 'H'; + } + else if ((-40 > lat) && (lat >= -48)) { + LetterDesignator = 'G'; + } + else if ((-48 > lat) && (lat >= -56)) { + LetterDesignator = 'F'; + } + else if ((-56 > lat) && (lat >= -64)) { + LetterDesignator = 'E'; + } + else if ((-64 > lat) && (lat >= -72)) { + LetterDesignator = 'D'; + } + else if ((-72 > lat) && (lat >= -80)) { + LetterDesignator = 'C'; + } + return LetterDesignator; +} + +/** + * Encodes a UTM location as MGRS string. + * + * @private + * @param {object} utm An object literal with easting, northing, + * zoneLetter, zoneNumber + * @param {number} accuracy Accuracy in digits (1-5). + * @return {string} MGRS string for the given UTM location. + */ +function encode(utm, accuracy) { + // prepend with leading zeroes + var seasting = "00000" + utm.easting, + snorthing = "00000" + utm.northing; + + return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy); +} + +/** + * Get the two letter 100k designator for a given UTM easting, + * northing and zone number value. + * + * @private + * @param {number} easting + * @param {number} northing + * @param {number} zoneNumber + * @return the two letter 100k designator for the given UTM location. + */ +function get100kID(easting, northing, zoneNumber) { + var setParm = get100kSetForZone(zoneNumber); + var setColumn = Math.floor(easting / 100000); + var setRow = Math.floor(northing / 100000) % 20; + return getLetter100kID(setColumn, setRow, setParm); +} + +/** + * Given a UTM zone number, figure out the MGRS 100K set it is in. + * + * @private + * @param {number} i An UTM zone number. + * @return {number} the 100k set the UTM zone is in. + */ +function get100kSetForZone(i) { + var setParm = i % NUM_100K_SETS; + if (setParm === 0) { + setParm = NUM_100K_SETS; + } + + return setParm; +} + +/** + * Get the two-letter MGRS 100k designator given information + * translated from the UTM northing, easting and zone number. + * + * @private + * @param {number} column the column index as it relates to the MGRS + * 100k set spreadsheet, created from the UTM easting. + * Values are 1-8. + * @param {number} row the row index as it relates to the MGRS 100k set + * spreadsheet, created from the UTM northing value. Values + * are from 0-19. + * @param {number} parm the set block, as it relates to the MGRS 100k set + * spreadsheet, created from the UTM zone. Values are from + * 1-60. + * @return two letter MGRS 100k code. + */ +function getLetter100kID(column, row, parm) { + // colOrigin and rowOrigin are the letters at the origin of the set + var index = parm - 1; + var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index); + var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index); + + // colInt and rowInt are the letters to build to return + var colInt = colOrigin + column - 1; + var rowInt = rowOrigin + row; + var rollover = false; + + if (colInt > Z) { + colInt = colInt - Z + A$1 - 1; + rollover = true; + } + + if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) { + colInt++; + } + + if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) { + colInt++; + + if (colInt === I) { + colInt++; + } + } + + if (colInt > Z) { + colInt = colInt - Z + A$1 - 1; + } + + if (rowInt > V) { + rowInt = rowInt - V + A$1 - 1; + rollover = true; + } + else { + rollover = false; + } + + if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) { + rowInt++; + } + + if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) { + rowInt++; + + if (rowInt === I) { + rowInt++; + } + } + + if (rowInt > V) { + rowInt = rowInt - V + A$1 - 1; + } + + var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt); + return twoLetter; +} + +/** + * Decode the UTM parameters from a MGRS string. + * + * @private + * @param {string} mgrsString an UPPERCASE coordinate string is expected. + * @return {object} An object literal with easting, northing, zoneLetter, + * zoneNumber and accuracy (in meters) properties. + */ +function decode(mgrsString) { + + if (mgrsString && mgrsString.length === 0) { + throw ("MGRSPoint coverting from nothing"); + } + + var length = mgrsString.length; + + var hunK = null; + var sb = ""; + var testChar; + var i = 0; + + // get Zone number + while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) { + if (i >= 2) { + throw ("MGRSPoint bad conversion from: " + mgrsString); + } + sb += testChar; + i++; + } + + var zoneNumber = parseInt(sb, 10); + + if (i === 0 || i + 3 > length) { + // A good MGRS string has to be 4-5 digits long, + // ##AAA/#AAA at least. + throw ("MGRSPoint bad conversion from: " + mgrsString); + } + + var zoneLetter = mgrsString.charAt(i++); + + // Should we check the zone letter here? Why not. + if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') { + throw ("MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString); + } + + hunK = mgrsString.substring(i, i += 2); + + var set = get100kSetForZone(zoneNumber); + + var east100k = getEastingFromChar(hunK.charAt(0), set); + var north100k = getNorthingFromChar(hunK.charAt(1), set); + + // We have a bug where the northing may be 2000000 too low. + // How + // do we know when to roll over? + + while (north100k < getMinNorthing(zoneLetter)) { + north100k += 2000000; + } + + // calculate the char index for easting/northing separator + var remainder = length - i; + + if (remainder % 2 !== 0) { + throw ("MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString); + } + + var sep = remainder / 2; + + var sepEasting = 0.0; + var sepNorthing = 0.0; + var accuracyBonus, sepEastingString, sepNorthingString, easting, northing; + if (sep > 0) { + accuracyBonus = 100000.0 / Math.pow(10, sep); + sepEastingString = mgrsString.substring(i, i + sep); + sepEasting = parseFloat(sepEastingString) * accuracyBonus; + sepNorthingString = mgrsString.substring(i + sep); + sepNorthing = parseFloat(sepNorthingString) * accuracyBonus; + } + + easting = sepEasting + east100k; + northing = sepNorthing + north100k; + + return { + easting: easting, + northing: northing, + zoneLetter: zoneLetter, + zoneNumber: zoneNumber, + accuracy: accuracyBonus + }; +} + +/** + * Given the first letter from a two-letter MGRS 100k zone, and given the + * MGRS table set for the zone number, figure out the easting value that + * should be added to the other, secondary easting value. + * + * @private + * @param {char} e The first letter from a two-letter MGRS 100´k zone. + * @param {number} set The MGRS table set for the zone number. + * @return {number} The easting value for the given letter and set. + */ +function getEastingFromChar(e, set) { + // colOrigin is the letter at the origin of the set for the + // column + var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1); + var eastingValue = 100000.0; + var rewindMarker = false; + + while (curCol !== e.charCodeAt(0)) { + curCol++; + if (curCol === I) { + curCol++; + } + if (curCol === O) { + curCol++; + } + if (curCol > Z) { + if (rewindMarker) { + throw ("Bad character: " + e); + } + curCol = A$1; + rewindMarker = true; + } + eastingValue += 100000.0; + } + + return eastingValue; +} + +/** + * Given the second letter from a two-letter MGRS 100k zone, and given the + * MGRS table set for the zone number, figure out the northing value that + * should be added to the other, secondary northing value. You have to + * remember that Northings are determined from the equator, and the vertical + * cycle of letters mean a 2000000 additional northing meters. This happens + * approx. every 18 degrees of latitude. This method does *NOT* count any + * additional northings. You have to figure out how many 2000000 meters need + * to be added for the zone letter of the MGRS coordinate. + * + * @private + * @param {char} n Second letter of the MGRS 100k zone + * @param {number} set The MGRS table set number, which is dependent on the + * UTM zone number. + * @return {number} The northing value for the given letter and set. + */ +function getNorthingFromChar(n, set) { + + if (n > 'V') { + throw ("MGRSPoint given invalid Northing " + n); + } + + // rowOrigin is the letter at the origin of the set for the + // column + var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1); + var northingValue = 0.0; + var rewindMarker = false; + + while (curRow !== n.charCodeAt(0)) { + curRow++; + if (curRow === I) { + curRow++; + } + if (curRow === O) { + curRow++; + } + // fixing a bug making whole application hang in this loop + // when 'n' is a wrong character + if (curRow > V) { + if (rewindMarker) { // making sure that this loop ends + throw ("Bad character: " + n); + } + curRow = A$1; + rewindMarker = true; + } + northingValue += 100000.0; + } + + return northingValue; +} + +/** + * The function getMinNorthing returns the minimum northing value of a MGRS + * zone. + * + * Ported from Geotrans' c Lattitude_Band_Value structure table. + * + * @private + * @param {char} zoneLetter The MGRS zone to get the min northing for. + * @return {number} + */ +function getMinNorthing(zoneLetter) { + var northing; + switch (zoneLetter) { + case 'C': + northing = 1100000.0; + break; + case 'D': + northing = 2000000.0; + break; + case 'E': + northing = 2800000.0; + break; + case 'F': + northing = 3700000.0; + break; + case 'G': + northing = 4600000.0; + break; + case 'H': + northing = 5500000.0; + break; + case 'J': + northing = 6400000.0; + break; + case 'K': + northing = 7300000.0; + break; + case 'L': + northing = 8200000.0; + break; + case 'M': + northing = 9100000.0; + break; + case 'N': + northing = 0.0; + break; + case 'P': + northing = 800000.0; + break; + case 'Q': + northing = 1700000.0; + break; + case 'R': + northing = 2600000.0; + break; + case 'S': + northing = 3500000.0; + break; + case 'T': + northing = 4400000.0; + break; + case 'U': + northing = 5300000.0; + break; + case 'V': + northing = 6200000.0; + break; + case 'W': + northing = 7000000.0; + break; + case 'X': + northing = 7900000.0; + break; + default: + northing = -1.0; + } + if (northing >= 0.0) { + return northing; + } + else { + throw ("Invalid zone letter: " + zoneLetter); + } + +} + +function Point(x, y, z) { + if (!(this instanceof Point)) { + return new Point(x, y, z); + } + if (Array.isArray(x)) { + this.x = x[0]; + this.y = x[1]; + this.z = x[2] || 0.0; + } else if(typeof x === 'object') { + this.x = x.x; + this.y = x.y; + this.z = x.z || 0.0; + } else if (typeof x === 'string' && typeof y === 'undefined') { + var coords = x.split(','); + this.x = parseFloat(coords[0], 10); + this.y = parseFloat(coords[1], 10); + this.z = parseFloat(coords[2], 10) || 0.0; + } else { + this.x = x; + this.y = y; + this.z = z || 0.0; + } + console.warn('proj4.Point will be removed in version 3, use proj4.toPoint'); +} + +Point.fromMGRS = function(mgrsStr) { + return new Point(toPoint(mgrsStr)); +}; +Point.prototype.toMGRS = function(accuracy) { + return forward$t([this.x, this.y], accuracy); +}; + +var C00 = 1; +var C02 = 0.25; +var C04 = 0.046875; +var C06 = 0.01953125; +var C08 = 0.01068115234375; +var C22 = 0.75; +var C44 = 0.46875; +var C46 = 0.01302083333333333333; +var C48 = 0.00712076822916666666; +var C66 = 0.36458333333333333333; +var C68 = 0.00569661458333333333; +var C88 = 0.3076171875; + +function pj_enfn(es) { + var en = []; + en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08))); + en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08))); + var t = es * es; + en[2] = t * (C44 - es * (C46 + es * C48)); + t *= es; + en[3] = t * (C66 - es * C68); + en[4] = t * es * C88; + return en; +} + +function pj_mlfn(phi, sphi, cphi, en) { + cphi *= sphi; + sphi *= sphi; + return (en[0] * phi - cphi * (en[1] + sphi * (en[2] + sphi * (en[3] + sphi * en[4])))); +} + +var MAX_ITER$3 = 20; + +function pj_inv_mlfn(arg, es, en) { + var k = 1 / (1 - es); + var phi = arg; + for (var i = MAX_ITER$3; i; --i) { /* rarely goes over 2 iterations */ + var s = Math.sin(phi); + var t = 1 - es * s * s; + //t = this.pj_mlfn(phi, s, Math.cos(phi), en) - arg; + //phi -= t * (t * Math.sqrt(t)) * k; + t = (pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k; + phi -= t; + if (Math.abs(t) < EPSLN) { + return phi; + } + } + //..reportError("cass:pj_inv_mlfn: Convergence error"); + return phi; +} + +// Heavily based on this tmerc projection implementation +// https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js + + +function init$t() { + this.x0 = this.x0 !== undefined ? this.x0 : 0; + this.y0 = this.y0 !== undefined ? this.y0 : 0; + this.long0 = this.long0 !== undefined ? this.long0 : 0; + this.lat0 = this.lat0 !== undefined ? this.lat0 : 0; + + if (this.es) { + this.en = pj_enfn(this.es); + this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en); + } +} + +/** + Transverse Mercator Forward - long/lat to x/y + long/lat in radians + */ +function forward$s(p) { + var lon = p.x; + var lat = p.y; + + var delta_lon = adjust_lon(lon - this.long0); + var con; + var x, y; + var sin_phi = Math.sin(lat); + var cos_phi = Math.cos(lat); + + if (!this.es) { + var b = cos_phi * Math.sin(delta_lon); + + if ((Math.abs(Math.abs(b) - 1)) < EPSLN) { + return (93); + } + else { + x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0; + y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2)); + b = Math.abs(y); + + if (b >= 1) { + if ((b - 1) > EPSLN) { + return (93); + } + else { + y = 0; + } + } + else { + y = Math.acos(y); + } + + if (lat < 0) { + y = -y; + } + + y = this.a * this.k0 * (y - this.lat0) + this.y0; + } + } + else { + var al = cos_phi * delta_lon; + var als = Math.pow(al, 2); + var c = this.ep2 * Math.pow(cos_phi, 2); + var cs = Math.pow(c, 2); + var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0; + var t = Math.pow(tq, 2); + var ts = Math.pow(t, 2); + con = 1 - this.es * Math.pow(sin_phi, 2); + al = al / Math.sqrt(con); + var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en); + + x = this.a * (this.k0 * al * (1 + + als / 6 * (1 - t + c + + als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c + + als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) + + this.x0; + + y = this.a * (this.k0 * (ml - this.ml0 + + sin_phi * delta_lon * al / 2 * (1 + + als / 12 * (5 - t + 9 * c + 4 * cs + + als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c + + als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) + + this.y0; + } + + p.x = x; + p.y = y; + + return p; +} + +/** + Transverse Mercator Inverse - x/y to long/lat + */ +function inverse$s(p) { + var con, phi; + var lat, lon; + var x = (p.x - this.x0) * (1 / this.a); + var y = (p.y - this.y0) * (1 / this.a); + + if (!this.es) { + var f = Math.exp(x / this.k0); + var g = 0.5 * (f - 1 / f); + var temp = this.lat0 + y / this.k0; + var h = Math.cos(temp); + con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2))); + lat = Math.asin(con); + + if (y < 0) { + lat = -lat; + } + + if ((g === 0) && (h === 0)) { + lon = 0; + } + else { + lon = adjust_lon(Math.atan2(g, h) + this.long0); + } + } + else { // ellipsoidal form + con = this.ml0 + y / this.k0; + phi = pj_inv_mlfn(con, this.es, this.en); + + if (Math.abs(phi) < HALF_PI) { + var sin_phi = Math.sin(phi); + var cos_phi = Math.cos(phi); + var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0; + var c = this.ep2 * Math.pow(cos_phi, 2); + var cs = Math.pow(c, 2); + var t = Math.pow(tan_phi, 2); + var ts = Math.pow(t, 2); + con = 1 - this.es * Math.pow(sin_phi, 2); + var d = x * Math.sqrt(con) / this.k0; + var ds = Math.pow(d, 2); + con = con * tan_phi; + + lat = phi - (con * ds / (1 - this.es)) * 0.5 * (1 - + ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs - + ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c - + ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t)))); + + lon = adjust_lon(this.long0 + (d * (1 - + ds / 6 * (1 + 2 * t + c - + ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c - + ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi)); + } + else { + lat = HALF_PI * sign(y); + lon = 0; + } + } + + p.x = lon; + p.y = lat; + + return p; +} + +var names$t = ["Fast_Transverse_Mercator", "Fast Transverse Mercator"]; +var tmerc = { + init: init$t, + forward: forward$s, + inverse: inverse$s, + names: names$t +}; + +function sinh(x) { + var r = Math.exp(x); + r = (r - 1 / r) / 2; + return r; +} + +function hypot(x, y) { + x = Math.abs(x); + y = Math.abs(y); + var a = Math.max(x, y); + var b = Math.min(x, y) / (a ? a : 1); + + return a * Math.sqrt(1 + Math.pow(b, 2)); +} + +function log1py(x) { + var y = 1 + x; + var z = y - 1; + + return z === 0 ? x : x * Math.log(y) / z; +} + +function asinhy(x) { + var y = Math.abs(x); + y = log1py(y * (1 + y / (hypot(1, y) + 1))); + + return x < 0 ? -y : y; +} + +function gatg(pp, B) { + var cos_2B = 2 * Math.cos(2 * B); + var i = pp.length - 1; + var h1 = pp[i]; + var h2 = 0; + var h; + + while (--i >= 0) { + h = -h2 + cos_2B * h1 + pp[i]; + h2 = h1; + h1 = h; + } + + return (B + h * Math.sin(2 * B)); +} + +function clens(pp, arg_r) { + var r = 2 * Math.cos(arg_r); + var i = pp.length - 1; + var hr1 = pp[i]; + var hr2 = 0; + var hr; + + while (--i >= 0) { + hr = -hr2 + r * hr1 + pp[i]; + hr2 = hr1; + hr1 = hr; + } + + return Math.sin(arg_r) * hr; +} + +function cosh(x) { + var r = Math.exp(x); + r = (r + 1 / r) / 2; + return r; +} + +function clens_cmplx(pp, arg_r, arg_i) { + var sin_arg_r = Math.sin(arg_r); + var cos_arg_r = Math.cos(arg_r); + var sinh_arg_i = sinh(arg_i); + var cosh_arg_i = cosh(arg_i); + var r = 2 * cos_arg_r * cosh_arg_i; + var i = -2 * sin_arg_r * sinh_arg_i; + var j = pp.length - 1; + var hr = pp[j]; + var hi1 = 0; + var hr1 = 0; + var hi = 0; + var hr2; + var hi2; + + while (--j >= 0) { + hr2 = hr1; + hi2 = hi1; + hr1 = hr; + hi1 = hi; + hr = -hr2 + r * hr1 - i * hi1 + pp[j]; + hi = -hi2 + i * hr1 + r * hi1; + } + + r = sin_arg_r * cosh_arg_i; + i = cos_arg_r * sinh_arg_i; + + return [r * hr - i * hi, r * hi + i * hr]; +} + +// Heavily based on this etmerc projection implementation +// https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/etmerc.js + + +function init$s() { + if (!this.approx && (isNaN(this.es) || this.es <= 0)) { + throw new Error('Incorrect elliptical usage. Try using the +approx option in the proj string, or PROJECTION["Fast_Transverse_Mercator"] in the WKT.'); + } + if (this.approx) { + // When '+approx' is set, use tmerc instead + tmerc.init.apply(this); + this.forward = tmerc.forward; + this.inverse = tmerc.inverse; + } + + this.x0 = this.x0 !== undefined ? this.x0 : 0; + this.y0 = this.y0 !== undefined ? this.y0 : 0; + this.long0 = this.long0 !== undefined ? this.long0 : 0; + this.lat0 = this.lat0 !== undefined ? this.lat0 : 0; + + this.cgb = []; + this.cbg = []; + this.utg = []; + this.gtu = []; + + var f = this.es / (1 + Math.sqrt(1 - this.es)); + var n = f / (2 - f); + var np = n; + + this.cgb[0] = n * (2 + n * (-2 / 3 + n * (-2 + n * (116 / 45 + n * (26 / 45 + n * (-2854 / 675 )))))); + this.cbg[0] = n * (-2 + n * ( 2 / 3 + n * ( 4 / 3 + n * (-82 / 45 + n * (32 / 45 + n * (4642 / 4725)))))); + + np = np * n; + this.cgb[1] = np * (7 / 3 + n * (-8 / 5 + n * (-227 / 45 + n * (2704 / 315 + n * (2323 / 945))))); + this.cbg[1] = np * (5 / 3 + n * (-16 / 15 + n * ( -13 / 9 + n * (904 / 315 + n * (-1522 / 945))))); + + np = np * n; + this.cgb[2] = np * (56 / 15 + n * (-136 / 35 + n * (-1262 / 105 + n * (73814 / 2835)))); + this.cbg[2] = np * (-26 / 15 + n * (34 / 21 + n * (8 / 5 + n * (-12686 / 2835)))); + + np = np * n; + this.cgb[3] = np * (4279 / 630 + n * (-332 / 35 + n * (-399572 / 14175))); + this.cbg[3] = np * (1237 / 630 + n * (-12 / 5 + n * ( -24832 / 14175))); + + np = np * n; + this.cgb[4] = np * (4174 / 315 + n * (-144838 / 6237)); + this.cbg[4] = np * (-734 / 315 + n * (109598 / 31185)); + + np = np * n; + this.cgb[5] = np * (601676 / 22275); + this.cbg[5] = np * (444337 / 155925); + + np = Math.pow(n, 2); + this.Qn = this.k0 / (1 + n) * (1 + np * (1 / 4 + np * (1 / 64 + np / 256))); + + this.utg[0] = n * (-0.5 + n * ( 2 / 3 + n * (-37 / 96 + n * ( 1 / 360 + n * (81 / 512 + n * (-96199 / 604800)))))); + this.gtu[0] = n * (0.5 + n * (-2 / 3 + n * (5 / 16 + n * (41 / 180 + n * (-127 / 288 + n * (7891 / 37800)))))); + + this.utg[1] = np * (-1 / 48 + n * (-1 / 15 + n * (437 / 1440 + n * (-46 / 105 + n * (1118711 / 3870720))))); + this.gtu[1] = np * (13 / 48 + n * (-3 / 5 + n * (557 / 1440 + n * (281 / 630 + n * (-1983433 / 1935360))))); + + np = np * n; + this.utg[2] = np * (-17 / 480 + n * (37 / 840 + n * (209 / 4480 + n * (-5569 / 90720 )))); + this.gtu[2] = np * (61 / 240 + n * (-103 / 140 + n * (15061 / 26880 + n * (167603 / 181440)))); + + np = np * n; + this.utg[3] = np * (-4397 / 161280 + n * (11 / 504 + n * (830251 / 7257600))); + this.gtu[3] = np * (49561 / 161280 + n * (-179 / 168 + n * (6601661 / 7257600))); + + np = np * n; + this.utg[4] = np * (-4583 / 161280 + n * (108847 / 3991680)); + this.gtu[4] = np * (34729 / 80640 + n * (-3418889 / 1995840)); + + np = np * n; + this.utg[5] = np * (-20648693 / 638668800); + this.gtu[5] = np * (212378941 / 319334400); + + var Z = gatg(this.cbg, this.lat0); + this.Zb = -this.Qn * (Z + clens(this.gtu, 2 * Z)); +} + +function forward$r(p) { + var Ce = adjust_lon(p.x - this.long0); + var Cn = p.y; + + Cn = gatg(this.cbg, Cn); + var sin_Cn = Math.sin(Cn); + var cos_Cn = Math.cos(Cn); + var sin_Ce = Math.sin(Ce); + var cos_Ce = Math.cos(Ce); + + Cn = Math.atan2(sin_Cn, cos_Ce * cos_Cn); + Ce = Math.atan2(sin_Ce * cos_Cn, hypot(sin_Cn, cos_Cn * cos_Ce)); + Ce = asinhy(Math.tan(Ce)); + + var tmp = clens_cmplx(this.gtu, 2 * Cn, 2 * Ce); + + Cn = Cn + tmp[0]; + Ce = Ce + tmp[1]; + + var x; + var y; + + if (Math.abs(Ce) <= 2.623395162778) { + x = this.a * (this.Qn * Ce) + this.x0; + y = this.a * (this.Qn * Cn + this.Zb) + this.y0; + } + else { + x = Infinity; + y = Infinity; + } + + p.x = x; + p.y = y; + + return p; +} + +function inverse$r(p) { + var Ce = (p.x - this.x0) * (1 / this.a); + var Cn = (p.y - this.y0) * (1 / this.a); + + Cn = (Cn - this.Zb) / this.Qn; + Ce = Ce / this.Qn; + + var lon; + var lat; + + if (Math.abs(Ce) <= 2.623395162778) { + var tmp = clens_cmplx(this.utg, 2 * Cn, 2 * Ce); + + Cn = Cn + tmp[0]; + Ce = Ce + tmp[1]; + Ce = Math.atan(sinh(Ce)); + + var sin_Cn = Math.sin(Cn); + var cos_Cn = Math.cos(Cn); + var sin_Ce = Math.sin(Ce); + var cos_Ce = Math.cos(Ce); + + Cn = Math.atan2(sin_Cn * cos_Ce, hypot(sin_Ce, cos_Ce * cos_Cn)); + Ce = Math.atan2(sin_Ce, cos_Ce * cos_Cn); + + lon = adjust_lon(Ce + this.long0); + lat = gatg(this.cgb, Cn); + } + else { + lon = Infinity; + lat = Infinity; + } + + p.x = lon; + p.y = lat; + + return p; +} + +var names$s = ["Extended_Transverse_Mercator", "Extended Transverse Mercator", "etmerc", "Transverse_Mercator", "Transverse Mercator", "Gauss Kruger", "Gauss_Kruger", "tmerc"]; +var etmerc = { + init: init$s, + forward: forward$r, + inverse: inverse$r, + names: names$s +}; + +function adjust_zone(zone, lon) { + if (zone === undefined) { + zone = Math.floor((adjust_lon(lon) + Math.PI) * 30 / Math.PI) + 1; + + if (zone < 0) { + return 0; + } else if (zone > 60) { + return 60; + } + } + return zone; +} + +var dependsOn = 'etmerc'; + + +function init$r() { + var zone = adjust_zone(this.zone, this.long0); + if (zone === undefined) { + throw new Error('unknown utm zone'); + } + this.lat0 = 0; + this.long0 = ((6 * Math.abs(zone)) - 183) * D2R$1; + this.x0 = 500000; + this.y0 = this.utmSouth ? 10000000 : 0; + this.k0 = 0.9996; + + etmerc.init.apply(this); + this.forward = etmerc.forward; + this.inverse = etmerc.inverse; +} + +var names$r = ["Universal Transverse Mercator System", "utm"]; +var utm = { + init: init$r, + names: names$r, + dependsOn: dependsOn +}; + +function srat(esinp, exp) { + return (Math.pow((1 - esinp) / (1 + esinp), exp)); +} + +var MAX_ITER$2 = 20; + +function init$q() { + var sphi = Math.sin(this.lat0); + var cphi = Math.cos(this.lat0); + cphi *= cphi; + this.rc = Math.sqrt(1 - this.es) / (1 - this.es * sphi * sphi); + this.C = Math.sqrt(1 + this.es * cphi * cphi / (1 - this.es)); + this.phic0 = Math.asin(sphi / this.C); + this.ratexp = 0.5 * this.C * this.e; + this.K = Math.tan(0.5 * this.phic0 + FORTPI) / (Math.pow(Math.tan(0.5 * this.lat0 + FORTPI), this.C) * srat(this.e * sphi, this.ratexp)); +} + +function forward$q(p) { + var lon = p.x; + var lat = p.y; + + p.y = 2 * Math.atan(this.K * Math.pow(Math.tan(0.5 * lat + FORTPI), this.C) * srat(this.e * Math.sin(lat), this.ratexp)) - HALF_PI; + p.x = this.C * lon; + return p; +} + +function inverse$q(p) { + var DEL_TOL = 1e-14; + var lon = p.x / this.C; + var lat = p.y; + var num = Math.pow(Math.tan(0.5 * lat + FORTPI) / this.K, 1 / this.C); + for (var i = MAX_ITER$2; i > 0; --i) { + lat = 2 * Math.atan(num * srat(this.e * Math.sin(p.y), - 0.5 * this.e)) - HALF_PI; + if (Math.abs(lat - p.y) < DEL_TOL) { + break; + } + p.y = lat; + } + /* convergence failed */ + if (!i) { + return null; + } + p.x = lon; + p.y = lat; + return p; +} + +var names$q = ["gauss"]; +var gauss = { + init: init$q, + forward: forward$q, + inverse: inverse$q, + names: names$q +}; + +function init$p() { + gauss.init.apply(this); + if (!this.rc) { + return; + } + this.sinc0 = Math.sin(this.phic0); + this.cosc0 = Math.cos(this.phic0); + this.R2 = 2 * this.rc; + if (!this.title) { + this.title = "Oblique Stereographic Alternative"; + } +} + +function forward$p(p) { + var sinc, cosc, cosl, k; + p.x = adjust_lon(p.x - this.long0); + gauss.forward.apply(this, [p]); + sinc = Math.sin(p.y); + cosc = Math.cos(p.y); + cosl = Math.cos(p.x); + k = this.k0 * this.R2 / (1 + this.sinc0 * sinc + this.cosc0 * cosc * cosl); + p.x = k * cosc * Math.sin(p.x); + p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl); + p.x = this.a * p.x + this.x0; + p.y = this.a * p.y + this.y0; + return p; +} + +function inverse$p(p) { + var sinc, cosc, lon, lat, rho; + p.x = (p.x - this.x0) / this.a; + p.y = (p.y - this.y0) / this.a; + + p.x /= this.k0; + p.y /= this.k0; + if ((rho = hypot(p.x, p.y))) { + var c = 2 * Math.atan2(rho, this.R2); + sinc = Math.sin(c); + cosc = Math.cos(c); + lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho); + lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc); + } + else { + lat = this.phic0; + lon = 0; + } + + p.x = lon; + p.y = lat; + gauss.inverse.apply(this, [p]); + p.x = adjust_lon(p.x + this.long0); + return p; +} + +var names$p = ["Stereographic_North_Pole", "Oblique_Stereographic", "sterea","Oblique Stereographic Alternative","Double_Stereographic"]; +var sterea = { + init: init$p, + forward: forward$p, + inverse: inverse$p, + names: names$p +}; + +function ssfn_(phit, sinphi, eccen) { + sinphi *= eccen; + return (Math.tan(0.5 * (HALF_PI + phit)) * Math.pow((1 - sinphi) / (1 + sinphi), 0.5 * eccen)); +} + +function init$o() { + + // setting default parameters + this.x0 = this.x0 || 0; + this.y0 = this.y0 || 0; + this.lat0 = this.lat0 || 0; + this.long0 = this.long0 || 0; + + this.coslat0 = Math.cos(this.lat0); + this.sinlat0 = Math.sin(this.lat0); + if (this.sphere) { + if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) { + this.k0 = 0.5 * (1 + sign(this.lat0) * Math.sin(this.lat_ts)); + } + } + else { + if (Math.abs(this.coslat0) <= EPSLN) { + if (this.lat0 > 0) { + //North pole + //trace('stere:north pole'); + this.con = 1; + } + else { + //South pole + //trace('stere:south pole'); + this.con = -1; + } + } + this.cons = Math.sqrt(Math.pow(1 + this.e, 1 + this.e) * Math.pow(1 - this.e, 1 - this.e)); + if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN && Math.abs(Math.cos(this.lat_ts)) > EPSLN) { + // When k0 is 1 (default value) and lat_ts is a vaild number and lat0 is at a pole and lat_ts is not at a pole + // Recalculate k0 using formula 21-35 from p161 of Snyder, 1987 + this.k0 = 0.5 * this.cons * msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)) / tsfnz(this.e, this.con * this.lat_ts, this.con * Math.sin(this.lat_ts)); + } + this.ms1 = msfnz(this.e, this.sinlat0, this.coslat0); + this.X0 = 2 * Math.atan(this.ssfn_(this.lat0, this.sinlat0, this.e)) - HALF_PI; + this.cosX0 = Math.cos(this.X0); + this.sinX0 = Math.sin(this.X0); + } +} + +// Stereographic forward equations--mapping lat,long to x,y +function forward$o(p) { + var lon = p.x; + var lat = p.y; + var sinlat = Math.sin(lat); + var coslat = Math.cos(lat); + var A, X, sinX, cosX, ts, rh; + var dlon = adjust_lon(lon - this.long0); + + if (Math.abs(Math.abs(lon - this.long0) - Math.PI) <= EPSLN && Math.abs(lat + this.lat0) <= EPSLN) { + //case of the origine point + //trace('stere:this is the origin point'); + p.x = NaN; + p.y = NaN; + return p; + } + if (this.sphere) { + //trace('stere:sphere case'); + A = 2 * this.k0 / (1 + this.sinlat0 * sinlat + this.coslat0 * coslat * Math.cos(dlon)); + p.x = this.a * A * coslat * Math.sin(dlon) + this.x0; + p.y = this.a * A * (this.coslat0 * sinlat - this.sinlat0 * coslat * Math.cos(dlon)) + this.y0; + return p; + } + else { + X = 2 * Math.atan(this.ssfn_(lat, sinlat, this.e)) - HALF_PI; + cosX = Math.cos(X); + sinX = Math.sin(X); + if (Math.abs(this.coslat0) <= EPSLN) { + ts = tsfnz(this.e, lat * this.con, this.con * sinlat); + rh = 2 * this.a * this.k0 * ts / this.cons; + p.x = this.x0 + rh * Math.sin(lon - this.long0); + p.y = this.y0 - this.con * rh * Math.cos(lon - this.long0); + //trace(p.toString()); + return p; + } + else if (Math.abs(this.sinlat0) < EPSLN) { + //Eq + //trace('stere:equateur'); + A = 2 * this.a * this.k0 / (1 + cosX * Math.cos(dlon)); + p.y = A * sinX; + } + else { + //other case + //trace('stere:normal case'); + A = 2 * this.a * this.k0 * this.ms1 / (this.cosX0 * (1 + this.sinX0 * sinX + this.cosX0 * cosX * Math.cos(dlon))); + p.y = A * (this.cosX0 * sinX - this.sinX0 * cosX * Math.cos(dlon)) + this.y0; + } + p.x = A * cosX * Math.sin(dlon) + this.x0; + } + //trace(p.toString()); + return p; +} + +//* Stereographic inverse equations--mapping x,y to lat/long +function inverse$o(p) { + p.x -= this.x0; + p.y -= this.y0; + var lon, lat, ts, ce, Chi; + var rh = Math.sqrt(p.x * p.x + p.y * p.y); + if (this.sphere) { + var c = 2 * Math.atan(rh / (2 * this.a * this.k0)); + lon = this.long0; + lat = this.lat0; + if (rh <= EPSLN) { + p.x = lon; + p.y = lat; + return p; + } + lat = Math.asin(Math.cos(c) * this.sinlat0 + p.y * Math.sin(c) * this.coslat0 / rh); + if (Math.abs(this.coslat0) < EPSLN) { + if (this.lat0 > 0) { + lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y)); + } + else { + lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y)); + } + } + else { + lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(c), rh * this.coslat0 * Math.cos(c) - p.y * this.sinlat0 * Math.sin(c))); + } + p.x = lon; + p.y = lat; + return p; + } + else { + if (Math.abs(this.coslat0) <= EPSLN) { + if (rh <= EPSLN) { + lat = this.lat0; + lon = this.long0; + p.x = lon; + p.y = lat; + //trace(p.toString()); + return p; + } + p.x *= this.con; + p.y *= this.con; + ts = rh * this.cons / (2 * this.a * this.k0); + lat = this.con * phi2z(this.e, ts); + lon = this.con * adjust_lon(this.con * this.long0 + Math.atan2(p.x, - 1 * p.y)); + } + else { + ce = 2 * Math.atan(rh * this.cosX0 / (2 * this.a * this.k0 * this.ms1)); + lon = this.long0; + if (rh <= EPSLN) { + Chi = this.X0; + } + else { + Chi = Math.asin(Math.cos(ce) * this.sinX0 + p.y * Math.sin(ce) * this.cosX0 / rh); + lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(ce), rh * this.cosX0 * Math.cos(ce) - p.y * this.sinX0 * Math.sin(ce))); + } + lat = -1 * phi2z(this.e, Math.tan(0.5 * (HALF_PI + Chi))); + } + } + p.x = lon; + p.y = lat; + + //trace(p.toString()); + return p; + +} + +var names$o = ["stere", "Stereographic_South_Pole", "Polar Stereographic (variant B)", "Polar_Stereographic"]; +var stere = { + init: init$o, + forward: forward$o, + inverse: inverse$o, + names: names$o, + ssfn_: ssfn_ +}; + +/* + references: + Formules et constantes pour le Calcul pour la + projection cylindrique conforme à axe oblique et pour la transformation entre + des systèmes de référence. + http://www.swisstopo.admin.ch/internet/swisstopo/fr/home/topics/survey/sys/refsys/switzerland.parsysrelated1.31216.downloadList.77004.DownloadFile.tmp/swissprojectionfr.pdf + */ + +function init$n() { + var phy0 = this.lat0; + this.lambda0 = this.long0; + var sinPhy0 = Math.sin(phy0); + var semiMajorAxis = this.a; + var invF = this.rf; + var flattening = 1 / invF; + var e2 = 2 * flattening - Math.pow(flattening, 2); + var e = this.e = Math.sqrt(e2); + this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2)); + this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4)); + this.b0 = Math.asin(sinPhy0 / this.alpha); + var k1 = Math.log(Math.tan(Math.PI / 4 + this.b0 / 2)); + var k2 = Math.log(Math.tan(Math.PI / 4 + phy0 / 2)); + var k3 = Math.log((1 + e * sinPhy0) / (1 - e * sinPhy0)); + this.K = k1 - this.alpha * k2 + this.alpha * e / 2 * k3; +} + +function forward$n(p) { + var Sa1 = Math.log(Math.tan(Math.PI / 4 - p.y / 2)); + var Sa2 = this.e / 2 * Math.log((1 + this.e * Math.sin(p.y)) / (1 - this.e * Math.sin(p.y))); + var S = -this.alpha * (Sa1 + Sa2) + this.K; + + // spheric latitude + var b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4); + + // spheric longitude + var I = this.alpha * (p.x - this.lambda0); + + // psoeudo equatorial rotation + var rotI = Math.atan(Math.sin(I) / (Math.sin(this.b0) * Math.tan(b) + Math.cos(this.b0) * Math.cos(I))); + + var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) - Math.sin(this.b0) * Math.cos(b) * Math.cos(I)); + + p.y = this.R / 2 * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB))) + this.y0; + p.x = this.R * rotI + this.x0; + return p; +} + +function inverse$n(p) { + var Y = p.x - this.x0; + var X = p.y - this.y0; + + var rotI = Y / this.R; + var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4); + + var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB) + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI)); + var I = Math.atan(Math.sin(rotI) / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0) * Math.tan(rotB))); + + var lambda = this.lambda0 + I / this.alpha; + + var S = 0; + var phy = b; + var prevPhy = -1000; + var iteration = 0; + while (Math.abs(phy - prevPhy) > 0.0000001) { + if (++iteration > 20) { + //...reportError("omercFwdInfinity"); + return; + } + //S = Math.log(Math.tan(Math.PI / 4 + phy / 2)); + S = 1 / this.alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - this.K) + this.e * Math.log(Math.tan(Math.PI / 4 + Math.asin(this.e * Math.sin(phy)) / 2)); + prevPhy = phy; + phy = 2 * Math.atan(Math.exp(S)) - Math.PI / 2; + } + + p.x = lambda; + p.y = phy; + return p; +} + +var names$n = ["somerc"]; +var somerc = { + init: init$n, + forward: forward$n, + inverse: inverse$n, + names: names$n +}; + +var TOL = 1e-7; + +function isTypeA(P) { + var typeAProjections = ['Hotine_Oblique_Mercator','Hotine_Oblique_Mercator_Azimuth_Natural_Origin']; + var projectionName = typeof P.PROJECTION === "object" ? Object.keys(P.PROJECTION)[0] : P.PROJECTION; + + return 'no_uoff' in P || 'no_off' in P || typeAProjections.indexOf(projectionName) !== -1; +} + + +/* Initialize the Oblique Mercator projection + ------------------------------------------*/ +function init$m() { + var con, com, cosph0, D, F, H, L, sinph0, p, J, gamma = 0, + gamma0, lamc = 0, lam1 = 0, lam2 = 0, phi1 = 0, phi2 = 0, alpha_c = 0; + + // only Type A uses the no_off or no_uoff property + // https://github.com/OSGeo/proj.4/issues/104 + this.no_off = isTypeA(this); + this.no_rot = 'no_rot' in this; + + var alp = false; + if ("alpha" in this) { + alp = true; + } + + var gam = false; + if ("rectified_grid_angle" in this) { + gam = true; + } + + if (alp) { + alpha_c = this.alpha; + } + + if (gam) { + gamma = (this.rectified_grid_angle * D2R$1); + } + + if (alp || gam) { + lamc = this.longc; + } else { + lam1 = this.long1; + phi1 = this.lat1; + lam2 = this.long2; + phi2 = this.lat2; + + if (Math.abs(phi1 - phi2) <= TOL || (con = Math.abs(phi1)) <= TOL || + Math.abs(con - HALF_PI) <= TOL || Math.abs(Math.abs(this.lat0) - HALF_PI) <= TOL || + Math.abs(Math.abs(phi2) - HALF_PI) <= TOL) { + throw new Error(); + } + } + + var one_es = 1.0 - this.es; + com = Math.sqrt(one_es); + + if (Math.abs(this.lat0) > EPSLN) { + sinph0 = Math.sin(this.lat0); + cosph0 = Math.cos(this.lat0); + con = 1 - this.es * sinph0 * sinph0; + this.B = cosph0 * cosph0; + this.B = Math.sqrt(1 + this.es * this.B * this.B / one_es); + this.A = this.B * this.k0 * com / con; + D = this.B * com / (cosph0 * Math.sqrt(con)); + F = D * D -1; + + if (F <= 0) { + F = 0; + } else { + F = Math.sqrt(F); + if (this.lat0 < 0) { + F = -F; + } + } + + this.E = F += D; + this.E *= Math.pow(tsfnz(this.e, this.lat0, sinph0), this.B); + } else { + this.B = 1 / com; + this.A = this.k0; + this.E = D = F = 1; + } + + if (alp || gam) { + if (alp) { + gamma0 = Math.asin(Math.sin(alpha_c) / D); + if (!gam) { + gamma = alpha_c; + } + } else { + gamma0 = gamma; + alpha_c = Math.asin(D * Math.sin(gamma0)); + } + this.lam0 = lamc - Math.asin(0.5 * (F - 1 / F) * Math.tan(gamma0)) / this.B; + } else { + H = Math.pow(tsfnz(this.e, phi1, Math.sin(phi1)), this.B); + L = Math.pow(tsfnz(this.e, phi2, Math.sin(phi2)), this.B); + F = this.E / H; + p = (L - H) / (L + H); + J = this.E * this.E; + J = (J - L * H) / (J + L * H); + con = lam1 - lam2; + + if (con < -Math.pi) { + lam2 -=TWO_PI; + } else if (con > Math.pi) { + lam2 += TWO_PI; + } + + this.lam0 = adjust_lon(0.5 * (lam1 + lam2) - Math.atan(J * Math.tan(0.5 * this.B * (lam1 - lam2)) / p) / this.B); + gamma0 = Math.atan(2 * Math.sin(this.B * adjust_lon(lam1 - this.lam0)) / (F - 1 / F)); + gamma = alpha_c = Math.asin(D * Math.sin(gamma0)); + } + + this.singam = Math.sin(gamma0); + this.cosgam = Math.cos(gamma0); + this.sinrot = Math.sin(gamma); + this.cosrot = Math.cos(gamma); + + this.rB = 1 / this.B; + this.ArB = this.A * this.rB; + this.BrA = 1 / this.ArB; + this.A * this.B; + + if (this.no_off) { + this.u_0 = 0; + } else { + this.u_0 = Math.abs(this.ArB * Math.atan(Math.sqrt(D * D - 1) / Math.cos(alpha_c))); + + if (this.lat0 < 0) { + this.u_0 = - this.u_0; + } + } + + F = 0.5 * gamma0; + this.v_pole_n = this.ArB * Math.log(Math.tan(FORTPI - F)); + this.v_pole_s = this.ArB * Math.log(Math.tan(FORTPI + F)); +} + + +/* Oblique Mercator forward equations--mapping lat,long to x,y + ----------------------------------------------------------*/ +function forward$m(p) { + var coords = {}; + var S, T, U, V, W, temp, u, v; + p.x = p.x - this.lam0; + + if (Math.abs(Math.abs(p.y) - HALF_PI) > EPSLN) { + W = this.E / Math.pow(tsfnz(this.e, p.y, Math.sin(p.y)), this.B); + + temp = 1 / W; + S = 0.5 * (W - temp); + T = 0.5 * (W + temp); + V = Math.sin(this.B * p.x); + U = (S * this.singam - V * this.cosgam) / T; + + if (Math.abs(Math.abs(U) - 1.0) < EPSLN) { + throw new Error(); + } + + v = 0.5 * this.ArB * Math.log((1 - U)/(1 + U)); + temp = Math.cos(this.B * p.x); + + if (Math.abs(temp) < TOL) { + u = this.A * p.x; + } else { + u = this.ArB * Math.atan2((S * this.cosgam + V * this.singam), temp); + } + } else { + v = p.y > 0 ? this.v_pole_n : this.v_pole_s; + u = this.ArB * p.y; + } + + if (this.no_rot) { + coords.x = u; + coords.y = v; + } else { + u -= this.u_0; + coords.x = v * this.cosrot + u * this.sinrot; + coords.y = u * this.cosrot - v * this.sinrot; + } + + coords.x = (this.a * coords.x + this.x0); + coords.y = (this.a * coords.y + this.y0); + + return coords; +} + +function inverse$m(p) { + var u, v, Qp, Sp, Tp, Vp, Up; + var coords = {}; + + p.x = (p.x - this.x0) * (1.0 / this.a); + p.y = (p.y - this.y0) * (1.0 / this.a); + + if (this.no_rot) { + v = p.y; + u = p.x; + } else { + v = p.x * this.cosrot - p.y * this.sinrot; + u = p.y * this.cosrot + p.x * this.sinrot + this.u_0; + } + + Qp = Math.exp(-this.BrA * v); + Sp = 0.5 * (Qp - 1 / Qp); + Tp = 0.5 * (Qp + 1 / Qp); + Vp = Math.sin(this.BrA * u); + Up = (Vp * this.cosgam + Sp * this.singam) / Tp; + + if (Math.abs(Math.abs(Up) - 1) < EPSLN) { + coords.x = 0; + coords.y = Up < 0 ? -HALF_PI : HALF_PI; + } else { + coords.y = this.E / Math.sqrt((1 + Up) / (1 - Up)); + coords.y = phi2z(this.e, Math.pow(coords.y, 1 / this.B)); + + if (coords.y === Infinity) { + throw new Error(); + } + + coords.x = -this.rB * Math.atan2((Sp * this.cosgam - Vp * this.singam), Math.cos(this.BrA * u)); + } + + coords.x += this.lam0; + + return coords; +} + +var names$m = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "Oblique_Mercator", "omerc"]; +var omerc = { + init: init$m, + forward: forward$m, + inverse: inverse$m, + names: names$m +}; + +function init$l() { + + //double lat0; /* the reference latitude */ + //double long0; /* the reference longitude */ + //double lat1; /* first standard parallel */ + //double lat2; /* second standard parallel */ + //double r_maj; /* major axis */ + //double r_min; /* minor axis */ + //double false_east; /* x offset in meters */ + //double false_north; /* y offset in meters */ + + //the above value can be set with proj4.defs + //example: proj4.defs("EPSG:2154","+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"); + + if (!this.lat2) { + this.lat2 = this.lat1; + } //if lat2 is not defined + if (!this.k0) { + this.k0 = 1; + } + this.x0 = this.x0 || 0; + this.y0 = this.y0 || 0; + // Standard Parallels cannot be equal and on opposite sides of the equator + if (Math.abs(this.lat1 + this.lat2) < EPSLN) { + return; + } + + var temp = this.b / this.a; + this.e = Math.sqrt(1 - temp * temp); + + var sin1 = Math.sin(this.lat1); + var cos1 = Math.cos(this.lat1); + var ms1 = msfnz(this.e, sin1, cos1); + var ts1 = tsfnz(this.e, this.lat1, sin1); + + var sin2 = Math.sin(this.lat2); + var cos2 = Math.cos(this.lat2); + var ms2 = msfnz(this.e, sin2, cos2); + var ts2 = tsfnz(this.e, this.lat2, sin2); + + var ts0 = tsfnz(this.e, this.lat0, Math.sin(this.lat0)); + + if (Math.abs(this.lat1 - this.lat2) > EPSLN) { + this.ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2); + } + else { + this.ns = sin1; + } + if (isNaN(this.ns)) { + this.ns = sin1; + } + this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns)); + this.rh = this.a * this.f0 * Math.pow(ts0, this.ns); + if (!this.title) { + this.title = "Lambert Conformal Conic"; + } +} + +// Lambert Conformal conic forward equations--mapping lat,long to x,y +// ----------------------------------------------------------------- +function forward$l(p) { + + var lon = p.x; + var lat = p.y; + + // singular cases : + if (Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) { + lat = sign(lat) * (HALF_PI - 2 * EPSLN); + } + + var con = Math.abs(Math.abs(lat) - HALF_PI); + var ts, rh1; + if (con > EPSLN) { + ts = tsfnz(this.e, lat, Math.sin(lat)); + rh1 = this.a * this.f0 * Math.pow(ts, this.ns); + } + else { + con = lat * this.ns; + if (con <= 0) { + return null; + } + rh1 = 0; + } + var theta = this.ns * adjust_lon(lon - this.long0); + p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0; + p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0; + + return p; +} + +// Lambert Conformal Conic inverse equations--mapping x,y to lat/long +// ----------------------------------------------------------------- +function inverse$l(p) { + + var rh1, con, ts; + var lat, lon; + var x = (p.x - this.x0) / this.k0; + var y = (this.rh - (p.y - this.y0) / this.k0); + if (this.ns > 0) { + rh1 = Math.sqrt(x * x + y * y); + con = 1; + } + else { + rh1 = -Math.sqrt(x * x + y * y); + con = -1; + } + var theta = 0; + if (rh1 !== 0) { + theta = Math.atan2((con * x), (con * y)); + } + if ((rh1 !== 0) || (this.ns > 0)) { + con = 1 / this.ns; + ts = Math.pow((rh1 / (this.a * this.f0)), con); + lat = phi2z(this.e, ts); + if (lat === -9999) { + return null; + } + } + else { + lat = -HALF_PI; + } + lon = adjust_lon(theta / this.ns + this.long0); + + p.x = lon; + p.y = lat; + return p; +} + +var names$l = [ + "Lambert Tangential Conformal Conic Projection", + "Lambert_Conformal_Conic", + "Lambert_Conformal_Conic_1SP", + "Lambert_Conformal_Conic_2SP", + "lcc", + "Lambert Conic Conformal (1SP)", + "Lambert Conic Conformal (2SP)" +]; + +var lcc = { + init: init$l, + forward: forward$l, + inverse: inverse$l, + names: names$l +}; + +function init$k() { + this.a = 6377397.155; + this.es = 0.006674372230614; + this.e = Math.sqrt(this.es); + if (!this.lat0) { + this.lat0 = 0.863937979737193; + } + if (!this.long0) { + this.long0 = 0.7417649320975901 - 0.308341501185665; + } + /* if scale not set default to 0.9999 */ + if (!this.k0) { + this.k0 = 0.9999; + } + this.s45 = 0.785398163397448; /* 45 */ + this.s90 = 2 * this.s45; + this.fi0 = this.lat0; + this.e2 = this.es; + this.e = Math.sqrt(this.e2); + this.alfa = Math.sqrt(1 + (this.e2 * Math.pow(Math.cos(this.fi0), 4)) / (1 - this.e2)); + this.uq = 1.04216856380474; + this.u0 = Math.asin(Math.sin(this.fi0) / this.alfa); + this.g = Math.pow((1 + this.e * Math.sin(this.fi0)) / (1 - this.e * Math.sin(this.fi0)), this.alfa * this.e / 2); + this.k = Math.tan(this.u0 / 2 + this.s45) / Math.pow(Math.tan(this.fi0 / 2 + this.s45), this.alfa) * this.g; + this.k1 = this.k0; + this.n0 = this.a * Math.sqrt(1 - this.e2) / (1 - this.e2 * Math.pow(Math.sin(this.fi0), 2)); + this.s0 = 1.37008346281555; + this.n = Math.sin(this.s0); + this.ro0 = this.k1 * this.n0 / Math.tan(this.s0); + this.ad = this.s90 - this.uq; +} + +/* ellipsoid */ +/* calculate xy from lat/lon */ +/* Constants, identical to inverse transform function */ +function forward$k(p) { + var gfi, u, deltav, s, d, eps, ro; + var lon = p.x; + var lat = p.y; + var delta_lon = adjust_lon(lon - this.long0); + /* Transformation */ + gfi = Math.pow(((1 + this.e * Math.sin(lat)) / (1 - this.e * Math.sin(lat))), (this.alfa * this.e / 2)); + u = 2 * (Math.atan(this.k * Math.pow(Math.tan(lat / 2 + this.s45), this.alfa) / gfi) - this.s45); + deltav = -delta_lon * this.alfa; + s = Math.asin(Math.cos(this.ad) * Math.sin(u) + Math.sin(this.ad) * Math.cos(u) * Math.cos(deltav)); + d = Math.asin(Math.cos(u) * Math.sin(deltav) / Math.cos(s)); + eps = this.n * d; + ro = this.ro0 * Math.pow(Math.tan(this.s0 / 2 + this.s45), this.n) / Math.pow(Math.tan(s / 2 + this.s45), this.n); + p.y = ro * Math.cos(eps) / 1; + p.x = ro * Math.sin(eps) / 1; + + if (!this.czech) { + p.y *= -1; + p.x *= -1; + } + return (p); +} + +/* calculate lat/lon from xy */ +function inverse$k(p) { + var u, deltav, s, d, eps, ro, fi1; + var ok; + + /* Transformation */ + /* revert y, x*/ + var tmp = p.x; + p.x = p.y; + p.y = tmp; + if (!this.czech) { + p.y *= -1; + p.x *= -1; + } + ro = Math.sqrt(p.x * p.x + p.y * p.y); + eps = Math.atan2(p.y, p.x); + d = eps / Math.sin(this.s0); + s = 2 * (Math.atan(Math.pow(this.ro0 / ro, 1 / this.n) * Math.tan(this.s0 / 2 + this.s45)) - this.s45); + u = Math.asin(Math.cos(this.ad) * Math.sin(s) - Math.sin(this.ad) * Math.cos(s) * Math.cos(d)); + deltav = Math.asin(Math.cos(s) * Math.sin(d) / Math.cos(u)); + p.x = this.long0 - deltav / this.alfa; + fi1 = u; + ok = 0; + var iter = 0; + do { + p.y = 2 * (Math.atan(Math.pow(this.k, - 1 / this.alfa) * Math.pow(Math.tan(u / 2 + this.s45), 1 / this.alfa) * Math.pow((1 + this.e * Math.sin(fi1)) / (1 - this.e * Math.sin(fi1)), this.e / 2)) - this.s45); + if (Math.abs(fi1 - p.y) < 0.0000000001) { + ok = 1; + } + fi1 = p.y; + iter += 1; + } while (ok === 0 && iter < 15); + if (iter >= 15) { + return null; + } + + return (p); +} + +var names$k = ["Krovak", "krovak"]; +var krovak = { + init: init$k, + forward: forward$k, + inverse: inverse$k, + names: names$k +}; + +function mlfn(e0, e1, e2, e3, phi) { + return (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi)); +} + +function e0fn(x) { + return (1 - 0.25 * x * (1 + x / 16 * (3 + 1.25 * x))); +} + +function e1fn(x) { + return (0.375 * x * (1 + 0.25 * x * (1 + 0.46875 * x))); +} + +function e2fn(x) { + return (0.05859375 * x * x * (1 + 0.75 * x)); +} + +function e3fn(x) { + return (x * x * x * (35 / 3072)); +} + +function gN(a, e, sinphi) { + var temp = e * sinphi; + return a / Math.sqrt(1 - temp * temp); +} + +function adjust_lat(x) { + return (Math.abs(x) < HALF_PI) ? x : (x - (sign(x) * Math.PI)); +} + +function imlfn(ml, e0, e1, e2, e3) { + var phi; + var dphi; + + phi = ml / e0; + for (var i = 0; i < 15; i++) { + dphi = (ml - (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi))) / (e0 - 2 * e1 * Math.cos(2 * phi) + 4 * e2 * Math.cos(4 * phi) - 6 * e3 * Math.cos(6 * phi)); + phi += dphi; + if (Math.abs(dphi) <= 0.0000000001) { + return phi; + } + } + + //..reportError("IMLFN-CONV:Latitude failed to converge after 15 iterations"); + return NaN; +} + +function init$j() { + if (!this.sphere) { + this.e0 = e0fn(this.es); + this.e1 = e1fn(this.es); + this.e2 = e2fn(this.es); + this.e3 = e3fn(this.es); + this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); + } +} + +/* Cassini forward equations--mapping lat,long to x,y + -----------------------------------------------------------------------*/ +function forward$j(p) { + + /* Forward equations + -----------------*/ + var x, y; + var lam = p.x; + var phi = p.y; + lam = adjust_lon(lam - this.long0); + + if (this.sphere) { + x = this.a * Math.asin(Math.cos(phi) * Math.sin(lam)); + y = this.a * (Math.atan2(Math.tan(phi), Math.cos(lam)) - this.lat0); + } + else { + //ellipsoid + var sinphi = Math.sin(phi); + var cosphi = Math.cos(phi); + var nl = gN(this.a, this.e, sinphi); + var tl = Math.tan(phi) * Math.tan(phi); + var al = lam * Math.cos(phi); + var asq = al * al; + var cl = this.es * cosphi * cosphi / (1 - this.es); + var ml = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi); + + x = nl * al * (1 - asq * tl * (1 / 6 - (8 - tl + 8 * cl) * asq / 120)); + y = ml - this.ml0 + nl * sinphi / cosphi * asq * (0.5 + (5 - tl + 6 * cl) * asq / 24); + + + } + + p.x = x + this.x0; + p.y = y + this.y0; + return p; +} + +/* Inverse equations + -----------------*/ +function inverse$j(p) { + p.x -= this.x0; + p.y -= this.y0; + var x = p.x / this.a; + var y = p.y / this.a; + var phi, lam; + + if (this.sphere) { + var dd = y + this.lat0; + phi = Math.asin(Math.sin(dd) * Math.cos(x)); + lam = Math.atan2(Math.tan(x), Math.cos(dd)); + } + else { + /* ellipsoid */ + var ml1 = this.ml0 / this.a + y; + var phi1 = imlfn(ml1, this.e0, this.e1, this.e2, this.e3); + if (Math.abs(Math.abs(phi1) - HALF_PI) <= EPSLN) { + p.x = this.long0; + p.y = HALF_PI; + if (y < 0) { + p.y *= -1; + } + return p; + } + var nl1 = gN(this.a, this.e, Math.sin(phi1)); + + var rl1 = nl1 * nl1 * nl1 / this.a / this.a * (1 - this.es); + var tl1 = Math.pow(Math.tan(phi1), 2); + var dl = x * this.a / nl1; + var dsq = dl * dl; + phi = phi1 - nl1 * Math.tan(phi1) / rl1 * dl * dl * (0.5 - (1 + 3 * tl1) * dl * dl / 24); + lam = dl * (1 - dsq * (tl1 / 3 + (1 + 3 * tl1) * tl1 * dsq / 15)) / Math.cos(phi1); + + } + + p.x = adjust_lon(lam + this.long0); + p.y = adjust_lat(phi); + return p; + +} + +var names$j = ["Cassini", "Cassini_Soldner", "cass"]; +var cass = { + init: init$j, + forward: forward$j, + inverse: inverse$j, + names: names$j +}; + +function qsfnz(eccent, sinphi) { + var con; + if (eccent > 1.0e-7) { + con = eccent * sinphi; + return ((1 - eccent * eccent) * (sinphi / (1 - con * con) - (0.5 / eccent) * Math.log((1 - con) / (1 + con)))); + } + else { + return (2 * sinphi); + } +} + +/* + reference + "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder, + The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355. + */ + +var S_POLE = 1; + +var N_POLE = 2; +var EQUIT = 3; +var OBLIQ = 4; + +/* Initialize the Lambert Azimuthal Equal Area projection + ------------------------------------------------------*/ +function init$i() { + var t = Math.abs(this.lat0); + if (Math.abs(t - HALF_PI) < EPSLN) { + this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE; + } + else if (Math.abs(t) < EPSLN) { + this.mode = this.EQUIT; + } + else { + this.mode = this.OBLIQ; + } + if (this.es > 0) { + var sinphi; + + this.qp = qsfnz(this.e, 1); + this.mmf = 0.5 / (1 - this.es); + this.apa = authset(this.es); + switch (this.mode) { + case this.N_POLE: + this.dd = 1; + break; + case this.S_POLE: + this.dd = 1; + break; + case this.EQUIT: + this.rq = Math.sqrt(0.5 * this.qp); + this.dd = 1 / this.rq; + this.xmf = 1; + this.ymf = 0.5 * this.qp; + break; + case this.OBLIQ: + this.rq = Math.sqrt(0.5 * this.qp); + sinphi = Math.sin(this.lat0); + this.sinb1 = qsfnz(this.e, sinphi) / this.qp; + this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1); + this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1); + this.ymf = (this.xmf = this.rq) / this.dd; + this.xmf *= this.dd; + break; + } + } + else { + if (this.mode === this.OBLIQ) { + this.sinph0 = Math.sin(this.lat0); + this.cosph0 = Math.cos(this.lat0); + } + } +} + +/* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y + -----------------------------------------------------------------------*/ +function forward$i(p) { + + /* Forward equations + -----------------*/ + var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi; + var lam = p.x; + var phi = p.y; + + lam = adjust_lon(lam - this.long0); + if (this.sphere) { + sinphi = Math.sin(phi); + cosphi = Math.cos(phi); + coslam = Math.cos(lam); + if (this.mode === this.OBLIQ || this.mode === this.EQUIT) { + y = (this.mode === this.EQUIT) ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam; + if (y <= EPSLN) { + return null; + } + y = Math.sqrt(2 / y); + x = y * cosphi * Math.sin(lam); + y *= (this.mode === this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam; + } + else if (this.mode === this.N_POLE || this.mode === this.S_POLE) { + if (this.mode === this.N_POLE) { + coslam = -coslam; + } + if (Math.abs(phi + this.lat0) < EPSLN) { + return null; + } + y = FORTPI - phi * 0.5; + y = 2 * ((this.mode === this.S_POLE) ? Math.cos(y) : Math.sin(y)); + x = y * Math.sin(lam); + y *= coslam; + } + } + else { + sinb = 0; + cosb = 0; + b = 0; + coslam = Math.cos(lam); + sinlam = Math.sin(lam); + sinphi = Math.sin(phi); + q = qsfnz(this.e, sinphi); + if (this.mode === this.OBLIQ || this.mode === this.EQUIT) { + sinb = q / this.qp; + cosb = Math.sqrt(1 - sinb * sinb); + } + switch (this.mode) { + case this.OBLIQ: + b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam; + break; + case this.EQUIT: + b = 1 + cosb * coslam; + break; + case this.N_POLE: + b = HALF_PI + phi; + q = this.qp - q; + break; + case this.S_POLE: + b = phi - HALF_PI; + q = this.qp + q; + break; + } + if (Math.abs(b) < EPSLN) { + return null; + } + switch (this.mode) { + case this.OBLIQ: + case this.EQUIT: + b = Math.sqrt(2 / b); + if (this.mode === this.OBLIQ) { + y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam); + } + else { + y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf; + } + x = this.xmf * b * cosb * sinlam; + break; + case this.N_POLE: + case this.S_POLE: + if (q >= 0) { + x = (b = Math.sqrt(q)) * sinlam; + y = coslam * ((this.mode === this.S_POLE) ? b : -b); + } + else { + x = y = 0; + } + break; + } + } + + p.x = this.a * x + this.x0; + p.y = this.a * y + this.y0; + return p; +} + +/* Inverse equations + -----------------*/ +function inverse$i(p) { + p.x -= this.x0; + p.y -= this.y0; + var x = p.x / this.a; + var y = p.y / this.a; + var lam, phi, cCe, sCe, q, rho, ab; + if (this.sphere) { + var cosz = 0, + rh, sinz = 0; + + rh = Math.sqrt(x * x + y * y); + phi = rh * 0.5; + if (phi > 1) { + return null; + } + phi = 2 * Math.asin(phi); + if (this.mode === this.OBLIQ || this.mode === this.EQUIT) { + sinz = Math.sin(phi); + cosz = Math.cos(phi); + } + switch (this.mode) { + case this.EQUIT: + phi = (Math.abs(rh) <= EPSLN) ? 0 : Math.asin(y * sinz / rh); + x *= sinz; + y = cosz * rh; + break; + case this.OBLIQ: + phi = (Math.abs(rh) <= EPSLN) ? this.lat0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh); + x *= sinz * this.cosph0; + y = (cosz - Math.sin(phi) * this.sinph0) * rh; + break; + case this.N_POLE: + y = -y; + phi = HALF_PI - phi; + break; + case this.S_POLE: + phi -= HALF_PI; + break; + } + lam = (y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ)) ? 0 : Math.atan2(x, y); + } + else { + ab = 0; + if (this.mode === this.OBLIQ || this.mode === this.EQUIT) { + x /= this.dd; + y *= this.dd; + rho = Math.sqrt(x * x + y * y); + if (rho < EPSLN) { + p.x = this.long0; + p.y = this.lat0; + return p; + } + sCe = 2 * Math.asin(0.5 * rho / this.rq); + cCe = Math.cos(sCe); + x *= (sCe = Math.sin(sCe)); + if (this.mode === this.OBLIQ) { + ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho; + q = this.qp * ab; + y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe; + } + else { + ab = y * sCe / rho; + q = this.qp * ab; + y = rho * cCe; + } + } + else if (this.mode === this.N_POLE || this.mode === this.S_POLE) { + if (this.mode === this.N_POLE) { + y = -y; + } + q = (x * x + y * y); + if (!q) { + p.x = this.long0; + p.y = this.lat0; + return p; + } + ab = 1 - q / this.qp; + if (this.mode === this.S_POLE) { + ab = -ab; + } + } + lam = Math.atan2(x, y); + phi = authlat(Math.asin(ab), this.apa); + } + + p.x = adjust_lon(this.long0 + lam); + p.y = phi; + return p; +} + +/* determine latitude from authalic latitude */ +var P00 = 0.33333333333333333333; + +var P01 = 0.17222222222222222222; +var P02 = 0.10257936507936507936; +var P10 = 0.06388888888888888888; +var P11 = 0.06640211640211640211; +var P20 = 0.01641501294219154443; + +function authset(es) { + var t; + var APA = []; + APA[0] = es * P00; + t = es * es; + APA[0] += t * P01; + APA[1] = t * P10; + t *= es; + APA[0] += t * P02; + APA[1] += t * P11; + APA[2] = t * P20; + return APA; +} + +function authlat(beta, APA) { + var t = beta + beta; + return (beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t)); +} + +var names$i = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"]; +var laea = { + init: init$i, + forward: forward$i, + inverse: inverse$i, + names: names$i, + S_POLE: S_POLE, + N_POLE: N_POLE, + EQUIT: EQUIT, + OBLIQ: OBLIQ +}; + +function asinz(x) { + if (Math.abs(x) > 1) { + x = (x > 1) ? 1 : -1; + } + return Math.asin(x); +} + +function init$h() { + + if (Math.abs(this.lat1 + this.lat2) < EPSLN) { + return; + } + this.temp = this.b / this.a; + this.es = 1 - Math.pow(this.temp, 2); + this.e3 = Math.sqrt(this.es); + + this.sin_po = Math.sin(this.lat1); + this.cos_po = Math.cos(this.lat1); + this.t1 = this.sin_po; + this.con = this.sin_po; + this.ms1 = msfnz(this.e3, this.sin_po, this.cos_po); + this.qs1 = qsfnz(this.e3, this.sin_po); + + this.sin_po = Math.sin(this.lat2); + this.cos_po = Math.cos(this.lat2); + this.t2 = this.sin_po; + this.ms2 = msfnz(this.e3, this.sin_po, this.cos_po); + this.qs2 = qsfnz(this.e3, this.sin_po); + + this.sin_po = Math.sin(this.lat0); + this.cos_po = Math.cos(this.lat0); + this.t3 = this.sin_po; + this.qs0 = qsfnz(this.e3, this.sin_po); + + if (Math.abs(this.lat1 - this.lat2) > EPSLN) { + this.ns0 = (this.ms1 * this.ms1 - this.ms2 * this.ms2) / (this.qs2 - this.qs1); + } + else { + this.ns0 = this.con; + } + this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1; + this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0) / this.ns0; +} + +/* Albers Conical Equal Area forward equations--mapping lat,long to x,y + -------------------------------------------------------------------*/ +function forward$h(p) { + + var lon = p.x; + var lat = p.y; + + this.sin_phi = Math.sin(lat); + this.cos_phi = Math.cos(lat); + + var qs = qsfnz(this.e3, this.sin_phi); + var rh1 = this.a * Math.sqrt(this.c - this.ns0 * qs) / this.ns0; + var theta = this.ns0 * adjust_lon(lon - this.long0); + var x = rh1 * Math.sin(theta) + this.x0; + var y = this.rh - rh1 * Math.cos(theta) + this.y0; + + p.x = x; + p.y = y; + return p; +} + +function inverse$h(p) { + var rh1, qs, con, theta, lon, lat; + + p.x -= this.x0; + p.y = this.rh - p.y + this.y0; + if (this.ns0 >= 0) { + rh1 = Math.sqrt(p.x * p.x + p.y * p.y); + con = 1; + } + else { + rh1 = -Math.sqrt(p.x * p.x + p.y * p.y); + con = -1; + } + theta = 0; + if (rh1 !== 0) { + theta = Math.atan2(con * p.x, con * p.y); + } + con = rh1 * this.ns0 / this.a; + if (this.sphere) { + lat = Math.asin((this.c - con * con) / (2 * this.ns0)); + } + else { + qs = (this.c - con * con) / this.ns0; + lat = this.phi1z(this.e3, qs); + } + + lon = adjust_lon(theta / this.ns0 + this.long0); + p.x = lon; + p.y = lat; + return p; +} + +/* Function to compute phi1, the latitude for the inverse of the + Albers Conical Equal-Area projection. +-------------------------------------------*/ +function phi1z(eccent, qs) { + var sinphi, cosphi, con, com, dphi; + var phi = asinz(0.5 * qs); + if (eccent < EPSLN) { + return phi; + } + + var eccnts = eccent * eccent; + for (var i = 1; i <= 25; i++) { + sinphi = Math.sin(phi); + cosphi = Math.cos(phi); + con = eccent * sinphi; + com = 1 - con * con; + dphi = 0.5 * com * com / cosphi * (qs / (1 - eccnts) - sinphi / com + 0.5 / eccent * Math.log((1 - con) / (1 + con))); + phi = phi + dphi; + if (Math.abs(dphi) <= 1e-7) { + return phi; + } + } + return null; +} + +var names$h = ["Albers_Conic_Equal_Area", "Albers", "aea"]; +var aea = { + init: init$h, + forward: forward$h, + inverse: inverse$h, + names: names$h, + phi1z: phi1z +}; + +/* + reference: + Wolfram Mathworld "Gnomonic Projection" + http://mathworld.wolfram.com/GnomonicProjection.html + Accessed: 12th November 2009 + */ +function init$g() { + + /* Place parameters in static storage for common use + -------------------------------------------------*/ + this.sin_p14 = Math.sin(this.lat0); + this.cos_p14 = Math.cos(this.lat0); + // Approximation for projecting points to the horizon (infinity) + this.infinity_dist = 1000 * this.a; + this.rc = 1; +} + +/* Gnomonic forward equations--mapping lat,long to x,y + ---------------------------------------------------*/ +function forward$g(p) { + var sinphi, cosphi; /* sin and cos value */ + var dlon; /* delta longitude value */ + var coslon; /* cos of longitude */ + var ksp; /* scale factor */ + var g; + var x, y; + var lon = p.x; + var lat = p.y; + /* Forward equations + -----------------*/ + dlon = adjust_lon(lon - this.long0); + + sinphi = Math.sin(lat); + cosphi = Math.cos(lat); + + coslon = Math.cos(dlon); + g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon; + ksp = 1; + if ((g > 0) || (Math.abs(g) <= EPSLN)) { + x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g; + y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g; + } + else { + + // Point is in the opposing hemisphere and is unprojectable + // We still need to return a reasonable point, so we project + // to infinity, on a bearing + // equivalent to the northern hemisphere equivalent + // This is a reasonable approximation for short shapes and lines that + // straddle the horizon. + + x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon); + y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon); + + } + p.x = x; + p.y = y; + return p; +} + +function inverse$g(p) { + var rh; /* Rho */ + var sinc, cosc; + var c; + var lon, lat; + + /* Inverse equations + -----------------*/ + p.x = (p.x - this.x0) / this.a; + p.y = (p.y - this.y0) / this.a; + + p.x /= this.k0; + p.y /= this.k0; + + if ((rh = Math.sqrt(p.x * p.x + p.y * p.y))) { + c = Math.atan2(rh, this.rc); + sinc = Math.sin(c); + cosc = Math.cos(c); + + lat = asinz(cosc * this.sin_p14 + (p.y * sinc * this.cos_p14) / rh); + lon = Math.atan2(p.x * sinc, rh * this.cos_p14 * cosc - p.y * this.sin_p14 * sinc); + lon = adjust_lon(this.long0 + lon); + } + else { + lat = this.phic0; + lon = 0; + } + + p.x = lon; + p.y = lat; + return p; +} + +var names$g = ["gnom"]; +var gnom = { + init: init$g, + forward: forward$g, + inverse: inverse$g, + names: names$g +}; + +function iqsfnz(eccent, q) { + var temp = 1 - (1 - eccent * eccent) / (2 * eccent) * Math.log((1 - eccent) / (1 + eccent)); + if (Math.abs(Math.abs(q) - temp) < 1.0E-6) { + if (q < 0) { + return (-1 * HALF_PI); + } + else { + return HALF_PI; + } + } + //var phi = 0.5* q/(1-eccent*eccent); + var phi = Math.asin(0.5 * q); + var dphi; + var sin_phi; + var cos_phi; + var con; + for (var i = 0; i < 30; i++) { + sin_phi = Math.sin(phi); + cos_phi = Math.cos(phi); + con = eccent * sin_phi; + dphi = Math.pow(1 - con * con, 2) / (2 * cos_phi) * (q / (1 - eccent * eccent) - sin_phi / (1 - con * con) + 0.5 / eccent * Math.log((1 - con) / (1 + con))); + phi += dphi; + if (Math.abs(dphi) <= 0.0000000001) { + return phi; + } + } + + //console.log("IQSFN-CONV:Latitude failed to converge after 30 iterations"); + return NaN; +} + +/* + reference: + "Cartographic Projection Procedures for the UNIX Environment- + A User's Manual" by Gerald I. Evenden, + USGS Open File Report 90-284and Release 4 Interim Reports (2003) +*/ +function init$f() { + //no-op + if (!this.sphere) { + this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)); + } +} + +/* Cylindrical Equal Area forward equations--mapping lat,long to x,y + ------------------------------------------------------------*/ +function forward$f(p) { + var lon = p.x; + var lat = p.y; + var x, y; + /* Forward equations + -----------------*/ + var dlon = adjust_lon(lon - this.long0); + if (this.sphere) { + x = this.x0 + this.a * dlon * Math.cos(this.lat_ts); + y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts); + } + else { + var qs = qsfnz(this.e, Math.sin(lat)); + x = this.x0 + this.a * this.k0 * dlon; + y = this.y0 + this.a * qs * 0.5 / this.k0; + } + + p.x = x; + p.y = y; + return p; +} + +/* Cylindrical Equal Area inverse equations--mapping x,y to lat/long + ------------------------------------------------------------*/ +function inverse$f(p) { + p.x -= this.x0; + p.y -= this.y0; + var lon, lat; + + if (this.sphere) { + lon = adjust_lon(this.long0 + (p.x / this.a) / Math.cos(this.lat_ts)); + lat = Math.asin((p.y / this.a) * Math.cos(this.lat_ts)); + } + else { + lat = iqsfnz(this.e, 2 * p.y * this.k0 / this.a); + lon = adjust_lon(this.long0 + p.x / (this.a * this.k0)); + } + + p.x = lon; + p.y = lat; + return p; +} + +var names$f = ["cea"]; +var cea = { + init: init$f, + forward: forward$f, + inverse: inverse$f, + names: names$f +}; + +function init$e() { + + this.x0 = this.x0 || 0; + this.y0 = this.y0 || 0; + this.lat0 = this.lat0 || 0; + this.long0 = this.long0 || 0; + this.lat_ts = this.lat_ts || 0; + this.title = this.title || "Equidistant Cylindrical (Plate Carre)"; + + this.rc = Math.cos(this.lat_ts); +} + +// forward equations--mapping lat,long to x,y +// ----------------------------------------------------------------- +function forward$e(p) { + + var lon = p.x; + var lat = p.y; + + var dlon = adjust_lon(lon - this.long0); + var dlat = adjust_lat(lat - this.lat0); + p.x = this.x0 + (this.a * dlon * this.rc); + p.y = this.y0 + (this.a * dlat); + return p; +} + +// inverse equations--mapping x,y to lat/long +// ----------------------------------------------------------------- +function inverse$e(p) { + + var x = p.x; + var y = p.y; + + p.x = adjust_lon(this.long0 + ((x - this.x0) / (this.a * this.rc))); + p.y = adjust_lat(this.lat0 + ((y - this.y0) / (this.a))); + return p; +} + +var names$e = ["Equirectangular", "Equidistant_Cylindrical", "eqc"]; +var eqc = { + init: init$e, + forward: forward$e, + inverse: inverse$e, + names: names$e +}; + +var MAX_ITER$1 = 20; + +function init$d() { + /* Place parameters in static storage for common use + -------------------------------------------------*/ + this.temp = this.b / this.a; + this.es = 1 - Math.pow(this.temp, 2); // devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles + this.e = Math.sqrt(this.es); + this.e0 = e0fn(this.es); + this.e1 = e1fn(this.es); + this.e2 = e2fn(this.es); + this.e3 = e3fn(this.es); + this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); //si que des zeros le calcul ne se fait pas +} + +/* Polyconic forward equations--mapping lat,long to x,y + ---------------------------------------------------*/ +function forward$d(p) { + var lon = p.x; + var lat = p.y; + var x, y, el; + var dlon = adjust_lon(lon - this.long0); + el = dlon * Math.sin(lat); + if (this.sphere) { + if (Math.abs(lat) <= EPSLN) { + x = this.a * dlon; + y = -1 * this.a * this.lat0; + } + else { + x = this.a * Math.sin(el) / Math.tan(lat); + y = this.a * (adjust_lat(lat - this.lat0) + (1 - Math.cos(el)) / Math.tan(lat)); + } + } + else { + if (Math.abs(lat) <= EPSLN) { + x = this.a * dlon; + y = -1 * this.ml0; + } + else { + var nl = gN(this.a, this.e, Math.sin(lat)) / Math.tan(lat); + x = nl * Math.sin(el); + y = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, lat) - this.ml0 + nl * (1 - Math.cos(el)); + } + + } + p.x = x + this.x0; + p.y = y + this.y0; + return p; +} + +/* Inverse equations + -----------------*/ +function inverse$d(p) { + var lon, lat, x, y, i; + var al, bl; + var phi, dphi; + x = p.x - this.x0; + y = p.y - this.y0; + + if (this.sphere) { + if (Math.abs(y + this.a * this.lat0) <= EPSLN) { + lon = adjust_lon(x / this.a + this.long0); + lat = 0; + } + else { + al = this.lat0 + y / this.a; + bl = x * x / this.a / this.a + al * al; + phi = al; + var tanphi; + for (i = MAX_ITER$1; i; --i) { + tanphi = Math.tan(phi); + dphi = -1 * (al * (phi * tanphi + 1) - phi - 0.5 * (phi * phi + bl) * tanphi) / ((phi - al) / tanphi - 1); + phi += dphi; + if (Math.abs(dphi) <= EPSLN) { + lat = phi; + break; + } + } + lon = adjust_lon(this.long0 + (Math.asin(x * Math.tan(phi) / this.a)) / Math.sin(lat)); + } + } + else { + if (Math.abs(y + this.ml0) <= EPSLN) { + lat = 0; + lon = adjust_lon(this.long0 + x / this.a); + } + else { + + al = (this.ml0 + y) / this.a; + bl = x * x / this.a / this.a + al * al; + phi = al; + var cl, mln, mlnp, ma; + var con; + for (i = MAX_ITER$1; i; --i) { + con = this.e * Math.sin(phi); + cl = Math.sqrt(1 - con * con) * Math.tan(phi); + mln = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi); + mlnp = this.e0 - 2 * this.e1 * Math.cos(2 * phi) + 4 * this.e2 * Math.cos(4 * phi) - 6 * this.e3 * Math.cos(6 * phi); + ma = mln / this.a; + dphi = (al * (cl * ma + 1) - ma - 0.5 * cl * (ma * ma + bl)) / (this.es * Math.sin(2 * phi) * (ma * ma + bl - 2 * al * ma) / (4 * cl) + (al - ma) * (cl * mlnp - 2 / Math.sin(2 * phi)) - mlnp); + phi -= dphi; + if (Math.abs(dphi) <= EPSLN) { + lat = phi; + break; + } + } + + //lat=phi4z(this.e,this.e0,this.e1,this.e2,this.e3,al,bl,0,0); + cl = Math.sqrt(1 - this.es * Math.pow(Math.sin(lat), 2)) * Math.tan(lat); + lon = adjust_lon(this.long0 + Math.asin(x * cl / this.a) / Math.sin(lat)); + } + } + + p.x = lon; + p.y = lat; + return p; +} + +var names$d = ["Polyconic", "poly"]; +var poly = { + init: init$d, + forward: forward$d, + inverse: inverse$d, + names: names$d +}; + +function init$c() { + this.A = []; + this.A[1] = 0.6399175073; + this.A[2] = -0.1358797613; + this.A[3] = 0.063294409; + this.A[4] = -0.02526853; + this.A[5] = 0.0117879; + this.A[6] = -0.0055161; + this.A[7] = 0.0026906; + this.A[8] = -0.001333; + this.A[9] = 0.00067; + this.A[10] = -0.00034; + + this.B_re = []; + this.B_im = []; + this.B_re[1] = 0.7557853228; + this.B_im[1] = 0; + this.B_re[2] = 0.249204646; + this.B_im[2] = 0.003371507; + this.B_re[3] = -0.001541739; + this.B_im[3] = 0.041058560; + this.B_re[4] = -0.10162907; + this.B_im[4] = 0.01727609; + this.B_re[5] = -0.26623489; + this.B_im[5] = -0.36249218; + this.B_re[6] = -0.6870983; + this.B_im[6] = -1.1651967; + + this.C_re = []; + this.C_im = []; + this.C_re[1] = 1.3231270439; + this.C_im[1] = 0; + this.C_re[2] = -0.577245789; + this.C_im[2] = -0.007809598; + this.C_re[3] = 0.508307513; + this.C_im[3] = -0.112208952; + this.C_re[4] = -0.15094762; + this.C_im[4] = 0.18200602; + this.C_re[5] = 1.01418179; + this.C_im[5] = 1.64497696; + this.C_re[6] = 1.9660549; + this.C_im[6] = 2.5127645; + + this.D = []; + this.D[1] = 1.5627014243; + this.D[2] = 0.5185406398; + this.D[3] = -0.03333098; + this.D[4] = -0.1052906; + this.D[5] = -0.0368594; + this.D[6] = 0.007317; + this.D[7] = 0.01220; + this.D[8] = 0.00394; + this.D[9] = -0.0013; +} + +/** + New Zealand Map Grid Forward - long/lat to x/y + long/lat in radians + */ +function forward$c(p) { + var n; + var lon = p.x; + var lat = p.y; + + var delta_lat = lat - this.lat0; + var delta_lon = lon - this.long0; + + // 1. Calculate d_phi and d_psi ... // and d_lambda + // For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians. + var d_phi = delta_lat / SEC_TO_RAD * 1E-5; + var d_lambda = delta_lon; + var d_phi_n = 1; // d_phi^0 + + var d_psi = 0; + for (n = 1; n <= 10; n++) { + d_phi_n = d_phi_n * d_phi; + d_psi = d_psi + this.A[n] * d_phi_n; + } + + // 2. Calculate theta + var th_re = d_psi; + var th_im = d_lambda; + + // 3. Calculate z + var th_n_re = 1; + var th_n_im = 0; // theta^0 + var th_n_re1; + var th_n_im1; + + var z_re = 0; + var z_im = 0; + for (n = 1; n <= 6; n++) { + th_n_re1 = th_n_re * th_re - th_n_im * th_im; + th_n_im1 = th_n_im * th_re + th_n_re * th_im; + th_n_re = th_n_re1; + th_n_im = th_n_im1; + z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im; + z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im; + } + + // 4. Calculate easting and northing + p.x = (z_im * this.a) + this.x0; + p.y = (z_re * this.a) + this.y0; + + return p; +} + +/** + New Zealand Map Grid Inverse - x/y to long/lat + */ +function inverse$c(p) { + var n; + var x = p.x; + var y = p.y; + + var delta_x = x - this.x0; + var delta_y = y - this.y0; + + // 1. Calculate z + var z_re = delta_y / this.a; + var z_im = delta_x / this.a; + + // 2a. Calculate theta - first approximation gives km accuracy + var z_n_re = 1; + var z_n_im = 0; // z^0 + var z_n_re1; + var z_n_im1; + + var th_re = 0; + var th_im = 0; + for (n = 1; n <= 6; n++) { + z_n_re1 = z_n_re * z_re - z_n_im * z_im; + z_n_im1 = z_n_im * z_re + z_n_re * z_im; + z_n_re = z_n_re1; + z_n_im = z_n_im1; + th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im; + th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im; + } + + // 2b. Iterate to refine the accuracy of the calculation + // 0 iterations gives km accuracy + // 1 iteration gives m accuracy -- good enough for most mapping applications + // 2 iterations bives mm accuracy + for (var i = 0; i < this.iterations; i++) { + var th_n_re = th_re; + var th_n_im = th_im; + var th_n_re1; + var th_n_im1; + + var num_re = z_re; + var num_im = z_im; + for (n = 2; n <= 6; n++) { + th_n_re1 = th_n_re * th_re - th_n_im * th_im; + th_n_im1 = th_n_im * th_re + th_n_re * th_im; + th_n_re = th_n_re1; + th_n_im = th_n_im1; + num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im); + num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im); + } + + th_n_re = 1; + th_n_im = 0; + var den_re = this.B_re[1]; + var den_im = this.B_im[1]; + for (n = 2; n <= 6; n++) { + th_n_re1 = th_n_re * th_re - th_n_im * th_im; + th_n_im1 = th_n_im * th_re + th_n_re * th_im; + th_n_re = th_n_re1; + th_n_im = th_n_im1; + den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im); + den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im); + } + + // Complex division + var den2 = den_re * den_re + den_im * den_im; + th_re = (num_re * den_re + num_im * den_im) / den2; + th_im = (num_im * den_re - num_re * den_im) / den2; + } + + // 3. Calculate d_phi ... // and d_lambda + var d_psi = th_re; + var d_lambda = th_im; + var d_psi_n = 1; // d_psi^0 + + var d_phi = 0; + for (n = 1; n <= 9; n++) { + d_psi_n = d_psi_n * d_psi; + d_phi = d_phi + this.D[n] * d_psi_n; + } + + // 4. Calculate latitude and longitude + // d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians. + var lat = this.lat0 + (d_phi * SEC_TO_RAD * 1E5); + var lon = this.long0 + d_lambda; + + p.x = lon; + p.y = lat; + + return p; +} + +var names$c = ["New_Zealand_Map_Grid", "nzmg"]; +var nzmg = { + init: init$c, + forward: forward$c, + inverse: inverse$c, + names: names$c +}; + +/* + reference + "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder, + The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355. + */ + + +/* Initialize the Miller Cylindrical projection + -------------------------------------------*/ +function init$b() { + //no-op +} + +/* Miller Cylindrical forward equations--mapping lat,long to x,y + ------------------------------------------------------------*/ +function forward$b(p) { + var lon = p.x; + var lat = p.y; + /* Forward equations + -----------------*/ + var dlon = adjust_lon(lon - this.long0); + var x = this.x0 + this.a * dlon; + var y = this.y0 + this.a * Math.log(Math.tan((Math.PI / 4) + (lat / 2.5))) * 1.25; + + p.x = x; + p.y = y; + return p; +} + +/* Miller Cylindrical inverse equations--mapping x,y to lat/long + ------------------------------------------------------------*/ +function inverse$b(p) { + p.x -= this.x0; + p.y -= this.y0; + + var lon = adjust_lon(this.long0 + p.x / this.a); + var lat = 2.5 * (Math.atan(Math.exp(0.8 * p.y / this.a)) - Math.PI / 4); + + p.x = lon; + p.y = lat; + return p; +} + +var names$b = ["Miller_Cylindrical", "mill"]; +var mill = { + init: init$b, + forward: forward$b, + inverse: inverse$b, + names: names$b +}; + +var MAX_ITER = 20; + + +function init$a() { + /* Place parameters in static storage for common use + -------------------------------------------------*/ + + + if (!this.sphere) { + this.en = pj_enfn(this.es); + } + else { + this.n = 1; + this.m = 0; + this.es = 0; + this.C_y = Math.sqrt((this.m + 1) / this.n); + this.C_x = this.C_y / (this.m + 1); + } + +} + +/* Sinusoidal forward equations--mapping lat,long to x,y + -----------------------------------------------------*/ +function forward$a(p) { + var x, y; + var lon = p.x; + var lat = p.y; + /* Forward equations + -----------------*/ + lon = adjust_lon(lon - this.long0); + + if (this.sphere) { + if (!this.m) { + lat = this.n !== 1 ? Math.asin(this.n * Math.sin(lat)) : lat; + } + else { + var k = this.n * Math.sin(lat); + for (var i = MAX_ITER; i; --i) { + var V = (this.m * lat + Math.sin(lat) - k) / (this.m + Math.cos(lat)); + lat -= V; + if (Math.abs(V) < EPSLN) { + break; + } + } + } + x = this.a * this.C_x * lon * (this.m + Math.cos(lat)); + y = this.a * this.C_y * lat; + + } + else { + + var s = Math.sin(lat); + var c = Math.cos(lat); + y = this.a * pj_mlfn(lat, s, c, this.en); + x = this.a * lon * c / Math.sqrt(1 - this.es * s * s); + } + + p.x = x; + p.y = y; + return p; +} + +function inverse$a(p) { + var lat, temp, lon, s; + + p.x -= this.x0; + lon = p.x / this.a; + p.y -= this.y0; + lat = p.y / this.a; + + if (this.sphere) { + lat /= this.C_y; + lon = lon / (this.C_x * (this.m + Math.cos(lat))); + if (this.m) { + lat = asinz((this.m * lat + Math.sin(lat)) / this.n); + } + else if (this.n !== 1) { + lat = asinz(Math.sin(lat) / this.n); + } + lon = adjust_lon(lon + this.long0); + lat = adjust_lat(lat); + } + else { + lat = pj_inv_mlfn(p.y / this.a, this.es, this.en); + s = Math.abs(lat); + if (s < HALF_PI) { + s = Math.sin(lat); + temp = this.long0 + p.x * Math.sqrt(1 - this.es * s * s) / (this.a * Math.cos(lat)); + //temp = this.long0 + p.x / (this.a * Math.cos(lat)); + lon = adjust_lon(temp); + } + else if ((s - EPSLN) < HALF_PI) { + lon = this.long0; + } + } + p.x = lon; + p.y = lat; + return p; +} + +var names$a = ["Sinusoidal", "sinu"]; +var sinu = { + init: init$a, + forward: forward$a, + inverse: inverse$a, + names: names$a +}; + +function init$9() {} +/* Mollweide forward equations--mapping lat,long to x,y + ----------------------------------------------------*/ +function forward$9(p) { + + /* Forward equations + -----------------*/ + var lon = p.x; + var lat = p.y; + + var delta_lon = adjust_lon(lon - this.long0); + var theta = lat; + var con = Math.PI * Math.sin(lat); + + /* Iterate using the Newton-Raphson method to find theta + -----------------------------------------------------*/ + while (true) { + var delta_theta = -(theta + Math.sin(theta) - con) / (1 + Math.cos(theta)); + theta += delta_theta; + if (Math.abs(delta_theta) < EPSLN) { + break; + } + } + theta /= 2; + + /* If the latitude is 90 deg, force the x coordinate to be "0 + false easting" + this is done here because of precision problems with "cos(theta)" + --------------------------------------------------------------------------*/ + if (Math.PI / 2 - Math.abs(lat) < EPSLN) { + delta_lon = 0; + } + var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0; + var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0; + + p.x = x; + p.y = y; + return p; +} + +function inverse$9(p) { + var theta; + var arg; + + /* Inverse equations + -----------------*/ + p.x -= this.x0; + p.y -= this.y0; + arg = p.y / (1.4142135623731 * this.a); + + /* Because of division by zero problems, 'arg' can not be 1. Therefore + a number very close to one is used instead. + -------------------------------------------------------------------*/ + if (Math.abs(arg) > 0.999999999999) { + arg = 0.999999999999; + } + theta = Math.asin(arg); + var lon = adjust_lon(this.long0 + (p.x / (0.900316316158 * this.a * Math.cos(theta)))); + if (lon < (-Math.PI)) { + lon = -Math.PI; + } + if (lon > Math.PI) { + lon = Math.PI; + } + arg = (2 * theta + Math.sin(2 * theta)) / Math.PI; + if (Math.abs(arg) > 1) { + arg = 1; + } + var lat = Math.asin(arg); + + p.x = lon; + p.y = lat; + return p; +} + +var names$9 = ["Mollweide", "moll"]; +var moll = { + init: init$9, + forward: forward$9, + inverse: inverse$9, + names: names$9 +}; + +function init$8() { + + /* Place parameters in static storage for common use + -------------------------------------------------*/ + // Standard Parallels cannot be equal and on opposite sides of the equator + if (Math.abs(this.lat1 + this.lat2) < EPSLN) { + return; + } + this.lat2 = this.lat2 || this.lat1; + this.temp = this.b / this.a; + this.es = 1 - Math.pow(this.temp, 2); + this.e = Math.sqrt(this.es); + this.e0 = e0fn(this.es); + this.e1 = e1fn(this.es); + this.e2 = e2fn(this.es); + this.e3 = e3fn(this.es); + + this.sinphi = Math.sin(this.lat1); + this.cosphi = Math.cos(this.lat1); + + this.ms1 = msfnz(this.e, this.sinphi, this.cosphi); + this.ml1 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat1); + + if (Math.abs(this.lat1 - this.lat2) < EPSLN) { + this.ns = this.sinphi; + } + else { + this.sinphi = Math.sin(this.lat2); + this.cosphi = Math.cos(this.lat2); + this.ms2 = msfnz(this.e, this.sinphi, this.cosphi); + this.ml2 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2); + this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1); + } + this.g = this.ml1 + this.ms1 / this.ns; + this.ml0 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); + this.rh = this.a * (this.g - this.ml0); +} + +/* Equidistant Conic forward equations--mapping lat,long to x,y + -----------------------------------------------------------*/ +function forward$8(p) { + var lon = p.x; + var lat = p.y; + var rh1; + + /* Forward equations + -----------------*/ + if (this.sphere) { + rh1 = this.a * (this.g - lat); + } + else { + var ml = mlfn(this.e0, this.e1, this.e2, this.e3, lat); + rh1 = this.a * (this.g - ml); + } + var theta = this.ns * adjust_lon(lon - this.long0); + var x = this.x0 + rh1 * Math.sin(theta); + var y = this.y0 + this.rh - rh1 * Math.cos(theta); + p.x = x; + p.y = y; + return p; +} + +/* Inverse equations + -----------------*/ +function inverse$8(p) { + p.x -= this.x0; + p.y = this.rh - p.y + this.y0; + var con, rh1, lat, lon; + if (this.ns >= 0) { + rh1 = Math.sqrt(p.x * p.x + p.y * p.y); + con = 1; + } + else { + rh1 = -Math.sqrt(p.x * p.x + p.y * p.y); + con = -1; + } + var theta = 0; + if (rh1 !== 0) { + theta = Math.atan2(con * p.x, con * p.y); + } + + if (this.sphere) { + lon = adjust_lon(this.long0 + theta / this.ns); + lat = adjust_lat(this.g - rh1 / this.a); + p.x = lon; + p.y = lat; + return p; + } + else { + var ml = this.g - rh1 / this.a; + lat = imlfn(ml, this.e0, this.e1, this.e2, this.e3); + lon = adjust_lon(this.long0 + theta / this.ns); + p.x = lon; + p.y = lat; + return p; + } + +} + +var names$8 = ["Equidistant_Conic", "eqdc"]; +var eqdc = { + init: init$8, + forward: forward$8, + inverse: inverse$8, + names: names$8 +}; + +/* Initialize the Van Der Grinten projection + ----------------------------------------*/ +function init$7() { + //this.R = 6370997; //Radius of earth + this.R = this.a; +} + +function forward$7(p) { + + var lon = p.x; + var lat = p.y; + + /* Forward equations + -----------------*/ + var dlon = adjust_lon(lon - this.long0); + var x, y; + + if (Math.abs(lat) <= EPSLN) { + x = this.x0 + this.R * dlon; + y = this.y0; + } + var theta = asinz(2 * Math.abs(lat / Math.PI)); + if ((Math.abs(dlon) <= EPSLN) || (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN)) { + x = this.x0; + if (lat >= 0) { + y = this.y0 + Math.PI * this.R * Math.tan(0.5 * theta); + } + else { + y = this.y0 + Math.PI * this.R * -Math.tan(0.5 * theta); + } + // return(OK); + } + var al = 0.5 * Math.abs((Math.PI / dlon) - (dlon / Math.PI)); + var asq = al * al; + var sinth = Math.sin(theta); + var costh = Math.cos(theta); + + var g = costh / (sinth + costh - 1); + var gsq = g * g; + var m = g * (2 / sinth - 1); + var msq = m * m; + var con = Math.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq); + if (dlon < 0) { + con = -con; + } + x = this.x0 + con; + //con = Math.abs(con / (Math.PI * this.R)); + var q = asq + g; + con = Math.PI * this.R * (m * q - al * Math.sqrt((msq + asq) * (asq + 1) - q * q)) / (msq + asq); + if (lat >= 0) { + //y = this.y0 + Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con); + y = this.y0 + con; + } + else { + //y = this.y0 - Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con); + y = this.y0 - con; + } + p.x = x; + p.y = y; + return p; +} + +/* Van Der Grinten inverse equations--mapping x,y to lat/long + ---------------------------------------------------------*/ +function inverse$7(p) { + var lon, lat; + var xx, yy, xys, c1, c2, c3; + var a1; + var m1; + var con; + var th1; + var d; + + /* inverse equations + -----------------*/ + p.x -= this.x0; + p.y -= this.y0; + con = Math.PI * this.R; + xx = p.x / con; + yy = p.y / con; + xys = xx * xx + yy * yy; + c1 = -Math.abs(yy) * (1 + xys); + c2 = c1 - 2 * yy * yy + xx * xx; + c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys; + d = yy * yy / c3 + (2 * c2 * c2 * c2 / c3 / c3 / c3 - 9 * c1 * c2 / c3 / c3) / 27; + a1 = (c1 - c2 * c2 / 3 / c3) / c3; + m1 = 2 * Math.sqrt(-a1 / 3); + con = ((3 * d) / a1) / m1; + if (Math.abs(con) > 1) { + if (con >= 0) { + con = 1; + } + else { + con = -1; + } + } + th1 = Math.acos(con) / 3; + if (p.y >= 0) { + lat = (-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI; + } + else { + lat = -(-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI; + } + + if (Math.abs(xx) < EPSLN) { + lon = this.long0; + } + else { + lon = adjust_lon(this.long0 + Math.PI * (xys - 1 + Math.sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys)) / 2 / xx); + } + + p.x = lon; + p.y = lat; + return p; +} + +var names$7 = ["Van_der_Grinten_I", "VanDerGrinten", "vandg"]; +var vandg = { + init: init$7, + forward: forward$7, + inverse: inverse$7, + names: names$7 +}; + +function init$6() { + this.sin_p12 = Math.sin(this.lat0); + this.cos_p12 = Math.cos(this.lat0); +} + +function forward$6(p) { + var lon = p.x; + var lat = p.y; + var sinphi = Math.sin(p.y); + var cosphi = Math.cos(p.y); + var dlon = adjust_lon(lon - this.long0); + var e0, e1, e2, e3, Mlp, Ml, tanphi, Nl1, Nl, psi, Az, G, H, GH, Hs, c, kp, cos_c, s, s2, s3, s4, s5; + if (this.sphere) { + if (Math.abs(this.sin_p12 - 1) <= EPSLN) { + //North Pole case + p.x = this.x0 + this.a * (HALF_PI - lat) * Math.sin(dlon); + p.y = this.y0 - this.a * (HALF_PI - lat) * Math.cos(dlon); + return p; + } + else if (Math.abs(this.sin_p12 + 1) <= EPSLN) { + //South Pole case + p.x = this.x0 + this.a * (HALF_PI + lat) * Math.sin(dlon); + p.y = this.y0 + this.a * (HALF_PI + lat) * Math.cos(dlon); + return p; + } + else { + //default case + cos_c = this.sin_p12 * sinphi + this.cos_p12 * cosphi * Math.cos(dlon); + c = Math.acos(cos_c); + kp = c ? c / Math.sin(c) : 1; + p.x = this.x0 + this.a * kp * cosphi * Math.sin(dlon); + p.y = this.y0 + this.a * kp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * Math.cos(dlon)); + return p; + } + } + else { + e0 = e0fn(this.es); + e1 = e1fn(this.es); + e2 = e2fn(this.es); + e3 = e3fn(this.es); + if (Math.abs(this.sin_p12 - 1) <= EPSLN) { + //North Pole case + Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI); + Ml = this.a * mlfn(e0, e1, e2, e3, lat); + p.x = this.x0 + (Mlp - Ml) * Math.sin(dlon); + p.y = this.y0 - (Mlp - Ml) * Math.cos(dlon); + return p; + } + else if (Math.abs(this.sin_p12 + 1) <= EPSLN) { + //South Pole case + Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI); + Ml = this.a * mlfn(e0, e1, e2, e3, lat); + p.x = this.x0 + (Mlp + Ml) * Math.sin(dlon); + p.y = this.y0 + (Mlp + Ml) * Math.cos(dlon); + return p; + } + else { + //Default case + tanphi = sinphi / cosphi; + Nl1 = gN(this.a, this.e, this.sin_p12); + Nl = gN(this.a, this.e, sinphi); + psi = Math.atan((1 - this.es) * tanphi + this.es * Nl1 * this.sin_p12 / (Nl * cosphi)); + Az = Math.atan2(Math.sin(dlon), this.cos_p12 * Math.tan(psi) - this.sin_p12 * Math.cos(dlon)); + if (Az === 0) { + s = Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi)); + } + else if (Math.abs(Math.abs(Az) - Math.PI) <= EPSLN) { + s = -Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi)); + } + else { + s = Math.asin(Math.sin(dlon) * Math.cos(psi) / Math.sin(Az)); + } + G = this.e * this.sin_p12 / Math.sqrt(1 - this.es); + H = this.e * this.cos_p12 * Math.cos(Az) / Math.sqrt(1 - this.es); + GH = G * H; + Hs = H * H; + s2 = s * s; + s3 = s2 * s; + s4 = s3 * s; + s5 = s4 * s; + c = Nl1 * s * (1 - s2 * Hs * (1 - Hs) / 6 + s3 / 8 * GH * (1 - 2 * Hs) + s4 / 120 * (Hs * (4 - 7 * Hs) - 3 * G * G * (1 - 7 * Hs)) - s5 / 48 * GH); + p.x = this.x0 + c * Math.sin(Az); + p.y = this.y0 + c * Math.cos(Az); + return p; + } + } + + +} + +function inverse$6(p) { + p.x -= this.x0; + p.y -= this.y0; + var rh, z, sinz, cosz, lon, lat, con, e0, e1, e2, e3, Mlp, M, N1, psi, Az, cosAz, tmp, A, B, D, Ee, F, sinpsi; + if (this.sphere) { + rh = Math.sqrt(p.x * p.x + p.y * p.y); + if (rh > (2 * HALF_PI * this.a)) { + return; + } + z = rh / this.a; + + sinz = Math.sin(z); + cosz = Math.cos(z); + + lon = this.long0; + if (Math.abs(rh) <= EPSLN) { + lat = this.lat0; + } + else { + lat = asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh); + con = Math.abs(this.lat0) - HALF_PI; + if (Math.abs(con) <= EPSLN) { + if (this.lat0 >= 0) { + lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y)); + } + else { + lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y)); + } + } + else { + /*con = cosz - this.sin_p12 * Math.sin(lat); + if ((Math.abs(con) < EPSLN) && (Math.abs(p.x) < EPSLN)) { + //no-op, just keep the lon value as is + } else { + var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh)); + lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh))); + }*/ + lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p12 * cosz - p.y * this.sin_p12 * sinz)); + } + } + + p.x = lon; + p.y = lat; + return p; + } + else { + e0 = e0fn(this.es); + e1 = e1fn(this.es); + e2 = e2fn(this.es); + e3 = e3fn(this.es); + if (Math.abs(this.sin_p12 - 1) <= EPSLN) { + //North pole case + Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI); + rh = Math.sqrt(p.x * p.x + p.y * p.y); + M = Mlp - rh; + lat = imlfn(M / this.a, e0, e1, e2, e3); + lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y)); + p.x = lon; + p.y = lat; + return p; + } + else if (Math.abs(this.sin_p12 + 1) <= EPSLN) { + //South pole case + Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI); + rh = Math.sqrt(p.x * p.x + p.y * p.y); + M = rh - Mlp; + + lat = imlfn(M / this.a, e0, e1, e2, e3); + lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y)); + p.x = lon; + p.y = lat; + return p; + } + else { + //default case + rh = Math.sqrt(p.x * p.x + p.y * p.y); + Az = Math.atan2(p.x, p.y); + N1 = gN(this.a, this.e, this.sin_p12); + cosAz = Math.cos(Az); + tmp = this.e * this.cos_p12 * cosAz; + A = -tmp * tmp / (1 - this.es); + B = 3 * this.es * (1 - A) * this.sin_p12 * this.cos_p12 * cosAz / (1 - this.es); + D = rh / N1; + Ee = D - A * (1 + A) * Math.pow(D, 3) / 6 - B * (1 + 3 * A) * Math.pow(D, 4) / 24; + F = 1 - A * Ee * Ee / 2 - D * Ee * Ee * Ee / 6; + psi = Math.asin(this.sin_p12 * Math.cos(Ee) + this.cos_p12 * Math.sin(Ee) * cosAz); + lon = adjust_lon(this.long0 + Math.asin(Math.sin(Az) * Math.sin(Ee) / Math.cos(psi))); + sinpsi = Math.sin(psi); + lat = Math.atan2((sinpsi - this.es * F * this.sin_p12) * Math.tan(psi), sinpsi * (1 - this.es)); + p.x = lon; + p.y = lat; + return p; + } + } + +} + +var names$6 = ["Azimuthal_Equidistant", "aeqd"]; +var aeqd = { + init: init$6, + forward: forward$6, + inverse: inverse$6, + names: names$6 +}; + +function init$5() { + //double temp; /* temporary variable */ + + /* Place parameters in static storage for common use + -------------------------------------------------*/ + this.sin_p14 = Math.sin(this.lat0); + this.cos_p14 = Math.cos(this.lat0); +} + +/* Orthographic forward equations--mapping lat,long to x,y + ---------------------------------------------------*/ +function forward$5(p) { + var sinphi, cosphi; /* sin and cos value */ + var dlon; /* delta longitude value */ + var coslon; /* cos of longitude */ + var ksp; /* scale factor */ + var g, x, y; + var lon = p.x; + var lat = p.y; + /* Forward equations + -----------------*/ + dlon = adjust_lon(lon - this.long0); + + sinphi = Math.sin(lat); + cosphi = Math.cos(lat); + + coslon = Math.cos(dlon); + g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon; + ksp = 1; + if ((g > 0) || (Math.abs(g) <= EPSLN)) { + x = this.a * ksp * cosphi * Math.sin(dlon); + y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon); + } + p.x = x; + p.y = y; + return p; +} + +function inverse$5(p) { + var rh; /* height above ellipsoid */ + var z; /* angle */ + var sinz, cosz; /* sin of z and cos of z */ + var con; + var lon, lat; + /* Inverse equations + -----------------*/ + p.x -= this.x0; + p.y -= this.y0; + rh = Math.sqrt(p.x * p.x + p.y * p.y); + z = asinz(rh / this.a); + + sinz = Math.sin(z); + cosz = Math.cos(z); + + lon = this.long0; + if (Math.abs(rh) <= EPSLN) { + lat = this.lat0; + p.x = lon; + p.y = lat; + return p; + } + lat = asinz(cosz * this.sin_p14 + (p.y * sinz * this.cos_p14) / rh); + con = Math.abs(this.lat0) - HALF_PI; + if (Math.abs(con) <= EPSLN) { + if (this.lat0 >= 0) { + lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y)); + } + else { + lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y)); + } + p.x = lon; + p.y = lat; + return p; + } + lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz), rh * this.cos_p14 * cosz - p.y * this.sin_p14 * sinz)); + p.x = lon; + p.y = lat; + return p; +} + +var names$5 = ["ortho"]; +var ortho = { + init: init$5, + forward: forward$5, + inverse: inverse$5, + names: names$5 +}; + +// QSC projection rewritten from the original PROJ4 +// https://github.com/OSGeo/proj.4/blob/master/src/PJ_qsc.c + + +/* constants */ +var FACE_ENUM = { + FRONT: 1, + RIGHT: 2, + BACK: 3, + LEFT: 4, + TOP: 5, + BOTTOM: 6 +}; + +var AREA_ENUM = { + AREA_0: 1, + AREA_1: 2, + AREA_2: 3, + AREA_3: 4 +}; + +function init$4() { + + this.x0 = this.x0 || 0; + this.y0 = this.y0 || 0; + this.lat0 = this.lat0 || 0; + this.long0 = this.long0 || 0; + this.lat_ts = this.lat_ts || 0; + this.title = this.title || "Quadrilateralized Spherical Cube"; + + /* Determine the cube face from the center of projection. */ + if (this.lat0 >= HALF_PI - FORTPI / 2.0) { + this.face = FACE_ENUM.TOP; + } else if (this.lat0 <= -(HALF_PI - FORTPI / 2.0)) { + this.face = FACE_ENUM.BOTTOM; + } else if (Math.abs(this.long0) <= FORTPI) { + this.face = FACE_ENUM.FRONT; + } else if (Math.abs(this.long0) <= HALF_PI + FORTPI) { + this.face = this.long0 > 0.0 ? FACE_ENUM.RIGHT : FACE_ENUM.LEFT; + } else { + this.face = FACE_ENUM.BACK; + } + + /* Fill in useful values for the ellipsoid <-> sphere shift + * described in [LK12]. */ + if (this.es !== 0) { + this.one_minus_f = 1 - (this.a - this.b) / this.a; + this.one_minus_f_squared = this.one_minus_f * this.one_minus_f; + } +} + +// QSC forward equations--mapping lat,long to x,y +// ----------------------------------------------------------------- +function forward$4(p) { + var xy = {x: 0, y: 0}; + var lat, lon; + var theta, phi; + var t, mu; + /* nu; */ + var area = {value: 0}; + + // move lon according to projection's lon + p.x -= this.long0; + + /* Convert the geodetic latitude to a geocentric latitude. + * This corresponds to the shift from the ellipsoid to the sphere + * described in [LK12]. */ + if (this.es !== 0) {//if (P->es != 0) { + lat = Math.atan(this.one_minus_f_squared * Math.tan(p.y)); + } else { + lat = p.y; + } + + /* Convert the input lat, lon into theta, phi as used by QSC. + * This depends on the cube face and the area on it. + * For the top and bottom face, we can compute theta and phi + * directly from phi, lam. For the other faces, we must use + * unit sphere cartesian coordinates as an intermediate step. */ + lon = p.x; //lon = lp.lam; + if (this.face === FACE_ENUM.TOP) { + phi = HALF_PI - lat; + if (lon >= FORTPI && lon <= HALF_PI + FORTPI) { + area.value = AREA_ENUM.AREA_0; + theta = lon - HALF_PI; + } else if (lon > HALF_PI + FORTPI || lon <= -(HALF_PI + FORTPI)) { + area.value = AREA_ENUM.AREA_1; + theta = (lon > 0.0 ? lon - SPI : lon + SPI); + } else if (lon > -(HALF_PI + FORTPI) && lon <= -FORTPI) { + area.value = AREA_ENUM.AREA_2; + theta = lon + HALF_PI; + } else { + area.value = AREA_ENUM.AREA_3; + theta = lon; + } + } else if (this.face === FACE_ENUM.BOTTOM) { + phi = HALF_PI + lat; + if (lon >= FORTPI && lon <= HALF_PI + FORTPI) { + area.value = AREA_ENUM.AREA_0; + theta = -lon + HALF_PI; + } else if (lon < FORTPI && lon >= -FORTPI) { + area.value = AREA_ENUM.AREA_1; + theta = -lon; + } else if (lon < -FORTPI && lon >= -(HALF_PI + FORTPI)) { + area.value = AREA_ENUM.AREA_2; + theta = -lon - HALF_PI; + } else { + area.value = AREA_ENUM.AREA_3; + theta = (lon > 0.0 ? -lon + SPI : -lon - SPI); + } + } else { + var q, r, s; + var sinlat, coslat; + var sinlon, coslon; + + if (this.face === FACE_ENUM.RIGHT) { + lon = qsc_shift_lon_origin(lon, +HALF_PI); + } else if (this.face === FACE_ENUM.BACK) { + lon = qsc_shift_lon_origin(lon, +SPI); + } else if (this.face === FACE_ENUM.LEFT) { + lon = qsc_shift_lon_origin(lon, -HALF_PI); + } + sinlat = Math.sin(lat); + coslat = Math.cos(lat); + sinlon = Math.sin(lon); + coslon = Math.cos(lon); + q = coslat * coslon; + r = coslat * sinlon; + s = sinlat; + + if (this.face === FACE_ENUM.FRONT) { + phi = Math.acos(q); + theta = qsc_fwd_equat_face_theta(phi, s, r, area); + } else if (this.face === FACE_ENUM.RIGHT) { + phi = Math.acos(r); + theta = qsc_fwd_equat_face_theta(phi, s, -q, area); + } else if (this.face === FACE_ENUM.BACK) { + phi = Math.acos(-q); + theta = qsc_fwd_equat_face_theta(phi, s, -r, area); + } else if (this.face === FACE_ENUM.LEFT) { + phi = Math.acos(-r); + theta = qsc_fwd_equat_face_theta(phi, s, q, area); + } else { + /* Impossible */ + phi = theta = 0; + area.value = AREA_ENUM.AREA_0; + } + } + + /* Compute mu and nu for the area of definition. + * For mu, see Eq. (3-21) in [OL76], but note the typos: + * compare with Eq. (3-14). For nu, see Eq. (3-38). */ + mu = Math.atan((12 / SPI) * (theta + Math.acos(Math.sin(theta) * Math.cos(FORTPI)) - HALF_PI)); + t = Math.sqrt((1 - Math.cos(phi)) / (Math.cos(mu) * Math.cos(mu)) / (1 - Math.cos(Math.atan(1 / Math.cos(theta))))); + + /* Apply the result to the real area. */ + if (area.value === AREA_ENUM.AREA_1) { + mu += HALF_PI; + } else if (area.value === AREA_ENUM.AREA_2) { + mu += SPI; + } else if (area.value === AREA_ENUM.AREA_3) { + mu += 1.5 * SPI; + } + + /* Now compute x, y from mu and nu */ + xy.x = t * Math.cos(mu); + xy.y = t * Math.sin(mu); + xy.x = xy.x * this.a + this.x0; + xy.y = xy.y * this.a + this.y0; + + p.x = xy.x; + p.y = xy.y; + return p; +} + +// QSC inverse equations--mapping x,y to lat/long +// ----------------------------------------------------------------- +function inverse$4(p) { + var lp = {lam: 0, phi: 0}; + var mu, nu, cosmu, tannu; + var tantheta, theta, cosphi, phi; + var t; + var area = {value: 0}; + + /* de-offset */ + p.x = (p.x - this.x0) / this.a; + p.y = (p.y - this.y0) / this.a; + + /* Convert the input x, y to the mu and nu angles as used by QSC. + * This depends on the area of the cube face. */ + nu = Math.atan(Math.sqrt(p.x * p.x + p.y * p.y)); + mu = Math.atan2(p.y, p.x); + if (p.x >= 0.0 && p.x >= Math.abs(p.y)) { + area.value = AREA_ENUM.AREA_0; + } else if (p.y >= 0.0 && p.y >= Math.abs(p.x)) { + area.value = AREA_ENUM.AREA_1; + mu -= HALF_PI; + } else if (p.x < 0.0 && -p.x >= Math.abs(p.y)) { + area.value = AREA_ENUM.AREA_2; + mu = (mu < 0.0 ? mu + SPI : mu - SPI); + } else { + area.value = AREA_ENUM.AREA_3; + mu += HALF_PI; + } + + /* Compute phi and theta for the area of definition. + * The inverse projection is not described in the original paper, but some + * good hints can be found here (as of 2011-12-14): + * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302 + * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */ + t = (SPI / 12) * Math.tan(mu); + tantheta = Math.sin(t) / (Math.cos(t) - (1 / Math.sqrt(2))); + theta = Math.atan(tantheta); + cosmu = Math.cos(mu); + tannu = Math.tan(nu); + cosphi = 1 - cosmu * cosmu * tannu * tannu * (1 - Math.cos(Math.atan(1 / Math.cos(theta)))); + if (cosphi < -1) { + cosphi = -1; + } else if (cosphi > +1) { + cosphi = +1; + } + + /* Apply the result to the real area on the cube face. + * For the top and bottom face, we can compute phi and lam directly. + * For the other faces, we must use unit sphere cartesian coordinates + * as an intermediate step. */ + if (this.face === FACE_ENUM.TOP) { + phi = Math.acos(cosphi); + lp.phi = HALF_PI - phi; + if (area.value === AREA_ENUM.AREA_0) { + lp.lam = theta + HALF_PI; + } else if (area.value === AREA_ENUM.AREA_1) { + lp.lam = (theta < 0.0 ? theta + SPI : theta - SPI); + } else if (area.value === AREA_ENUM.AREA_2) { + lp.lam = theta - HALF_PI; + } else /* area.value == AREA_ENUM.AREA_3 */ { + lp.lam = theta; + } + } else if (this.face === FACE_ENUM.BOTTOM) { + phi = Math.acos(cosphi); + lp.phi = phi - HALF_PI; + if (area.value === AREA_ENUM.AREA_0) { + lp.lam = -theta + HALF_PI; + } else if (area.value === AREA_ENUM.AREA_1) { + lp.lam = -theta; + } else if (area.value === AREA_ENUM.AREA_2) { + lp.lam = -theta - HALF_PI; + } else /* area.value == AREA_ENUM.AREA_3 */ { + lp.lam = (theta < 0.0 ? -theta - SPI : -theta + SPI); + } + } else { + /* Compute phi and lam via cartesian unit sphere coordinates. */ + var q, r, s; + q = cosphi; + t = q * q; + if (t >= 1) { + s = 0; + } else { + s = Math.sqrt(1 - t) * Math.sin(theta); + } + t += s * s; + if (t >= 1) { + r = 0; + } else { + r = Math.sqrt(1 - t); + } + /* Rotate q,r,s into the correct area. */ + if (area.value === AREA_ENUM.AREA_1) { + t = r; + r = -s; + s = t; + } else if (area.value === AREA_ENUM.AREA_2) { + r = -r; + s = -s; + } else if (area.value === AREA_ENUM.AREA_3) { + t = r; + r = s; + s = -t; + } + /* Rotate q,r,s into the correct cube face. */ + if (this.face === FACE_ENUM.RIGHT) { + t = q; + q = -r; + r = t; + } else if (this.face === FACE_ENUM.BACK) { + q = -q; + r = -r; + } else if (this.face === FACE_ENUM.LEFT) { + t = q; + q = r; + r = -t; + } + /* Now compute phi and lam from the unit sphere coordinates. */ + lp.phi = Math.acos(-s) - HALF_PI; + lp.lam = Math.atan2(r, q); + if (this.face === FACE_ENUM.RIGHT) { + lp.lam = qsc_shift_lon_origin(lp.lam, -HALF_PI); + } else if (this.face === FACE_ENUM.BACK) { + lp.lam = qsc_shift_lon_origin(lp.lam, -SPI); + } else if (this.face === FACE_ENUM.LEFT) { + lp.lam = qsc_shift_lon_origin(lp.lam, +HALF_PI); + } + } + + /* Apply the shift from the sphere to the ellipsoid as described + * in [LK12]. */ + if (this.es !== 0) { + var invert_sign; + var tanphi, xa; + invert_sign = (lp.phi < 0 ? 1 : 0); + tanphi = Math.tan(lp.phi); + xa = this.b / Math.sqrt(tanphi * tanphi + this.one_minus_f_squared); + lp.phi = Math.atan(Math.sqrt(this.a * this.a - xa * xa) / (this.one_minus_f * xa)); + if (invert_sign) { + lp.phi = -lp.phi; + } + } + + lp.lam += this.long0; + p.x = lp.lam; + p.y = lp.phi; + return p; +} + +/* Helper function for forward projection: compute the theta angle + * and determine the area number. */ +function qsc_fwd_equat_face_theta(phi, y, x, area) { + var theta; + if (phi < EPSLN) { + area.value = AREA_ENUM.AREA_0; + theta = 0.0; + } else { + theta = Math.atan2(y, x); + if (Math.abs(theta) <= FORTPI) { + area.value = AREA_ENUM.AREA_0; + } else if (theta > FORTPI && theta <= HALF_PI + FORTPI) { + area.value = AREA_ENUM.AREA_1; + theta -= HALF_PI; + } else if (theta > HALF_PI + FORTPI || theta <= -(HALF_PI + FORTPI)) { + area.value = AREA_ENUM.AREA_2; + theta = (theta >= 0.0 ? theta - SPI : theta + SPI); + } else { + area.value = AREA_ENUM.AREA_3; + theta += HALF_PI; + } + } + return theta; +} + +/* Helper function: shift the longitude. */ +function qsc_shift_lon_origin(lon, offset) { + var slon = lon + offset; + if (slon < -SPI) { + slon += TWO_PI; + } else if (slon > +SPI) { + slon -= TWO_PI; + } + return slon; +} + +var names$4 = ["Quadrilateralized Spherical Cube", "Quadrilateralized_Spherical_Cube", "qsc"]; +var qsc = { + init: init$4, + forward: forward$4, + inverse: inverse$4, + names: names$4 +}; + +// Robinson projection +// Based on https://github.com/OSGeo/proj.4/blob/master/src/PJ_robin.c +// Polynomial coeficients from http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039 + + +var COEFS_X = [ + [1.0000, 2.2199e-17, -7.15515e-05, 3.1103e-06], + [0.9986, -0.000482243, -2.4897e-05, -1.3309e-06], + [0.9954, -0.00083103, -4.48605e-05, -9.86701e-07], + [0.9900, -0.00135364, -5.9661e-05, 3.6777e-06], + [0.9822, -0.00167442, -4.49547e-06, -5.72411e-06], + [0.9730, -0.00214868, -9.03571e-05, 1.8736e-08], + [0.9600, -0.00305085, -9.00761e-05, 1.64917e-06], + [0.9427, -0.00382792, -6.53386e-05, -2.6154e-06], + [0.9216, -0.00467746, -0.00010457, 4.81243e-06], + [0.8962, -0.00536223, -3.23831e-05, -5.43432e-06], + [0.8679, -0.00609363, -0.000113898, 3.32484e-06], + [0.8350, -0.00698325, -6.40253e-05, 9.34959e-07], + [0.7986, -0.00755338, -5.00009e-05, 9.35324e-07], + [0.7597, -0.00798324, -3.5971e-05, -2.27626e-06], + [0.7186, -0.00851367, -7.01149e-05, -8.6303e-06], + [0.6732, -0.00986209, -0.000199569, 1.91974e-05], + [0.6213, -0.010418, 8.83923e-05, 6.24051e-06], + [0.5722, -0.00906601, 0.000182, 6.24051e-06], + [0.5322, -0.00677797, 0.000275608, 6.24051e-06] +]; + +var COEFS_Y = [ + [-5.20417e-18, 0.0124, 1.21431e-18, -8.45284e-11], + [0.0620, 0.0124, -1.26793e-09, 4.22642e-10], + [0.1240, 0.0124, 5.07171e-09, -1.60604e-09], + [0.1860, 0.0123999, -1.90189e-08, 6.00152e-09], + [0.2480, 0.0124002, 7.10039e-08, -2.24e-08], + [0.3100, 0.0123992, -2.64997e-07, 8.35986e-08], + [0.3720, 0.0124029, 9.88983e-07, -3.11994e-07], + [0.4340, 0.0123893, -3.69093e-06, -4.35621e-07], + [0.4958, 0.0123198, -1.02252e-05, -3.45523e-07], + [0.5571, 0.0121916, -1.54081e-05, -5.82288e-07], + [0.6176, 0.0119938, -2.41424e-05, -5.25327e-07], + [0.6769, 0.011713, -3.20223e-05, -5.16405e-07], + [0.7346, 0.0113541, -3.97684e-05, -6.09052e-07], + [0.7903, 0.0109107, -4.89042e-05, -1.04739e-06], + [0.8435, 0.0103431, -6.4615e-05, -1.40374e-09], + [0.8936, 0.00969686, -6.4636e-05, -8.547e-06], + [0.9394, 0.00840947, -0.000192841, -4.2106e-06], + [0.9761, 0.00616527, -0.000256, -4.2106e-06], + [1.0000, 0.00328947, -0.000319159, -4.2106e-06] +]; + +var FXC = 0.8487; +var FYC = 1.3523; +var C1 = R2D/5; // rad to 5-degree interval +var RC1 = 1/C1; +var NODES = 18; + +var poly3_val = function(coefs, x) { + return coefs[0] + x * (coefs[1] + x * (coefs[2] + x * coefs[3])); +}; + +var poly3_der = function(coefs, x) { + return coefs[1] + x * (2 * coefs[2] + x * 3 * coefs[3]); +}; + +function newton_rapshon(f_df, start, max_err, iters) { + var x = start; + for (; iters; --iters) { + var upd = f_df(x); + x -= upd; + if (Math.abs(upd) < max_err) { + break; + } + } + return x; +} + +function init$3() { + this.x0 = this.x0 || 0; + this.y0 = this.y0 || 0; + this.long0 = this.long0 || 0; + this.es = 0; + this.title = this.title || "Robinson"; +} + +function forward$3(ll) { + var lon = adjust_lon(ll.x - this.long0); + + var dphi = Math.abs(ll.y); + var i = Math.floor(dphi * C1); + if (i < 0) { + i = 0; + } else if (i >= NODES) { + i = NODES - 1; + } + dphi = R2D * (dphi - RC1 * i); + var xy = { + x: poly3_val(COEFS_X[i], dphi) * lon, + y: poly3_val(COEFS_Y[i], dphi) + }; + if (ll.y < 0) { + xy.y = -xy.y; + } + + xy.x = xy.x * this.a * FXC + this.x0; + xy.y = xy.y * this.a * FYC + this.y0; + return xy; +} + +function inverse$3(xy) { + var ll = { + x: (xy.x - this.x0) / (this.a * FXC), + y: Math.abs(xy.y - this.y0) / (this.a * FYC) + }; + + if (ll.y >= 1) { // pathologic case + ll.x /= COEFS_X[NODES][0]; + ll.y = xy.y < 0 ? -HALF_PI : HALF_PI; + } else { + // find table interval + var i = Math.floor(ll.y * NODES); + if (i < 0) { + i = 0; + } else if (i >= NODES) { + i = NODES - 1; + } + for (;;) { + if (COEFS_Y[i][0] > ll.y) { + --i; + } else if (COEFS_Y[i+1][0] <= ll.y) { + ++i; + } else { + break; + } + } + // linear interpolation in 5 degree interval + var coefs = COEFS_Y[i]; + var t = 5 * (ll.y - coefs[0]) / (COEFS_Y[i+1][0] - coefs[0]); + // find t so that poly3_val(coefs, t) = ll.y + t = newton_rapshon(function(x) { + return (poly3_val(coefs, x) - ll.y) / poly3_der(coefs, x); + }, t, EPSLN, 100); + + ll.x /= poly3_val(COEFS_X[i], t); + ll.y = (5 * i + t) * D2R$1; + if (xy.y < 0) { + ll.y = -ll.y; + } + } + + ll.x = adjust_lon(ll.x + this.long0); + return ll; +} + +var names$3 = ["Robinson", "robin"]; +var robin = { + init: init$3, + forward: forward$3, + inverse: inverse$3, + names: names$3 +}; + +function init$2() { + this.name = 'geocent'; + +} + +function forward$2(p) { + var point = geodeticToGeocentric(p, this.es, this.a); + return point; +} + +function inverse$2(p) { + var point = geocentricToGeodetic(p, this.es, this.a, this.b); + return point; +} + +var names$2 = ["Geocentric", 'geocentric', "geocent", "Geocent"]; +var geocent = { + init: init$2, + forward: forward$2, + inverse: inverse$2, + names: names$2 +}; + +var mode = { + N_POLE: 0, + S_POLE: 1, + EQUIT: 2, + OBLIQ: 3 +}; + +var params = { + h: { def: 100000, num: true }, // default is Karman line, no default in PROJ.7 + azi: { def: 0, num: true, degrees: true }, // default is North + tilt: { def: 0, num: true, degrees: true }, // default is Nadir + long0: { def: 0, num: true }, // default is Greenwich, conversion to rad is automatic + lat0: { def: 0, num: true } // default is Equator, conversion to rad is automatic +}; + +function init$1() { + Object.keys(params).forEach(function (p) { + if (typeof this[p] === "undefined") { + this[p] = params[p].def; + } else if (params[p].num && isNaN(this[p])) { + throw new Error("Invalid parameter value, must be numeric " + p + " = " + this[p]); + } else if (params[p].num) { + this[p] = parseFloat(this[p]); + } + if (params[p].degrees) { + this[p] = this[p] * D2R$1; + } + }.bind(this)); + + if (Math.abs((Math.abs(this.lat0) - HALF_PI)) < EPSLN) { + this.mode = this.lat0 < 0 ? mode.S_POLE : mode.N_POLE; + } else if (Math.abs(this.lat0) < EPSLN) { + this.mode = mode.EQUIT; + } else { + this.mode = mode.OBLIQ; + this.sinph0 = Math.sin(this.lat0); + this.cosph0 = Math.cos(this.lat0); + } + + this.pn1 = this.h / this.a; // Normalize relative to the Earth's radius + + if (this.pn1 <= 0 || this.pn1 > 1e10) { + throw new Error("Invalid height"); + } + + this.p = 1 + this.pn1; + this.rp = 1 / this.p; + this.h1 = 1 / this.pn1; + this.pfact = (this.p + 1) * this.h1; + this.es = 0; + + var omega = this.tilt; + var gamma = this.azi; + this.cg = Math.cos(gamma); + this.sg = Math.sin(gamma); + this.cw = Math.cos(omega); + this.sw = Math.sin(omega); +} + +function forward$1(p) { + p.x -= this.long0; + var sinphi = Math.sin(p.y); + var cosphi = Math.cos(p.y); + var coslam = Math.cos(p.x); + var x, y; + switch (this.mode) { + case mode.OBLIQ: + y = this.sinph0 * sinphi + this.cosph0 * cosphi * coslam; + break; + case mode.EQUIT: + y = cosphi * coslam; + break; + case mode.S_POLE: + y = -sinphi; + break; + case mode.N_POLE: + y = sinphi; + break; + } + y = this.pn1 / (this.p - y); + x = y * cosphi * Math.sin(p.x); + + switch (this.mode) { + case mode.OBLIQ: + y *= this.cosph0 * sinphi - this.sinph0 * cosphi * coslam; + break; + case mode.EQUIT: + y *= sinphi; + break; + case mode.N_POLE: + y *= -(cosphi * coslam); + break; + case mode.S_POLE: + y *= cosphi * coslam; + break; + } + + // Tilt + var yt, ba; + yt = y * this.cg + x * this.sg; + ba = 1 / (yt * this.sw * this.h1 + this.cw); + x = (x * this.cg - y * this.sg) * this.cw * ba; + y = yt * ba; + + p.x = x * this.a; + p.y = y * this.a; + return p; +} + +function inverse$1(p) { + p.x /= this.a; + p.y /= this.a; + var r = { x: p.x, y: p.y }; + + // Un-Tilt + var bm, bq, yt; + yt = 1 / (this.pn1 - p.y * this.sw); + bm = this.pn1 * p.x * yt; + bq = this.pn1 * p.y * this.cw * yt; + p.x = bm * this.cg + bq * this.sg; + p.y = bq * this.cg - bm * this.sg; + + var rh = hypot(p.x, p.y); + if (Math.abs(rh) < EPSLN) { + r.x = 0; + r.y = p.y; + } else { + var cosz, sinz; + sinz = 1 - rh * rh * this.pfact; + sinz = (this.p - Math.sqrt(sinz)) / (this.pn1 / rh + rh / this.pn1); + cosz = Math.sqrt(1 - sinz * sinz); + switch (this.mode) { + case mode.OBLIQ: + r.y = Math.asin(cosz * this.sinph0 + p.y * sinz * this.cosph0 / rh); + p.y = (cosz - this.sinph0 * Math.sin(r.y)) * rh; + p.x *= sinz * this.cosph0; + break; + case mode.EQUIT: + r.y = Math.asin(p.y * sinz / rh); + p.y = cosz * rh; + p.x *= sinz; + break; + case mode.N_POLE: + r.y = Math.asin(cosz); + p.y = -p.y; + break; + case mode.S_POLE: + r.y = -Math.asin(cosz); + break; + } + r.x = Math.atan2(p.x, p.y); + } + + p.x = r.x + this.long0; + p.y = r.y; + return p; +} + +var names$1 = ["Tilted_Perspective", "tpers"]; +var tpers = { + init: init$1, + forward: forward$1, + inverse: inverse$1, + names: names$1 +}; + +function init() { + this.flip_axis = (this.sweep === 'x' ? 1 : 0); + this.h = Number(this.h); + this.radius_g_1 = this.h / this.a; + + if (this.radius_g_1 <= 0 || this.radius_g_1 > 1e10) { + throw new Error(); + } + + this.radius_g = 1.0 + this.radius_g_1; + this.C = this.radius_g * this.radius_g - 1.0; + + if (this.es !== 0.0) { + var one_es = 1.0 - this.es; + var rone_es = 1 / one_es; + + this.radius_p = Math.sqrt(one_es); + this.radius_p2 = one_es; + this.radius_p_inv2 = rone_es; + + this.shape = 'ellipse'; // Use as a condition in the forward and inverse functions. + } else { + this.radius_p = 1.0; + this.radius_p2 = 1.0; + this.radius_p_inv2 = 1.0; + + this.shape = 'sphere'; // Use as a condition in the forward and inverse functions. + } + + if (!this.title) { + this.title = "Geostationary Satellite View"; + } +} + +function forward(p) { + var lon = p.x; + var lat = p.y; + var tmp, v_x, v_y, v_z; + lon = lon - this.long0; + + if (this.shape === 'ellipse') { + lat = Math.atan(this.radius_p2 * Math.tan(lat)); + var r = this.radius_p / hypot(this.radius_p * Math.cos(lat), Math.sin(lat)); + + v_x = r * Math.cos(lon) * Math.cos(lat); + v_y = r * Math.sin(lon) * Math.cos(lat); + v_z = r * Math.sin(lat); + + if (((this.radius_g - v_x) * v_x - v_y * v_y - v_z * v_z * this.radius_p_inv2) < 0.0) { + p.x = Number.NaN; + p.y = Number.NaN; + return p; + } + + tmp = this.radius_g - v_x; + if (this.flip_axis) { + p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp)); + p.y = this.radius_g_1 * Math.atan(v_z / tmp); + } else { + p.x = this.radius_g_1 * Math.atan(v_y / tmp); + p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp)); + } + } else if (this.shape === 'sphere') { + tmp = Math.cos(lat); + v_x = Math.cos(lon) * tmp; + v_y = Math.sin(lon) * tmp; + v_z = Math.sin(lat); + tmp = this.radius_g - v_x; + + if (this.flip_axis) { + p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp)); + p.y = this.radius_g_1 * Math.atan(v_z / tmp); + } else { + p.x = this.radius_g_1 * Math.atan(v_y / tmp); + p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp)); + } + } + p.x = p.x * this.a; + p.y = p.y * this.a; + return p; +} + +function inverse(p) { + var v_x = -1.0; + var v_y = 0.0; + var v_z = 0.0; + var a, b, det, k; + + p.x = p.x / this.a; + p.y = p.y / this.a; + + if (this.shape === 'ellipse') { + if (this.flip_axis) { + v_z = Math.tan(p.y / this.radius_g_1); + v_y = Math.tan(p.x / this.radius_g_1) * hypot(1.0, v_z); + } else { + v_y = Math.tan(p.x / this.radius_g_1); + v_z = Math.tan(p.y / this.radius_g_1) * hypot(1.0, v_y); + } + + var v_zp = v_z / this.radius_p; + a = v_y * v_y + v_zp * v_zp + v_x * v_x; + b = 2 * this.radius_g * v_x; + det = (b * b) - 4 * a * this.C; + + if (det < 0.0) { + p.x = Number.NaN; + p.y = Number.NaN; + return p; + } + + k = (-b - Math.sqrt(det)) / (2.0 * a); + v_x = this.radius_g + k * v_x; + v_y *= k; + v_z *= k; + + p.x = Math.atan2(v_y, v_x); + p.y = Math.atan(v_z * Math.cos(p.x) / v_x); + p.y = Math.atan(this.radius_p_inv2 * Math.tan(p.y)); + } else if (this.shape === 'sphere') { + if (this.flip_axis) { + v_z = Math.tan(p.y / this.radius_g_1); + v_y = Math.tan(p.x / this.radius_g_1) * Math.sqrt(1.0 + v_z * v_z); + } else { + v_y = Math.tan(p.x / this.radius_g_1); + v_z = Math.tan(p.y / this.radius_g_1) * Math.sqrt(1.0 + v_y * v_y); + } + + a = v_y * v_y + v_z * v_z + v_x * v_x; + b = 2 * this.radius_g * v_x; + det = (b * b) - 4 * a * this.C; + if (det < 0.0) { + p.x = Number.NaN; + p.y = Number.NaN; + return p; + } + + k = (-b - Math.sqrt(det)) / (2.0 * a); + v_x = this.radius_g + k * v_x; + v_y *= k; + v_z *= k; + + p.x = Math.atan2(v_y, v_x); + p.y = Math.atan(v_z * Math.cos(p.x) / v_x); + } + p.x = p.x + this.long0; + return p; +} + +var names = ["Geostationary Satellite View", "Geostationary_Satellite", "geos"]; +var geos = { + init: init, + forward: forward, + inverse: inverse, + names: names, +}; + +function includedProjections(proj4){ + proj4.Proj.projections.add(tmerc); + proj4.Proj.projections.add(etmerc); + proj4.Proj.projections.add(utm); + proj4.Proj.projections.add(sterea); + proj4.Proj.projections.add(stere); + proj4.Proj.projections.add(somerc); + proj4.Proj.projections.add(omerc); + proj4.Proj.projections.add(lcc); + proj4.Proj.projections.add(krovak); + proj4.Proj.projections.add(cass); + proj4.Proj.projections.add(laea); + proj4.Proj.projections.add(aea); + proj4.Proj.projections.add(gnom); + proj4.Proj.projections.add(cea); + proj4.Proj.projections.add(eqc); + proj4.Proj.projections.add(poly); + proj4.Proj.projections.add(nzmg); + proj4.Proj.projections.add(mill); + proj4.Proj.projections.add(sinu); + proj4.Proj.projections.add(moll); + proj4.Proj.projections.add(eqdc); + proj4.Proj.projections.add(vandg); + proj4.Proj.projections.add(aeqd); + proj4.Proj.projections.add(ortho); + proj4.Proj.projections.add(qsc); + proj4.Proj.projections.add(robin); + proj4.Proj.projections.add(geocent); + proj4.Proj.projections.add(tpers); + proj4.Proj.projections.add(geos); +} + +proj4.defaultDatum = 'WGS84'; //default datum +proj4.Proj = Projection; +proj4.WGS84 = new proj4.Proj('WGS84'); +proj4.Point = Point; +proj4.toPoint = common; +proj4.defs = defs; +proj4.nadgrid = nadgrid; +proj4.transform = transform; +proj4.mgrs = mgrs; +proj4.version = '__VERSION__'; +includedProjections(proj4); + +var f,m="deflate-raw",x=self.DecompressionStream;try{new x(m),f=async t=>{let n=new x(m),e=n.writable.getWriter(),i=n.readable.getReader();e.write(t),e.close();let c,o=[],s=0,a=0,l;for(;!(l=await i.read()).done;)c=l.value,o.push(c),s+=c.length;return o.length-1?(c=new Uint8Array(s),o.map(r=>{c.set(r,a),a+=r.length;}),c):o[0]};}catch{}var _=new TextDecoder,h=t=>{throw new Error("but-unzip~"+t)},E=t=>_.decode(t),A=t=>{let n=t.length-20,e=Math.max(n-65516,2);for(;(n=t.lastIndexOf(80,n-1))!==-1&&!(t[n+1]===75&&t[n+2]===5&&t[n+3]===6)&&n>e;);return n};function*C(t,n=f){let e=A(t);e===-1&&h(2);let i=(r,d)=>t.subarray(e+=r,e+=d),c=new DataView(t.buffer,t.byteOffset),o=r=>c.getUint16(r+e,!0),s=r=>c.getUint32(r+e,!0),a=o(10);for(a!==o(8)&&h(3),e=s(16);a--;){let r=o(10),d=o(28),g=o(30),y=o(32),b=s(20),w=s(42),p=E(i(46,d)),D=E(i(g,y)),L=e,u;e=w,u=i(30+o(26)+o(28),b),yield {filename:p,comment:D,read:()=>r&8?n(u):r?h(1):u},e=L;}} + +const regex$1 = /.+\.(shp|dbf|json|prj|cpg)$/i; +var unzip = async (buffer) => { + const files = {}; + const proms = []; + for (const entry of C(buffer)) { + if (!regex$1.test(entry.filename)) { + continue; + } + proms.push(Promise.resolve(entry.read()).then(bytes => files[entry.filename] = bytes)); + } + await Promise.all(proms); + const out = {}; + const decoder = new TextDecoder(); + for (const [key, value] of Object.entries(files)) { + if (key.slice(-3).toLowerCase() === 'shp' || key.slice(-3).toLowerCase() === 'dbf') { + out[key] = new DataView(value.buffer, value.byteOffset, value.byteLength); + } else { + out[key] = decoder.decode(value); + } + } + return out; +}; + +const URL$1 = globalThis.URL; + +var combine$1 = (base, type) => { + if (!type) { + return base; + } + const url = new URL$1(base); + url.pathname = `${url.pathname}.${type}`; + return url.href; +}; + +async function binaryAjax(_url, type) { + + const url = combine$1(_url, type); + const isOptionalTxt = type === 'prj' || type === 'cpg'; + try { + const resp = await fetch(url); + if (resp.status > 399) { + throw new Error(resp.statusText); + } + if (isOptionalTxt) { + return resp.text(); + } + const parsed = await resp.arrayBuffer(); + return new DataView(parsed) + } catch (e) { + if (isOptionalTxt || type === 'dbf') { + return false; + } + throw e; + } +} + +function isClockWise(array) { + let sum = 0; + let i = 1; + const len = array.length; + let prev, cur; + const bbox = [array[0][0], array[0][1], array[0][0], array[0][1]]; + while (i < len) { + prev = cur || array[0]; + cur = array[i]; + sum += ((cur[0] - prev[0]) * (cur[1] + prev[1])); + i++; + if (cur[0] < bbox[0]) { + bbox[0] = cur[0]; + } + if (cur[1] < bbox[1]) { + bbox[1] = cur[1]; + } + if (cur[0] > bbox[2]) { + bbox[2] = cur[0]; + } + if (cur[1] > bbox[3]) { + bbox[3] = cur[1]; + } + } + return { + ring: array, + clockWise: sum > 0, + bbox, + children: [] + } + +} + +function contains(outer, inner) { + if (outer.bbox[0] > inner.bbox[0]) { + return false; + } + if (outer.bbox[1] > inner.bbox[1]) { + return false; + } + if (outer.bbox[2] < inner.bbox[2]) { + return false; + } + if (outer.bbox[3] < inner.bbox[3]) { + return false; + } + return true; +} + +function handleRings(rings) { + const outers = []; + const inners = []; + for (const ring of rings) { + const proccessed = isClockWise(ring); + if (proccessed.clockWise) { + outers.push(proccessed); + } else { + inners.push(proccessed); + } + } + // this is an optimization, + // but it would also put in weird bad rings that would otherwise get left out + // if (outers.length === 1) { + // const out = [outers[0].ring] + // for (const inner of inners) { + // out.push(inner.ring); + + // } + // return [out]; + // } + for (const inner of inners) { + for (const outer of outers) { + if (contains(outer, inner)) { + outer.children.push(inner.ring); + break; + } + } + } + const out = []; + for (const outer of outers) { + out.push([outer.ring].concat(outer.children)); + } + return out; +} +ParseShp.prototype.parsePoint = function (data) { + return { + type: 'Point', + coordinates: this.parseCoord(data, 0) + }; +}; +ParseShp.prototype.parseZPoint = function (data) { + const pointXY = this.parsePoint(data); + pointXY.coordinates.push(data.getFloat64(16, true)); + return pointXY; +}; +ParseShp.prototype.parsePointArray = function (data, offset, num) { + const out = []; + let done = 0; + while (done < num) { + out.push(this.parseCoord(data, offset)); + offset += 16; + done++; + } + return out; +}; +ParseShp.prototype.parseZPointArray = function (data, zOffset, num, coordinates) { + let i = 0; + while (i < num) { + coordinates[i].push(data.getFloat64(zOffset, true)); + i++; + zOffset += 8; + } + return coordinates; +}; +ParseShp.prototype.parseArrayGroup = function (data, offset, partOffset, num, tot) { + const out = []; + let done = 0; + let curNum; let nextNum = 0; + let pointNumber; + while (done < num) { + done++; + partOffset += 4; + curNum = nextNum; + if (done === num) { + nextNum = tot; + } else { + nextNum = data.getInt32(partOffset, true); + } + pointNumber = nextNum - curNum; + if (!pointNumber) { + continue; + } + out.push(this.parsePointArray(data, offset, pointNumber)); + offset += (pointNumber << 4); + } + return out; +}; +ParseShp.prototype.parseZArrayGroup = function (data, zOffset, num, coordinates) { + let i = 0; + while (i < num) { + coordinates[i] = this.parseZPointArray(data, zOffset, coordinates[i].length, coordinates[i]); + zOffset += (coordinates[i].length << 3); + i++; + } + return coordinates; +}; +ParseShp.prototype.parseMultiPoint = function (data) { + const out = {}; + const num = data.getInt32(32, true); + if (!num) { + return null; + } + const mins = this.parseCoord(data, 0); + const maxs = this.parseCoord(data, 16); + out.bbox = [ + mins[0], + mins[1], + maxs[0], + maxs[1] + ]; + const offset = 36; + if (num === 1) { + out.type = 'Point'; + out.coordinates = this.parseCoord(data, offset); + } else { + out.type = 'MultiPoint'; + out.coordinates = this.parsePointArray(data, offset, num); + } + return out; +}; +ParseShp.prototype.parseZMultiPoint = function (data) { + const geoJson = this.parseMultiPoint(data); + if (!geoJson) { + return null; + } + let num; + if (geoJson.type === 'Point') { + geoJson.coordinates.push(data.getFloat64(72, true)); + return geoJson; + } else { + num = geoJson.coordinates.length; + } + const zOffset = 52 + (num << 4); + geoJson.coordinates = this.parseZPointArray(data, zOffset, num, geoJson.coordinates); + return geoJson; +}; +ParseShp.prototype.parsePolyline = function (data) { + const out = {}; + const numParts = data.getInt32(32, true); + if (!numParts) { + return null; + } + const mins = this.parseCoord(data, 0); + const maxs = this.parseCoord(data, 16); + out.bbox = [ + mins[0], + mins[1], + maxs[0], + maxs[1] + ]; + const num = data.getInt32(36, true); + let offset, partOffset; + if (numParts === 1) { + out.type = 'LineString'; + offset = 44; + out.coordinates = this.parsePointArray(data, offset, num); + } else { + out.type = 'MultiLineString'; + offset = 40 + (numParts << 2); + partOffset = 40; + out.coordinates = this.parseArrayGroup(data, offset, partOffset, numParts, num); + } + return out; +}; +ParseShp.prototype.parseZPolyline = function (data) { + const geoJson = this.parsePolyline(data); + if (!geoJson) { + return null; + } + const num = geoJson.coordinates.length; + let zOffset; + if (geoJson.type === 'LineString') { + zOffset = 60 + (num << 4); + geoJson.coordinates = this.parseZPointArray(data, zOffset, num, geoJson.coordinates); + return geoJson; + } else { + const totalPoints = geoJson.coordinates.reduce(function (a, v) { + return a + v.length; + }, 0); + zOffset = 56 + (totalPoints << 4) + (num << 2); + geoJson.coordinates = this.parseZArrayGroup(data, zOffset, num, geoJson.coordinates); + return geoJson; + } +}; +ParseShp.prototype.polyFuncs = function (out) { + if (!out) { + return out; + } + if (out.type === 'LineString') { + out.type = 'Polygon'; + out.coordinates = [out.coordinates]; + return out; + } else { + out.coordinates = handleRings(out.coordinates); + if (out.coordinates.length === 1) { + out.type = 'Polygon'; + out.coordinates = out.coordinates[0]; + return out; + } else { + out.type = 'MultiPolygon'; + return out; + } + } +}; +ParseShp.prototype.parsePolygon = function (data) { + return this.polyFuncs(this.parsePolyline(data)); +}; +ParseShp.prototype.parseZPolygon = function (data) { + return this.polyFuncs(this.parseZPolyline(data)); +}; +const shpFuncObj = { + 1: 'parsePoint', + 3: 'parsePolyline', + 5: 'parsePolygon', + 8: 'parseMultiPoint', + 11: 'parseZPoint', + 13: 'parseZPolyline', + 15: 'parseZPolygon', + 18: 'parseZMultiPoint' +}; + +function makeParseCoord(trans) { + if (trans) { + return function (data, offset) { + const args = [data.getFloat64(offset, true), data.getFloat64(offset + 8, true)]; + return trans.inverse(args); + }; + } else { + return function (data, offset) { + return [data.getFloat64(offset, true), data.getFloat64(offset + 8, true)]; + }; + } +} + +function ParseShp(buffer, trans) { + if (!(this instanceof ParseShp)) { + return new ParseShp(buffer, trans); + } + this.buffer = buffer; + this.headers = this.parseHeader(); + this.shpFuncs(trans); + this.rows = this.getRows(); +} +ParseShp.prototype.shpFuncs = function (tran) { + let num = this.headers.shpCode; + if (num > 20) { + num -= 20; + } + if (!(num in shpFuncObj)) { + throw new Error(`I don't know shp type "${num}"`); + } + this.parseFunc = this[shpFuncObj[num]]; + this.parseCoord = makeParseCoord(tran); +}; +ParseShp.prototype.getShpCode = function () { + return this.parseHeader().shpCode; +}; +ParseShp.prototype.parseHeader = function () { + const view = this.buffer; + return { + length: view.getInt32(6 << 2) << 1, + version: view.getInt32(7 << 2, true), + shpCode: view.getInt32(8 << 2, true), + bbox: [ + view.getFloat64(9 << 2, true), + view.getFloat64(11 << 2, true), + view.getFloat64(13 << 2, true), + view.getFloat64(15 << 2, true) + ] + }; +}; +ParseShp.prototype.getRows = function () { + let offset = 100; + const len = this.buffer.byteLength - 8; + const out = []; + let current; + while (offset <= len) { + current = this.getRow(offset); + if (!current) { + break; + } + offset += 8; + offset += current.len; + if (current.type) { + out.push(this.parseFunc(current.data)); + } else { + out.push(null); + } + } + return out; +}; +ParseShp.prototype.getRow = function (offset) { + const id = this.buffer.getInt32(offset); + const len = this.buffer.getInt32(offset + 4) << 1; + if (len === 0) { + return { + id: id, + len: len, + type: 0 + }; + } + + if (offset + len + 8 > this.buffer.byteLength) { + return; + } + return { + id: id, + len: len, + data: new DataView(this.buffer.buffer, this.buffer.byteOffset + offset + 12, len - 4), + type: this.buffer.getInt32(offset + 8, true) + }; +}; +function parseShp (buffer, trans) { + return new ParseShp(buffer, trans).rows; +} + +var regex = /^(?:ANSI\s)?(\d+)$/m; +function createDecoder(encoding, second) { + if (!encoding) { + return browserDecoder; + } + try { + new TextDecoder(encoding.trim()); + } catch (e) { + var match = regex.exec(encoding); + if (match && !second) { + return createDecoder('windows-' + match[1], true); + } else { + encoding = undefined; + return browserDecoder; + } + } + return browserDecoder; + function browserDecoder(buffer) { + var decoder = new TextDecoder(encoding ? encoding : undefined); + var out = decoder.decode(buffer, { + stream: true + }) + decoder.decode(); + return out.replace(/\0/g, '').trim(); + } +} + +function dbfHeader(data) { + var out = {}; + out.lastUpdated = new Date(data.getUint8(1) + 1900, data.getUint8(2), data.getUint8(3)); + out.records = data.getUint32(4, true); + out.headerLen = data.getUint16(8, true); + out.recLen = data.getUint16(10, true); + return out; +} + +function dbfRowHeader(data, headerLen, decoder) { + var out = []; + var offset = 32; + while (offset < headerLen) { + out.push({ + name: decoder(new Uint8Array(data.buffer.slice(data.byteOffset + offset, data.byteOffset + offset + 11))), + dataType: String.fromCharCode(data.getUint8(offset + 11)), + len: data.getUint8(offset + 16), + decimal: data.getUint8(offset + 17) + }); + if (data.getUint8(offset + 32) === 13) { + break; + } else { + offset += 32; + } + } + return out; +} + +function rowFuncs(buffer, offset, len, type, decoder) { + const data = new Uint8Array(buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + len)); + + var textData = decoder(data); + switch (type) { + case 'N': + case 'F': + case 'O': + return parseFloat(textData, 10); + case 'D': + return new Date(textData.slice(0, 4), parseInt(textData.slice(4, 6), 10) - 1, textData.slice(6, 8)); + case 'L': + return textData.toLowerCase() === 'y' || textData.toLowerCase() === 't'; + default: + return textData; + } +} + +function parseRow(buffer, offset, rowHeaders, decoder) { + var out = {}; + var i = 0; + var len = rowHeaders.length; + var field; + var header; + while (i < len) { + header = rowHeaders[i]; + field = rowFuncs(buffer, offset, header.len, header.dataType, decoder); + offset += header.len; + if (typeof field !== 'undefined') { + out[header.name] = field; + } + i++; + } + return out; +} + +function parseDbf (buffer, encoding) { + var decoder = createDecoder(encoding); + var header = dbfHeader(buffer); + var rowHeaders = dbfRowHeader(buffer, header.headerLen - 1, decoder); + + var offset = ((rowHeaders.length + 1) << 5) + 2; + var recLen = header.recLen; + var records = header.records; + var out = []; + while (records) { + out.push(parseRow(buffer, offset, rowHeaders, decoder)); + offset += recLen; + records--; + } + return out; +} + +const URL = globalThis.URL; +const toUitn8Arr = b => { + if (!b) { + throw new Error('forgot to pass buffer'); + } + if (isArrayBuffer(b)) { + return new Uint8Array(b); + } + if (isArrayBuffer(b.buffer)) { + if (b.BYTES_PER_ELEMENT === 1) { + return b; + } + return new Uint8Array(b.buffer, b.byteOffset, b.byteLength); + } + throw new Error('invalid buffer like object') +}; +const txtDecoder = new TextDecoder(); +const toString = (possibleString) => { + if (!possibleString) { + return; + } + if (typeof possibleString === 'string') { + return possibleString; + } + if (isArrayBuffer(possibleString) || ArrayBuffer.isView(possibleString) || isDataView(possibleString)) { + return txtDecoder.decode(possibleString); + } +}; +const toDataView = b => { + if (!b) { + throw new Error('forgot to pass buffer'); + } + if (isDataView(b)) { + return b; + } + if (isArrayBuffer(b)) { + return new DataView(b); + } + if (isArrayBuffer(b.buffer)) { + return new DataView(b.buffer, b.byteOffset, b.byteLength); + } + throw new Error('invalid buffer like object') +}; + +function isArrayBuffer(subject) { + return subject instanceof globalThis.ArrayBuffer || Object.prototype.toString.call(subject) === '[object ArrayBuffer]'; +} +function isDataView(subject) { + return subject instanceof globalThis.DataView || Object.prototype.toString.call(subject) === '[object DataView]' +} + +const combine = function ([shp, dbf]) { + const out = {}; + out.type = 'FeatureCollection'; + out.features = []; + let i = 0; + const len = shp.length; + if (!dbf) { + dbf = []; + } + while (i < len) { + out.features.push({ + type: 'Feature', + geometry: shp[i], + properties: dbf[i] || {} + }); + i++; + } + return out; +}; +const parseZip = async function (buffer, whiteList) { + let key; + buffer = toUitn8Arr(buffer); + const zip = await unzip(buffer); + const names = []; + whiteList = whiteList || []; + for (key in zip) { + if (key.indexOf('__MACOSX') !== -1) { + continue; + } + if (key.slice(-4).toLowerCase() === '.shp') { + names.push(key.slice(0, -4)); + zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = zip[key]; + } else if (key.slice(-4).toLowerCase() === '.prj') { + zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = proj4(zip[key]); + } else if (key.slice(-5).toLowerCase() === '.json' || whiteList.indexOf(key.split('.').pop()) > -1) { + names.push(key.slice(0, -3) + key.slice(-3).toLowerCase()); + } else if (key.slice(-4).toLowerCase() === '.dbf' || key.slice(-4).toLowerCase() === '.cpg') { + zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = zip[key]; + } + } + if (!names.length) { + throw new Error('no layers founds'); + } + const geojson = names.map(function (name) { + let parsed, dbf; + const lastDotIdx = name.lastIndexOf('.'); + if (lastDotIdx > -1 && name.slice(lastDotIdx).indexOf('json') > -1) { + parsed = JSON.parse(zip[name]); + parsed.fileName = name.slice(0, lastDotIdx); + } else if (whiteList.indexOf(name.slice(lastDotIdx + 1)) > -1) { + parsed = zip[name]; + parsed.fileName = name; + } else { + if (zip[name + '.dbf']) { + dbf = parseDbf(zip[name + '.dbf'], zip[name + '.cpg']); + } + parsed = combine([parseShp(zip[name + '.shp'], zip[name + '.prj']), dbf]); + parsed.fileName = name; + } + return parsed; + }); + if (geojson.length === 1) { + return geojson[0]; + } else { + return geojson; + } +}; +async function getZip(base, whiteList) { + const a = await binaryAjax(base); + return parseZip(a, whiteList); +} +const handleShp = async (base) => { + const args = await Promise.all([ + binaryAjax(base, 'shp'), + binaryAjax(base, 'prj') + ]); + let prj = false; + try { + if (args[1]) { + prj = proj4(args[1]); + } + } catch (e) { + prj = false; + } + return parseShp(args[0], prj); +}; +const handleDbf = async (base) => { + const [dbf, cpg] = await Promise.all([ + binaryAjax(base, 'dbf'), + binaryAjax(base, 'cpg') + ]); + if (!dbf) { + return; + } + return parseDbf(dbf, cpg); +}; +const checkSuffix = (base, suffix) => { + const url = new URL(base, globalThis?.document?.location); + return url.pathname.slice(-4).toLowerCase() === suffix; +}; +const fromObject = ({ shp, dbf, cpg, prj }) => { + const things = [ + _parseShp(shp, prj) + ]; + if (dbf) { + things.push(_parseDbf(dbf, cpg)); + } + return combine(things); +}; +const getShapefile = async function (base, whiteList) { + if (typeof base !== 'string') { + if (isArrayBuffer(base) || ArrayBuffer.isView(base) || isDataView(base)) { + return parseZip(base); + } + if (base.shp) { + return fromObject(base); + } + throw new TypeError('must be a string, some sort of Buffer, or an object with at least a .shp property') + } + if (checkSuffix(base, '.zip')) { + return getZip(base, whiteList); + } + if (checkSuffix(base, '.shp')) { + base = base.slice(0, -4); + } + const results = await Promise.all([ + handleShp(base), + handleDbf(base) + ]); + return combine(results); +}; +const _parseShp = function (shp, prj) { + shp = toDataView(shp); + prj = toString(prj); + if (typeof prj === 'string') { + try { + prj = proj4(prj); + } catch (e) { + prj = false; + } + } + return parseShp(shp, prj); +}; +const _parseDbf = function (dbf, cpg) { + dbf = toDataView(dbf); + cpg = toString(cpg); + return parseDbf(dbf, cpg); +}; + +export { combine, getShapefile as default, getShapefile, _parseDbf as parseDbf, _parseShp as parseShp, parseZip }; diff --git a/dist/shp.esm.min.js b/dist/shp.esm.min.js new file mode 100644 index 0000000..bd7a3e1 --- /dev/null +++ b/dist/shp.esm.min.js @@ -0,0 +1 @@ +var t=1,s=2,i=3,a=4,h=5,e=6378137,r=6356752.314,n=.0066943799901413165,o=484813681109536e-20,l=Math.PI/2,u=.16666666666666666,c=.04722222222222222,f=.022156084656084655,M=1e-10,p=.017453292519943295,d=57.29577951308232,y=Math.PI/4,m=2*Math.PI,_=3.14159265359,g={greenwich:0,lisbon:-9.131906111111,paris:2.337229166667,bogota:-74.080916666667,madrid:-3.687938888889,rome:12.452333333333,bern:7.439583333333,jakarta:106.807719444444,ferro:-17.666666666667,brussels:4.367975,stockholm:18.058277777778,athens:23.7163375,oslo:10.722916666667},x={ft:{to_meter:.3048},"us-ft":{to_meter:1200/3937}},v=/[\s_\-\/\(\)]/g;function b(t,s){if(t[s])return t[s];for(var i,a=Object.keys(t),h=s.toLowerCase().replace(v,""),e=-1;++e=this.text.length)return;t=this.text[this.place++]}switch(this.state){case A:return this.neutral(t);case 2:return this.keyword(t);case 4:return this.quoted(t);case 5:return this.afterquote(t);case 3:return this.number(t);case-1:return}},I.prototype.afterquote=function(t){if('"'===t)return this.word+='"',void(this.state=4);if(E.test(t))return this.word=this.word.trim(),void this.afterItem(t);throw new Error("havn't handled \""+t+'" in afterquote yet, index '+this.place)},I.prototype.afterItem=function(t){return","===t?(null!==this.word&&this.currentObject.push(this.word),this.word=null,void(this.state=A)):"]"===t?(this.level--,null!==this.word&&(this.currentObject.push(this.word),this.word=null),this.state=A,this.currentObject=this.stack.pop(),void(this.currentObject||(this.state=-1))):void 0},I.prototype.number=function(t){if(!S.test(t)){if(E.test(t))return this.word=parseFloat(this.word),void this.afterItem(t);throw new Error("havn't handled \""+t+'" in number yet, index '+this.place)}this.word+=t},I.prototype.quoted=function(t){'"'!==t?this.word+=t:this.state=5},I.prototype.keyword=function(t){if(P.test(t))this.word+=t;else{if("["===t){var s=[];return s.push(this.word),this.level++,null===this.root?this.root=s:this.currentObject.push(s),this.stack.push(this.currentObject),this.currentObject=s,void(this.state=A)}if(!E.test(t))throw new Error("havn't handled \""+t+'" in keyword yet, index '+this.place);this.afterItem(t)}},I.prototype.neutral=function(t){if(N.test(t))return this.word=t,void(this.state=2);if('"'===t)return this.word="",void(this.state=4);if(S.test(t))return this.word=t,void(this.state=3);if(!E.test(t))throw new Error("havn't handled \""+t+'" in neutral yet, index '+this.place);this.afterItem(t)},I.prototype.output=function(){for(;this.place0?90:-90)):(t.lat0=L(t.lat1>0?90:-90),t.lat_ts=t.lat1)}(h),h}function j(t){var s=this;if(2===arguments.length){var i=arguments[1];"string"==typeof i?"+"===i.charAt(0)?j[t]=w(arguments[1]):j[t]=R(arguments[1]):j[t]=i}else if(1===arguments.length){if(Array.isArray(t))return t.map((function(t){Array.isArray(t)?j.apply(s,t):j(t)}));if("string"==typeof t){if(t in j)return j[t]}else"EPSG"in t?j["EPSG:"+t.EPSG]=t:"ESRI"in t?j["ESRI:"+t.ESRI]=t:"IAU2000"in t?j["IAU2000:"+t.IAU2000]=t:console.log(t);return}}!function(t){t("EPSG:4326","+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"),t("EPSG:4269","+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees"),t("EPSG:3857","+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"),t.WGS84=t["EPSG:4326"],t["EPSG:3785"]=t["EPSG:3857"],t.GOOGLE=t["EPSG:3857"],t["EPSG:900913"]=t["EPSG:3857"],t["EPSG:102113"]=t["EPSG:3857"]}(j);var G=["PROJECTEDCRS","PROJCRS","GEOGCS","GEOCCS","PROJCS","LOCAL_CS","GEODCRS","GEODETICCRS","GEODETICDATUM","ENGCRS","ENGINEERINGCRS"];var T=["3857","900913","3785","102113"];function z(t){if(!function(t){return"string"==typeof t}(t))return t;if(function(t){return t in j}(t))return j[t];if(function(t){return G.some((function(s){return t.indexOf(s)>-1}))}(t)){var s=R(t);if(function(t){var s=b(t,"authority");if(s){var i=b(s,"epsg");return i&&T.indexOf(i)>-1}}(s))return j["EPSG:3857"];var i=function(t){var s=b(t,"extension");if(s)return b(s,"proj4")}(s);return i?w(i):s}return function(t){return"+"===t[0]}(t)?w(t):void 0}function B(t,s){var i,a;if(t=t||{},!s)return t;for(a in s)void 0!==(i=s[a])&&(t[a]=i);return t}function D(t,s,i){var a=t*s;return i/Math.sqrt(1-a*a)}function F(t){return t<0?-1:1}function U(t){return Math.abs(t)<=_?t:t-F(t)*m}function Q(t,s,i){var a=t*i,h=.5*t;return a=Math.pow((1-a)/(1+a),h),Math.tan(.5*(l-s))/a}function W(t,s){for(var i,a,h=.5*t,e=l-2*Math.atan(s),r=0;r<=15;r++)if(i=t*Math.sin(e),e+=a=l-2*Math.atan(s*Math.pow((1-i)/(1+i),h))-e,Math.abs(a)<=1e-10)return e;return-9999}var Z={init:function(){var t=this.b/this.a;this.es=1-t*t,"x0"in this||(this.x0=0),"y0"in this||(this.y0=0),this.e=Math.sqrt(this.es),this.lat_ts?this.sphere?this.k0=Math.cos(this.lat_ts):this.k0=D(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts)):this.k0||(this.k?this.k0=this.k:this.k0=1)},forward:function(t){var s,i,a=t.x,h=t.y;if(h*d>90&&h*d<-90&&a*d>180&&a*d<-180)return null;if(Math.abs(Math.abs(h)-l)<=M)return null;if(this.sphere)s=this.x0+this.a*this.k0*U(a-this.long0),i=this.y0+this.a*this.k0*Math.log(Math.tan(y+.5*h));else{var e=Math.sin(h),r=Q(this.e,h,e);s=this.x0+this.a*this.k0*U(a-this.long0),i=this.y0-this.a*this.k0*Math.log(r)}return t.x=s,t.y=i,t},inverse:function(t){var s,i,a=t.x-this.x0,h=t.y-this.y0;if(this.sphere)i=l-2*Math.atan(Math.exp(-h/(this.a*this.k0)));else{var e=Math.exp(-h/(this.a*this.k0));if(-9999===(i=W(this.e,e)))return null}return s=U(this.long0+a/(this.a*this.k0)),t.x=s,t.y=i,t},names:["Mercator","Popular Visualisation Pseudo Mercator","Mercator_1SP","Mercator_Auxiliary_Sphere","merc"]};function H(t){return t}var V=[Z,{init:function(){},forward:H,inverse:H,names:["longlat","identity"]}],X={},J=[];function K(t,s){var i=J.length;return t.names?(J[i]=t,t.names.forEach((function(t){X[t.toLowerCase()]=i})),this):(console.log(s),!0)}var $={start:function(){V.forEach(K)},add:K,get:function(t){if(!t)return!1;var s=t.toLowerCase();return void 0!==X[s]&&J[X[s]]?J[X[s]]:void 0}},Y={MERIT:{a:6378137,rf:298.257,ellipseName:"MERIT 1983"},SGS85:{a:6378136,rf:298.257,ellipseName:"Soviet Geodetic System 85"},GRS80:{a:6378137,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},IAU76:{a:6378140,rf:298.257,ellipseName:"IAU 1976"},airy:{a:6377563.396,b:6356256.91,ellipseName:"Airy 1830"},APL4:{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},NWL9D:{a:6378145,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},mod_airy:{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},andrae:{a:6377104.43,rf:300,ellipseName:"Andrae 1876 (Den., Iclnd.)"},aust_SA:{a:6378160,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},GRS67:{a:6378160,rf:298.247167427,ellipseName:"GRS 67(IUGG 1967)"},bessel:{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},bess_nam:{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},clrk66:{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},clrk80:{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},clrk80ign:{a:6378249.2,b:6356515,rf:293.4660213,ellipseName:"Clarke 1880 (IGN)"},clrk58:{a:6378293.645208759,rf:294.2606763692654,ellipseName:"Clarke 1858"},CPM:{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},delmbr:{a:6376428,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},engelis:{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},evrst30:{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},evrst48:{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},evrst56:{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},evrst69:{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},evrstSS:{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},fschr60:{a:6378166,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},fschr60m:{a:6378155,rf:298.3,ellipseName:"Fischer 1960"},fschr68:{a:6378150,rf:298.3,ellipseName:"Fischer 1968"},helmert:{a:6378200,rf:298.3,ellipseName:"Helmert 1906"},hough:{a:6378270,rf:297,ellipseName:"Hough"},intl:{a:6378388,rf:297,ellipseName:"International 1909 (Hayford)"},kaula:{a:6378163,rf:298.24,ellipseName:"Kaula 1961"},lerch:{a:6378139,rf:298.257,ellipseName:"Lerch 1979"},mprts:{a:6397300,rf:191,ellipseName:"Maupertius 1738"},new_intl:{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},plessis:{a:6376523,rf:6355863,ellipseName:"Plessis 1817 (France)"},krass:{a:6378245,rf:298.3,ellipseName:"Krassovsky, 1942"},SEasia:{a:6378155,b:6356773.3205,ellipseName:"Southeast Asia"},walbeck:{a:6376896,b:6355834.8467,ellipseName:"Walbeck"},WGS60:{a:6378165,rf:298.3,ellipseName:"WGS 60"},WGS66:{a:6378145,rf:298.25,ellipseName:"WGS 66"},WGS7:{a:6378135,rf:298.26,ellipseName:"WGS 72"}},tt=Y.WGS84={a:6378137,rf:298.257223563,ellipseName:"WGS 84"};Y.sphere={a:6370997,b:6370997,ellipseName:"Normal Sphere (r=6370997)"};var st={};st.wgs84={towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},st.ch1903={towgs84:"674.374,15.056,405.346",ellipse:"bessel",datumName:"swiss"},st.ggrs87={towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},st.nad83={towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},st.nad27={nadgrids:"@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},st.potsdam={towgs84:"598.1,73.7,418.2,0.202,0.045,-2.455,6.7",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},st.carthage={towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},st.hermannskogel={towgs84:"577.326,90.129,463.919,5.137,1.474,5.297,2.4232",ellipse:"bessel",datumName:"Hermannskogel"},st.militargeographische_institut={towgs84:"577.326,90.129,463.919,5.137,1.474,5.297,2.4232",ellipse:"bessel",datumName:"Militar-Geographische Institut"},st.osni52={towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"airy",datumName:"Irish National"},st.ire65={towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},st.rassadiran={towgs84:"-133.63,-157.5,-158.62",ellipse:"intl",datumName:"Rassadiran"},st.nzgd49={towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},st.osgb36={towgs84:"446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"},st.s_jtsk={towgs84:"589,76,480",ellipse:"bessel",datumName:"S-JTSK (Ferro)"},st.beduaram={towgs84:"-106,-87,188",ellipse:"clrk80",datumName:"Beduaram"},st.gunung_segara={towgs84:"-403,684,41",ellipse:"bessel",datumName:"Gunung Segara Jakarta"},st.rnb72={towgs84:"106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",ellipse:"intl",datumName:"Reseau National Belge 1972"};var it={};function at(t){if(0===t.length)return null;var s="@"===t[0];return s&&(t=t.slice(1)),"null"===t?{name:"null",mandatory:!s,grid:null,isNull:!0}:{name:t,mandatory:!s,grid:it[t]||null,isNull:!1}}function ht(t){return t/3600*Math.PI/180}function et(t,s,i){return String.fromCharCode.apply(null,new Uint8Array(t.buffer.slice(s,i)))}function rt(t){return t.map((function(t){return[ht(t.longitudeShift),ht(t.latitudeShift)]}))}function nt(t,s,i){return{name:et(t,s+8,s+16).trim(),parent:et(t,s+24,s+24+8).trim(),lowerLatitude:t.getFloat64(s+72,i),upperLatitude:t.getFloat64(s+88,i),lowerLongitude:t.getFloat64(s+104,i),upperLongitude:t.getFloat64(s+120,i),latitudeInterval:t.getFloat64(s+136,i),longitudeInterval:t.getFloat64(s+152,i),gridNodeCount:t.getInt32(s+168,i)}}function ot(t,s,i,a){for(var h=s+176,e=[],r=0;r3&&(0===M.datum_params[3]&&0===M.datum_params[4]&&0===M.datum_params[5]&&0===M.datum_params[6]||(M.datum_type=s,M.datum_params[3]*=o,M.datum_params[4]*=o,M.datum_params[5]*=o,M.datum_params[6]=M.datum_params[6]/1e6+1))),f&&(M.datum_type=i,M.grids=f),M.a=n,M.b=l,M.es=u,M.ep2=c,M}(n.datumCode,n.datum_params,w.a,w.b,A.es,A.ep2,C);B(this,n),B(this,l),this.a=w.a,this.b=w.b,this.rf=w.rf,this.sphere=w.sphere,this.es=A.es,this.e=A.e,this.ep2=A.ep2,this.datum=N,this.init(),r(null,this)}else r(e)}else r(e)}function ut(t,s,i){var a,h,e,r,n=t.x,o=t.y,u=t.z?t.z:0;if(o<-l&&o>-1.001*l)o=-l;else if(o>l&&o<1.001*l)o=l;else{if(o<-l)return{x:-1/0,y:-1/0,z:t.z};if(o>l)return{x:1/0,y:1/0,z:t.z}}return n>Math.PI&&(n-=2*Math.PI),h=Math.sin(o),r=Math.cos(o),e=h*h,{x:((a=i/Math.sqrt(1-s*e))+u)*r*Math.cos(n),y:(a+u)*r*Math.sin(n),z:(a*(1-s)+u)*h}}function ct(t,s,i,a){var h,e,r,n,o,u,c,f,M,p,d,y,m,_,g,x=1e-12,v=t.x,b=t.y,w=t.z?t.z:0;if(h=Math.sqrt(v*v+b*b),e=Math.sqrt(v*v+b*b+w*w),h/i1e-24&&m<30);return{x:_,y:Math.atan(d/Math.abs(p)),z:g}}function ft(i){return i===t||i===s}function Mt(a,o,l){if(function(i,a){return i.datum_type===a.datum_type&&!(i.a!==a.a||Math.abs(i.es-a.es)>5e-11)&&(i.datum_type===t?i.datum_params[0]===a.datum_params[0]&&i.datum_params[1]===a.datum_params[1]&&i.datum_params[2]===a.datum_params[2]:i.datum_type!==s||i.datum_params[0]===a.datum_params[0]&&i.datum_params[1]===a.datum_params[1]&&i.datum_params[2]===a.datum_params[2]&&i.datum_params[3]===a.datum_params[3]&&i.datum_params[4]===a.datum_params[4]&&i.datum_params[5]===a.datum_params[5]&&i.datum_params[6]===a.datum_params[6])}(a,o))return l;if(a.datum_type===h||o.datum_type===h)return l;var u=a.a,c=a.es;if(a.datum_type===i){if(0!==pt(a,!1,l))return;u=e,c=n}var f=o.a,M=o.b,p=o.es;if(o.datum_type===i&&(f=e,M=r,p=n),c===p&&u===f&&!ft(a.datum_type)&&!ft(o.datum_type))return l;if((l=ut(l,c,u),ft(a.datum_type)&&(l=function(i,a,h){if(a===t)return{x:i.x+h[0],y:i.y+h[1],z:i.z+h[2]};if(a===s){var e=h[0],r=h[1],n=h[2],o=h[3],l=h[4],u=h[5],c=h[6];return{x:c*(i.x-u*i.y+l*i.z)+e,y:c*(u*i.x+i.y-o*i.z)+r,z:c*(-l*i.x+o*i.y+i.z)+n}}}(l,a.datum_type,a.datum_params)),ft(o.datum_type)&&(l=function(i,a,h){if(a===t)return{x:i.x-h[0],y:i.y-h[1],z:i.z-h[2]};if(a===s){var e=h[0],r=h[1],n=h[2],o=h[3],l=h[4],u=h[5],c=h[6],f=(i.x-e)/c,M=(i.y-r)/c,p=(i.z-n)/c;return{x:f+u*M-l*p,y:-u*f+M+o*p,z:l*f-o*M+p}}}(l,o.datum_type,o.datum_params)),l=ct(l,p,f,M),o.datum_type===i)&&0!==pt(o,!0,l))return;return l}function pt(t,s,i){if(null===t.grids||0===t.grids.length)return console.log("Grid shift grids not found"),-1;var a={x:-i.x,y:i.y},h={x:Number.NaN,y:Number.NaN},e=[];t:for(var r=0;ra.y||M>a.x||m1e-12&&Math.abs(r.y)>1e-12);if(o<0)return console.log("Inverse grid shift iterator failed to converge."),a;a.x=U(e.x+i.ll[0]),a.y=e.y+i.ll[1]}else isNaN(e.x)||(a.x=t.x+e.x,a.y=t.y+e.y);return a}function yt(t,s){var i,a={x:t.x/s.del[0],y:t.y/s.del[1]},h=Math.floor(a.x),e=Math.floor(a.y),r=a.x-1*h,n=a.y-1*e,o={x:Number.NaN,y:Number.NaN};if(h<0||h>=s.lim[0])return o;if(e<0||e>=s.lim[1])return o;i=e*s.lim[0]+h;var l=s.cvs[i][0],u=s.cvs[i][1];i++;var c=s.cvs[i][0],f=s.cvs[i][1];i+=s.lim[0];var M=s.cvs[i][0],p=s.cvs[i][1];i--;var d=s.cvs[i][0],y=s.cvs[i][1],m=r*n,_=r*(1-n),g=(1-r)*(1-n),x=(1-r)*n;return o.x=g*l+_*c+x*d+m*M,o.y=g*u+_*f+x*y+m*p,o}function mt(t,s,i){var a,h,e,r=i.x,n=i.y,o=i.z||0,l={};for(e=0;e<3;e++)if(!s||2!==e||void 0!==i.z)switch(0===e?(a=r,h=-1!=="ew".indexOf(t.axis[e])?"x":"y"):1===e?(a=n,h=-1!=="ns".indexOf(t.axis[e])?"y":"x"):(a=o,h="z"),t.axis[e]){case"e":case"n":l[h]=a;break;case"w":case"s":l[h]=-a;break;case"u":void 0!==i[h]&&(l.z=a);break;case"d":void 0!==i[h]&&(l.z=-a);break;default:return null}return l}function _t(t){var s={x:t[0],y:t[1]};return t.length>2&&(s.z=t[2]),t.length>3&&(s.m=t[3]),s}function gt(t){if("function"==typeof Number.isFinite){if(Number.isFinite(t))return;throw new TypeError("coordinates must be finite numbers")}if("number"!=typeof t||t!=t||!isFinite(t))throw new TypeError("coordinates must be finite numbers")}function xt(a,h,e,r){var n,o=void 0!==(e=Array.isArray(e)?_t(e):{x:e.x,y:e.y,z:e.z,m:e.m}).z;if(function(t){gt(t.x),gt(t.y)}(e),a.datum&&h.datum&&function(a,h){return(a.datum.datum_type===t||a.datum.datum_type===s||a.datum.datum_type===i)&&"WGS84"!==h.datumCode||(h.datum.datum_type===t||h.datum.datum_type===s||h.datum.datum_type===i)&&"WGS84"!==a.datumCode}(a,h)&&(e=xt(a,n=new lt("WGS84"),e,r),a=n),r&&"enu"!==a.axis&&(e=mt(a,!1,e)),"longlat"===a.projName)e={x:e.x*p,y:e.y*p,z:e.z||0};else if(a.to_meter&&(e={x:e.x*a.to_meter,y:e.y*a.to_meter,z:e.z||0}),!(e=a.inverse(e)))return;if(a.from_greenwich&&(e.x+=a.from_greenwich),e=Mt(a.datum,h.datum,e))return h.from_greenwich&&(e={x:e.x-h.from_greenwich,y:e.y,z:e.z||0}),"longlat"===h.projName?e={x:e.x*d,y:e.y*d,z:e.z||0}:(e=h.forward(e),h.to_meter&&(e={x:e.x/h.to_meter,y:e.y/h.to_meter,z:e.z||0})),r&&"enu"!==h.axis?mt(h,!0,e):(e&&!o&&delete e.z,e)}lt.projections=$,lt.projections.start();var vt=lt("WGS84");function bt(t,s,i,a){var h,e,r;return Array.isArray(i)?(h=xt(t,s,i,a)||{x:NaN,y:NaN},i.length>2?void 0!==t.name&&"geocent"===t.name||void 0!==s.name&&"geocent"===s.name?"number"==typeof h.z?[h.x,h.y,h.z].concat(i.splice(3)):[h.x,h.y,i[2]].concat(i.splice(3)):[h.x,h.y].concat(i.splice(2)):[h.x,h.y]):(e=xt(t,s,i,a),2===(r=Object.keys(i)).length||r.forEach((function(a){if(void 0!==t.name&&"geocent"===t.name||void 0!==s.name&&"geocent"===s.name){if("x"===a||"y"===a||"z"===a)return}else if("x"===a||"y"===a)return;e[a]=i[a]})),e)}function wt(t){return t instanceof lt?t:t.oProj?t.oProj:lt(t)}function At(t,s,i){t=wt(t);var a,h=!1;return void 0===s?(s=t,t=vt,h=!0):(void 0!==s.x||Array.isArray(s))&&(i=s,s=t,t=vt,h=!0),s=wt(s),i?bt(t,s,i):(a={forward:function(i,a){return bt(t,s,i,a)},inverse:function(i,a){return bt(s,t,i,a)}},h&&(a.oProj=s),a)}var Ct=6,Nt="AJSAJS",Pt="AFAFAF",Et=65,St=73,It=79,kt=86,Ot=90,qt={forward:Lt,inverse:function(t){var s=Tt(Dt(t.toUpperCase()));if(s.lat&&s.lon)return[s.lon,s.lat,s.lon,s.lat];return[s.left,s.bottom,s.right,s.top]},toPoint:Rt};function Lt(t,s){return s=s||5,function(t,s){var i="00000"+t.easting,a="00000"+t.northing;return t.zoneNumber+t.zoneLetter+(M=t.easting,p=t.northing,d=t.zoneNumber,y=Bt(d),m=Math.floor(M/1e5),_=Math.floor(p/1e5)%20,h=m,e=_,r=y,n=r-1,o=Nt.charCodeAt(n),l=Pt.charCodeAt(n),u=o+h-1,c=l+e,f=!1,u>Ot&&(u=u-Ot+Et-1,f=!0),(u===St||oSt||(u>St||oIt||(u>It||oOt&&(u=u-Ot+Et-1),c>kt?(c=c-kt+Et-1,f=!0):f=!1,(c===St||lSt||(c>St||lIt||(c>It||lkt&&(c=c-kt+Et-1),String.fromCharCode(u)+String.fromCharCode(c))+i.substr(i.length-5,s)+a.substr(a.length-5,s);var h,e,r,n,o,l,u,c,f;var M,p,d,y,m,_}(function(t){var s,i,a,h,e,r,n,o,l=t.lat,u=t.lon,c=6378137,f=.00669438,M=.9996,p=jt(l),d=jt(u);o=Math.floor((u+180)/6)+1,180===u&&(o=60);l>=56&&l<64&&u>=3&&u<12&&(o=32);l>=72&&l<84&&(u>=0&&u<9?o=31:u>=9&&u<21?o=33:u>=21&&u<33?o=35:u>=33&&u<42&&(o=37));n=jt(6*(o-1)-180+3),s=f/(1-f),i=c/Math.sqrt(1-f*Math.sin(p)*Math.sin(p)),a=Math.tan(p)*Math.tan(p),h=s*Math.cos(p)*Math.cos(p),e=Math.cos(p)*(d-n),r=c*((1-f/4-3*f*f/64-5*f*f*f/256)*p-(3*f/8+3*f*f/32+45*f*f*f/1024)*Math.sin(2*p)+(15*f*f/256+45*f*f*f/1024)*Math.sin(4*p)-35*f*f*f/3072*Math.sin(6*p));var y=M*i*(e+(1-a+h)*e*e*e/6+(5-18*a+a*a+72*h-58*s)*e*e*e*e*e/120)+5e5,m=M*(r+i*Math.tan(p)*(e*e/2+(5-a+9*h+4*h*h)*e*e*e*e/24+(61-58*a+a*a+600*h-330*s)*e*e*e*e*e*e/720));l<0&&(m+=1e7);return{northing:Math.round(m),easting:Math.round(y),zoneNumber:o,zoneLetter:zt(l)}}({lat:t[1],lon:t[0]}),s)}function Rt(t){var s=Tt(Dt(t.toUpperCase()));return s.lat&&s.lon?[s.lon,s.lat]:[(s.left+s.right)/2,(s.top+s.bottom)/2]}function jt(t){return t*(Math.PI/180)}function Gt(t){return t/Math.PI*180}function Tt(t){var s=t.northing,i=t.easting,a=t.zoneLetter,h=t.zoneNumber;if(h<0||h>60)return null;var e,r,n,o,l,u,c,f,M,p=.9996,d=6378137,y=.00669438,m=(1-Math.sqrt(.99330562))/(1+Math.sqrt(.99330562)),_=i-5e5,g=s;a<"N"&&(g-=1e7),c=6*(h-1)-180+3,e=.006739496752268451,M=(f=g/p/6367449.145945056)+(3*m/2-27*m*m*m/32)*Math.sin(2*f)+(21*m*m/16-55*m*m*m*m/32)*Math.sin(4*f)+151*m*m*m/96*Math.sin(6*f),r=d/Math.sqrt(1-y*Math.sin(M)*Math.sin(M)),n=Math.tan(M)*Math.tan(M),o=e*Math.cos(M)*Math.cos(M),l=.99330562*d/Math.pow(1-y*Math.sin(M)*Math.sin(M),1.5),u=_/(r*p);var x=M-r*Math.tan(M)/l*(u*u/2-(5+3*n+10*o-4*o*o-9*e)*u*u*u*u/24+(61+90*n+298*o+45*n*n-1.6983531815716497-3*o*o)*u*u*u*u*u*u/720);x=Gt(x);var v,b=(u-(1+2*n+o)*u*u*u/6+(5-2*o+28*n-3*o*o+8*e+24*n*n)*u*u*u*u*u/120)/Math.cos(M);if(b=c+Gt(b),t.accuracy){var w=Tt({northing:t.northing+t.accuracy,easting:t.easting+t.accuracy,zoneLetter:t.zoneLetter,zoneNumber:t.zoneNumber});v={top:w.lat,right:w.lon,bottom:x,left:b}}else v={lat:x,lon:b};return v}function zt(t){var s="Z";return 84>=t&&t>=72?s="X":72>t&&t>=64?s="W":64>t&&t>=56?s="V":56>t&&t>=48?s="U":48>t&&t>=40?s="T":40>t&&t>=32?s="S":32>t&&t>=24?s="R":24>t&&t>=16?s="Q":16>t&&t>=8?s="P":8>t&&t>=0?s="N":0>t&&t>=-8?s="M":-8>t&&t>=-16?s="L":-16>t&&t>=-24?s="K":-24>t&&t>=-32?s="J":-32>t&&t>=-40?s="H":-40>t&&t>=-48?s="G":-48>t&&t>=-56?s="F":-56>t&&t>=-64?s="E":-64>t&&t>=-72?s="D":-72>t&&t>=-80&&(s="C"),s}function Bt(t){var s=t%Ct;return 0===s&&(s=Ct),s}function Dt(t){if(t&&0===t.length)throw"MGRSPoint coverting from nothing";for(var s,i=t.length,a=null,h="",e=0;!/[A-Z]/.test(s=t.charAt(e));){if(e>=2)throw"MGRSPoint bad conversion from: "+t;h+=s,e++}var r=parseInt(h,10);if(0===e||e+3>i)throw"MGRSPoint bad conversion from: "+t;var n=t.charAt(e++);if(n<="A"||"B"===n||"Y"===n||n>="Z"||"I"===n||"O"===n)throw"MGRSPoint zone letter "+n+" not handled: "+t;a=t.substring(e,e+=2);for(var o=Bt(r),l=function(t,s){var i=Nt.charCodeAt(s-1),a=1e5,h=!1;for(;i!==t.charCodeAt(0);){if(++i===St&&i++,i===It&&i++,i>Ot){if(h)throw"Bad character: "+t;i=Et,h=!0}a+=1e5}return a}(a.charAt(0),o),u=function(t,s){if(t>"V")throw"MGRSPoint given invalid Northing "+t;var i=Pt.charCodeAt(s-1),a=0,h=!1;for(;i!==t.charCodeAt(0);){if(++i===St&&i++,i===It&&i++,i>kt){if(h)throw"Bad character: "+t;i=Et,h=!0}a+=1e5}return a}(a.charAt(1),o);u0&&(f=1e5/Math.pow(10,d),M=t.substring(e,e+d),y=parseFloat(M)*f,p=t.substring(e+d),m=parseFloat(p)*f),{easting:y+l,northing:m+u,zoneLetter:n,zoneNumber:r,accuracy:f}}function Ft(t){var s;switch(t){case"C":s=11e5;break;case"D":s=2e6;break;case"E":s=28e5;break;case"F":s=37e5;break;case"G":s=46e5;break;case"H":s=55e5;break;case"J":s=64e5;break;case"K":s=73e5;break;case"L":s=82e5;break;case"M":s=91e5;break;case"N":s=0;break;case"P":s=8e5;break;case"Q":s=17e5;break;case"R":s=26e5;break;case"S":s=35e5;break;case"T":s=44e5;break;case"U":s=53e5;break;case"V":s=62e5;break;case"W":s=7e6;break;case"X":s=79e5;break;default:s=-1}if(s>=0)return s;throw"Invalid zone letter: "+t}function Ut(t,s,i){if(!(this instanceof Ut))return new Ut(t,s,i);if(Array.isArray(t))this.x=t[0],this.y=t[1],this.z=t[2]||0;else if("object"==typeof t)this.x=t.x,this.y=t.y,this.z=t.z||0;else if("string"==typeof t&&void 0===s){var a=t.split(",");this.x=parseFloat(a[0],10),this.y=parseFloat(a[1],10),this.z=parseFloat(a[2],10)||0}else this.x=t,this.y=s,this.z=i||0;console.warn("proj4.Point will be removed in version 3, use proj4.toPoint")}Ut.fromMGRS=function(t){return new Ut(Rt(t))},Ut.prototype.toMGRS=function(t){return Lt([this.x,this.y],t)};var Qt=1,Wt=.25,Zt=.046875,Ht=.01953125,Vt=.01068115234375,Xt=.75,Jt=.46875,Kt=.013020833333333334,$t=.007120768229166667,Yt=.3645833333333333,ts=.005696614583333333,ss=.3076171875;function is(t){var s=[];s[0]=Qt-t*(Wt+t*(Zt+t*(Ht+t*Vt))),s[1]=t*(Xt-t*(Zt+t*(Ht+t*Vt)));var i=t*t;return s[2]=i*(Jt-t*(Kt+t*$t)),i*=t,s[3]=i*(Yt-t*ts),s[4]=i*t*ss,s}function as(t,s,i,a){return i*=s,s*=s,a[0]*t-i*(a[1]+s*(a[2]+s*(a[3]+s*a[4])))}var hs=20;function es(t,s,i){for(var a=1/(1-s),h=t,e=hs;e;--e){var r=Math.sin(h),n=1-s*r*r;if(h-=n=(as(h,r,Math.cos(h),i)-t)*(n*Math.sqrt(n))*a,Math.abs(n)M?Math.tan(e):0,d=Math.pow(p,2),y=Math.pow(d,2);s=1-this.es*Math.pow(n,2),l/=Math.sqrt(s);var m=as(e,n,o,this.en);i=this.a*(this.k0*l*(1+u/6*(1-d+c+u/20*(5-18*d+y+14*c-58*d*c+u/42*(61+179*y-y*d-479*d)))))+this.x0,a=this.a*(this.k0*(m-this.ml0+n*r*l/2*(1+u/12*(5-d+9*c+4*f+u/30*(61+y-58*d+270*c-330*d*c+u/56*(1385+543*y-y*d-3111*d))))))+this.y0}else{var _=o*Math.sin(r);if(Math.abs(Math.abs(_)-1)=1){if(_-1>M)return 93;a=0}else a=Math.acos(a);e<0&&(a=-a),a=this.a*this.k0*(a-this.lat0)+this.y0}return t.x=i,t.y=a,t},inverse:function(t){var s,i,a,h,e=(t.x-this.x0)*(1/this.a),r=(t.y-this.y0)*(1/this.a);if(this.es)if(i=es(s=this.ml0+r/this.k0,this.es,this.en),Math.abs(i)M?Math.tan(i):0,c=this.ep2*Math.pow(o,2),f=Math.pow(c,2),p=Math.pow(u,2),d=Math.pow(p,2);s=1-this.es*Math.pow(n,2);var y=e*Math.sqrt(s)/this.k0,m=Math.pow(y,2);a=i-(s*=u)*m/(1-this.es)*.5*(1-m/12*(5+3*p-9*c*p+c-4*f-m/30*(61+90*p-252*c*p+45*d+46*c-m/56*(1385+3633*p+4095*d+1574*d*p)))),h=U(this.long0+y*(1-m/6*(1+2*p+c-m/20*(5+28*p+24*d+8*c*p+6*c-m/42*(61+662*p+1320*d+720*d*p))))/o)}else a=l*F(r),h=0;else{var _=Math.exp(e/this.k0),g=.5*(_-1/_),x=this.lat0+r/this.k0,v=Math.cos(x);s=Math.sqrt((1-Math.pow(v,2))/(1+Math.pow(g,2))),a=Math.asin(s),r<0&&(a=-a),h=0===g&&0===v?0:U(Math.atan2(g,v)+this.long0)}return t.x=h,t.y=a,t},names:["Fast_Transverse_Mercator","Fast Transverse Mercator"]};function ns(t){var s=Math.exp(t);return s=(s-1/s)/2}function os(t,s){t=Math.abs(t),s=Math.abs(s);var i=Math.max(t,s),a=Math.min(t,s)/(i||1);return i*Math.sqrt(1+Math.pow(a,2))}function ls(t){var s=Math.abs(t);return s=function(t){var s=1+t,i=s-1;return 0===i?t:t*Math.log(s)/i}(s*(1+s/(os(1,s)+1))),t<0?-s:s}function us(t,s){for(var i,a=2*Math.cos(2*s),h=t.length-1,e=t[h],r=0;--h>=0;)i=a*e-r+t[h],r=e,e=i;return s+i*Math.sin(2*s)}function cs(t,s,i){for(var a,h,e=Math.sin(s),r=Math.cos(s),n=ns(i),o=function(t){var s=Math.exp(t);return(s+1/s)/2}(i),l=2*r*o,u=-2*e*n,c=t.length-1,f=t[c],M=0,p=0,d=0;--c>=0;)a=p,h=M,f=l*(p=f)-a-u*(M=d)+t[c],d=u*p-h+l*M;return[(l=e*o)*f-(u=r*n)*d,l*d+u*f]}var fs={init:function(){if(!this.approx&&(isNaN(this.es)||this.es<=0))throw new Error('Incorrect elliptical usage. Try using the +approx option in the proj string, or PROJECTION["Fast_Transverse_Mercator"] in the WKT.');this.approx&&(rs.init.apply(this),this.forward=rs.forward,this.inverse=rs.inverse),this.x0=void 0!==this.x0?this.x0:0,this.y0=void 0!==this.y0?this.y0:0,this.long0=void 0!==this.long0?this.long0:0,this.lat0=void 0!==this.lat0?this.lat0:0,this.cgb=[],this.cbg=[],this.utg=[],this.gtu=[];var t=this.es/(1+Math.sqrt(1-this.es)),s=t/(2-t),i=s;this.cgb[0]=s*(2+s*(-2/3+s*(s*(116/45+s*(26/45+s*(-2854/675)))-2))),this.cbg[0]=s*(s*(2/3+s*(4/3+s*(-82/45+s*(32/45+s*(4642/4725)))))-2),i*=s,this.cgb[1]=i*(7/3+s*(s*(-227/45+s*(2704/315+s*(2323/945)))-1.6)),this.cbg[1]=i*(5/3+s*(-16/15+s*(-13/9+s*(904/315+s*(-1522/945))))),i*=s,this.cgb[2]=i*(56/15+s*(-136/35+s*(-1262/105+s*(73814/2835)))),this.cbg[2]=i*(-26/15+s*(34/21+s*(1.6+s*(-12686/2835)))),i*=s,this.cgb[3]=i*(4279/630+s*(-332/35+s*(-399572/14175))),this.cbg[3]=i*(1237/630+s*(s*(-24832/14175)-2.4)),i*=s,this.cgb[4]=i*(4174/315+s*(-144838/6237)),this.cbg[4]=i*(-734/315+s*(109598/31185)),i*=s,this.cgb[5]=i*(601676/22275),this.cbg[5]=i*(444337/155925),i=Math.pow(s,2),this.Qn=this.k0/(1+s)*(1+i*(1/4+i*(1/64+i/256))),this.utg[0]=s*(s*(2/3+s*(-37/96+s*(1/360+s*(81/512+s*(-96199/604800)))))-.5),this.gtu[0]=s*(.5+s*(-2/3+s*(5/16+s*(41/180+s*(-127/288+s*(7891/37800)))))),this.utg[1]=i*(-1/48+s*(-1/15+s*(437/1440+s*(-46/105+s*(1118711/3870720))))),this.gtu[1]=i*(13/48+s*(s*(557/1440+s*(281/630+s*(-1983433/1935360)))-.6)),i*=s,this.utg[2]=i*(-17/480+s*(37/840+s*(209/4480+s*(-5569/90720)))),this.gtu[2]=i*(61/240+s*(-103/140+s*(15061/26880+s*(167603/181440)))),i*=s,this.utg[3]=i*(-4397/161280+s*(11/504+s*(830251/7257600))),this.gtu[3]=i*(49561/161280+s*(-179/168+s*(6601661/7257600))),i*=s,this.utg[4]=i*(-4583/161280+s*(108847/3991680)),this.gtu[4]=i*(34729/80640+s*(-3418889/1995840)),i*=s,this.utg[5]=i*(-20648693/638668800),this.gtu[5]=.6650675310896665*i;var a=us(this.cbg,this.lat0);this.Zb=-this.Qn*(a+function(t,s){for(var i,a=2*Math.cos(s),h=t.length-1,e=t[h],r=0;--h>=0;)i=a*e-r+t[h],r=e,e=i;return Math.sin(s)*i}(this.gtu,2*a))},forward:function(t){var s=U(t.x-this.long0),i=t.y;i=us(this.cbg,i);var a=Math.sin(i),h=Math.cos(i),e=Math.sin(s),r=Math.cos(s);i=Math.atan2(a,r*h),s=Math.atan2(e*h,os(a,h*r)),s=ls(Math.tan(s));var n,o,l=cs(this.gtu,2*i,2*s);return i+=l[0],s+=l[1],Math.abs(s)<=2.623395162778?(n=this.a*(this.Qn*s)+this.x0,o=this.a*(this.Qn*i+this.Zb)+this.y0):(n=1/0,o=1/0),t.x=n,t.y=o,t},inverse:function(t){var s,i,a=(t.x-this.x0)*(1/this.a),h=(t.y-this.y0)*(1/this.a);if(h=(h-this.Zb)/this.Qn,a/=this.Qn,Math.abs(a)<=2.623395162778){var e=cs(this.utg,2*h,2*a);h+=e[0],a+=e[1],a=Math.atan(ns(a));var r=Math.sin(h),n=Math.cos(h),o=Math.sin(a),l=Math.cos(a);h=Math.atan2(r*l,os(o,l*n)),s=U((a=Math.atan2(o,l*n))+this.long0),i=us(this.cgb,h)}else s=1/0,i=1/0;return t.x=s,t.y=i,t},names:["Extended_Transverse_Mercator","Extended Transverse Mercator","etmerc","Transverse_Mercator","Transverse Mercator","Gauss Kruger","Gauss_Kruger","tmerc"]};var Ms={init:function(){var t=function(t,s){if(void 0===t){if((t=Math.floor(30*(U(s)+Math.PI)/Math.PI)+1)<0)return 0;if(t>60)return 60}return t}(this.zone,this.long0);if(void 0===t)throw new Error("unknown utm zone");this.lat0=0,this.long0=(6*Math.abs(t)-183)*p,this.x0=5e5,this.y0=this.utmSouth?1e7:0,this.k0=.9996,fs.init.apply(this),this.forward=fs.forward,this.inverse=fs.inverse},names:["Universal Transverse Mercator System","utm"],dependsOn:"etmerc"};function ps(t,s){return Math.pow((1-t)/(1+t),s)}var ds={init:function(){var t=Math.sin(this.lat0),s=Math.cos(this.lat0);s*=s,this.rc=Math.sqrt(1-this.es)/(1-this.es*t*t),this.C=Math.sqrt(1+this.es*s*s/(1-this.es)),this.phic0=Math.asin(t/this.C),this.ratexp=.5*this.C*this.e,this.K=Math.tan(.5*this.phic0+y)/(Math.pow(Math.tan(.5*this.lat0+y),this.C)*ps(this.e*t,this.ratexp))},forward:function(t){var s=t.x,i=t.y;return t.y=2*Math.atan(this.K*Math.pow(Math.tan(.5*i+y),this.C)*ps(this.e*Math.sin(i),this.ratexp))-l,t.x=this.C*s,t},inverse:function(t){for(var s=t.x/this.C,i=t.y,a=Math.pow(Math.tan(.5*i+y)/this.K,1/this.C),h=20;h>0&&(i=2*Math.atan(a*ps(this.e*Math.sin(t.y),-.5*this.e))-l,!(Math.abs(i-t.y)<1e-14));--h)t.y=i;return h?(t.x=s,t.y=i,t):null},names:["gauss"]};var ys={init:function(){ds.init.apply(this),this.rc&&(this.sinc0=Math.sin(this.phic0),this.cosc0=Math.cos(this.phic0),this.R2=2*this.rc,this.title||(this.title="Oblique Stereographic Alternative"))},forward:function(t){var s,i,a,h;return t.x=U(t.x-this.long0),ds.forward.apply(this,[t]),s=Math.sin(t.y),i=Math.cos(t.y),a=Math.cos(t.x),h=this.k0*this.R2/(1+this.sinc0*s+this.cosc0*i*a),t.x=h*i*Math.sin(t.x),t.y=h*(this.cosc0*s-this.sinc0*i*a),t.x=this.a*t.x+this.x0,t.y=this.a*t.y+this.y0,t},inverse:function(t){var s,i,a,h,e;if(t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,t.x/=this.k0,t.y/=this.k0,e=os(t.x,t.y)){var r=2*Math.atan2(e,this.R2);s=Math.sin(r),i=Math.cos(r),h=Math.asin(i*this.sinc0+t.y*s*this.cosc0/e),a=Math.atan2(t.x*s,e*this.cosc0*i-t.y*this.sinc0*s)}else h=this.phic0,a=0;return t.x=a,t.y=h,ds.inverse.apply(this,[t]),t.x=U(t.x+this.long0),t},names:["Stereographic_North_Pole","Oblique_Stereographic","sterea","Oblique Stereographic Alternative","Double_Stereographic"]};var ms={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.lat0=this.lat0||0,this.long0=this.long0||0,this.coslat0=Math.cos(this.lat0),this.sinlat0=Math.sin(this.lat0),this.sphere?1===this.k0&&!isNaN(this.lat_ts)&&Math.abs(this.coslat0)<=M&&(this.k0=.5*(1+F(this.lat0)*Math.sin(this.lat_ts))):(Math.abs(this.coslat0)<=M&&(this.lat0>0?this.con=1:this.con=-1),this.cons=Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e)),1===this.k0&&!isNaN(this.lat_ts)&&Math.abs(this.coslat0)<=M&&Math.abs(Math.cos(this.lat_ts))>M&&(this.k0=.5*this.cons*D(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts))/Q(this.e,this.con*this.lat_ts,this.con*Math.sin(this.lat_ts))),this.ms1=D(this.e,this.sinlat0,this.coslat0),this.X0=2*Math.atan(this.ssfn_(this.lat0,this.sinlat0,this.e))-l,this.cosX0=Math.cos(this.X0),this.sinX0=Math.sin(this.X0))},forward:function(t){var s,i,a,h,e,r,n=t.x,o=t.y,u=Math.sin(o),c=Math.cos(o),f=U(n-this.long0);return Math.abs(Math.abs(n-this.long0)-Math.PI)<=M&&Math.abs(o+this.lat0)<=M?(t.x=NaN,t.y=NaN,t):this.sphere?(s=2*this.k0/(1+this.sinlat0*u+this.coslat0*c*Math.cos(f)),t.x=this.a*s*c*Math.sin(f)+this.x0,t.y=this.a*s*(this.coslat0*u-this.sinlat0*c*Math.cos(f))+this.y0,t):(i=2*Math.atan(this.ssfn_(o,u,this.e))-l,h=Math.cos(i),a=Math.sin(i),Math.abs(this.coslat0)<=M?(e=Q(this.e,o*this.con,this.con*u),r=2*this.a*this.k0*e/this.cons,t.x=this.x0+r*Math.sin(n-this.long0),t.y=this.y0-this.con*r*Math.cos(n-this.long0),t):(Math.abs(this.sinlat0)0?U(this.long0+Math.atan2(t.x,-1*t.y)):U(this.long0+Math.atan2(t.x,t.y)):U(this.long0+Math.atan2(t.x*Math.sin(n),r*this.coslat0*Math.cos(n)-t.y*this.sinlat0*Math.sin(n))),t.x=s,t.y=i,t)}if(Math.abs(this.coslat0)<=M){if(r<=M)return i=this.lat0,s=this.long0,t.x=s,t.y=i,t;t.x*=this.con,t.y*=this.con,a=r*this.cons/(2*this.a*this.k0),i=this.con*W(this.e,a),s=this.con*U(this.con*this.long0+Math.atan2(t.x,-1*t.y))}else h=2*Math.atan(r*this.cosX0/(2*this.a*this.k0*this.ms1)),s=this.long0,r<=M?e=this.X0:(e=Math.asin(Math.cos(h)*this.sinX0+t.y*Math.sin(h)*this.cosX0/r),s=U(this.long0+Math.atan2(t.x*Math.sin(h),r*this.cosX0*Math.cos(h)-t.y*this.sinX0*Math.sin(h)))),i=-1*W(this.e,Math.tan(.5*(l+e)));return t.x=s,t.y=i,t},names:["stere","Stereographic_South_Pole","Polar Stereographic (variant B)","Polar_Stereographic"],ssfn_:function(t,s,i){return s*=i,Math.tan(.5*(l+t))*Math.pow((1-s)/(1+s),.5*i)}};var _s={init:function(){var t=this.lat0;this.lambda0=this.long0;var s=Math.sin(t),i=this.a,a=1/this.rf,h=2*a-Math.pow(a,2),e=this.e=Math.sqrt(h);this.R=this.k0*i*Math.sqrt(1-h)/(1-h*Math.pow(s,2)),this.alpha=Math.sqrt(1+h/(1-h)*Math.pow(Math.cos(t),4)),this.b0=Math.asin(s/this.alpha);var r=Math.log(Math.tan(Math.PI/4+this.b0/2)),n=Math.log(Math.tan(Math.PI/4+t/2)),o=Math.log((1+e*s)/(1-e*s));this.K=r-this.alpha*n+this.alpha*e/2*o},forward:function(t){var s=Math.log(Math.tan(Math.PI/4-t.y/2)),i=this.e/2*Math.log((1+this.e*Math.sin(t.y))/(1-this.e*Math.sin(t.y))),a=-this.alpha*(s+i)+this.K,h=2*(Math.atan(Math.exp(a))-Math.PI/4),e=this.alpha*(t.x-this.lambda0),r=Math.atan(Math.sin(e)/(Math.sin(this.b0)*Math.tan(h)+Math.cos(this.b0)*Math.cos(e))),n=Math.asin(Math.cos(this.b0)*Math.sin(h)-Math.sin(this.b0)*Math.cos(h)*Math.cos(e));return t.y=this.R/2*Math.log((1+Math.sin(n))/(1-Math.sin(n)))+this.y0,t.x=this.R*r+this.x0,t},inverse:function(t){for(var s=t.x-this.x0,i=t.y-this.y0,a=s/this.R,h=2*(Math.atan(Math.exp(i/this.R))-Math.PI/4),e=Math.asin(Math.cos(this.b0)*Math.sin(h)+Math.sin(this.b0)*Math.cos(h)*Math.cos(a)),r=Math.atan(Math.sin(a)/(Math.cos(this.b0)*Math.cos(a)-Math.sin(this.b0)*Math.tan(h))),n=this.lambda0+r/this.alpha,o=0,l=e,u=-1e3,c=0;Math.abs(l-u)>1e-7;){if(++c>20)return;o=1/this.alpha*(Math.log(Math.tan(Math.PI/4+e/2))-this.K)+this.e*Math.log(Math.tan(Math.PI/4+Math.asin(this.e*Math.sin(l))/2)),u=l,l=2*Math.atan(Math.exp(o))-Math.PI/2}return t.x=n,t.y=l,t},names:["somerc"]},gs=1e-7;var xs={init:function(){var t,s,i,a,h,e,r,n,o,u,c,f,d,_=0,g=0,x=0,v=0,b=0,w=0,A=0;this.no_off=(d="object"==typeof(f=this).PROJECTION?Object.keys(f.PROJECTION)[0]:f.PROJECTION,"no_uoff"in f||"no_off"in f||-1!==["Hotine_Oblique_Mercator","Hotine_Oblique_Mercator_Azimuth_Natural_Origin"].indexOf(d)),this.no_rot="no_rot"in this;var C=!1;"alpha"in this&&(C=!0);var N=!1;if("rectified_grid_angle"in this&&(N=!0),C&&(A=this.alpha),N&&(_=this.rectified_grid_angle*p),C||N)g=this.longc;else if(x=this.long1,b=this.lat1,v=this.long2,w=this.lat2,Math.abs(b-w)<=gs||(t=Math.abs(b))<=gs||Math.abs(t-l)<=gs||Math.abs(Math.abs(this.lat0)-l)<=gs||Math.abs(Math.abs(w)-l)<=gs)throw new Error;var P=1-this.es;s=Math.sqrt(P),Math.abs(this.lat0)>M?(n=Math.sin(this.lat0),i=Math.cos(this.lat0),t=1-this.es*n*n,this.B=i*i,this.B=Math.sqrt(1+this.es*this.B*this.B/P),this.A=this.B*this.k0*s/t,(h=(a=this.B*s/(i*Math.sqrt(t)))*a-1)<=0?h=0:(h=Math.sqrt(h),this.lat0<0&&(h=-h)),this.E=h+=a,this.E*=Math.pow(Q(this.e,this.lat0,n),this.B)):(this.B=1/s,this.A=this.k0,this.E=a=h=1),C||N?(C?(c=Math.asin(Math.sin(A)/a),N||(_=A)):(c=_,A=Math.asin(a*Math.sin(c))),this.lam0=g-Math.asin(.5*(h-1/h)*Math.tan(c))/this.B):(e=Math.pow(Q(this.e,b,Math.sin(b)),this.B),r=Math.pow(Q(this.e,w,Math.sin(w)),this.B),h=this.E/e,o=(r-e)/(r+e),u=((u=this.E*this.E)-r*e)/(u+r*e),(t=x-v)<-Math.pi?v-=m:t>Math.pi&&(v+=m),this.lam0=U(.5*(x+v)-Math.atan(u*Math.tan(.5*this.B*(x-v))/o)/this.B),c=Math.atan(2*Math.sin(this.B*U(x-this.lam0))/(h-1/h)),_=A=Math.asin(a*Math.sin(c))),this.singam=Math.sin(c),this.cosgam=Math.cos(c),this.sinrot=Math.sin(_),this.cosrot=Math.cos(_),this.rB=1/this.B,this.ArB=this.A*this.rB,this.BrA=1/this.ArB,this.A,this.B,this.no_off?this.u_0=0:(this.u_0=Math.abs(this.ArB*Math.atan(Math.sqrt(a*a-1)/Math.cos(A))),this.lat0<0&&(this.u_0=-this.u_0)),h=.5*c,this.v_pole_n=this.ArB*Math.log(Math.tan(y-h)),this.v_pole_s=this.ArB*Math.log(Math.tan(y+h))},forward:function(t){var s,i,a,h,e,r,n,o,u={};if(t.x=t.x-this.lam0,Math.abs(Math.abs(t.y)-l)>M){if(s=.5*((e=this.E/Math.pow(Q(this.e,t.y,Math.sin(t.y)),this.B))-(r=1/e)),i=.5*(e+r),h=Math.sin(this.B*t.x),a=(s*this.singam-h*this.cosgam)/i,Math.abs(Math.abs(a)-1)0?this.v_pole_n:this.v_pole_s,n=this.ArB*t.y;return this.no_rot?(u.x=n,u.y=o):(n-=this.u_0,u.x=o*this.cosrot+n*this.sinrot,u.y=n*this.cosrot-o*this.sinrot),u.x=this.a*u.x+this.x0,u.y=this.a*u.y+this.y0,u},inverse:function(t){var s,i,a,h,e,r,n,o={};if(t.x=(t.x-this.x0)*(1/this.a),t.y=(t.y-this.y0)*(1/this.a),this.no_rot?(i=t.y,s=t.x):(i=t.x*this.cosrot-t.y*this.sinrot,s=t.y*this.cosrot+t.x*this.sinrot+this.u_0),h=.5*((a=Math.exp(-this.BrA*i))-1/a),e=.5*(a+1/a),n=((r=Math.sin(this.BrA*s))*this.cosgam+h*this.singam)/e,Math.abs(Math.abs(n)-1)M?this.ns=Math.log(a/n)/Math.log(h/o):this.ns=s,isNaN(this.ns)&&(this.ns=s),this.f0=a/(this.ns*Math.pow(h,this.ns)),this.rh=this.a*this.f0*Math.pow(l,this.ns),this.title||(this.title="Lambert Conformal Conic")}},forward:function(t){var s=t.x,i=t.y;Math.abs(2*Math.abs(i)-Math.PI)<=M&&(i=F(i)*(l-2*M));var a,h,e=Math.abs(Math.abs(i)-l);if(e>M)a=Q(this.e,i,Math.sin(i)),h=this.a*this.f0*Math.pow(a,this.ns);else{if((e=i*this.ns)<=0)return null;h=0}var r=this.ns*U(s-this.long0);return t.x=this.k0*(h*Math.sin(r))+this.x0,t.y=this.k0*(this.rh-h*Math.cos(r))+this.y0,t},inverse:function(t){var s,i,a,h,e,r=(t.x-this.x0)/this.k0,n=this.rh-(t.y-this.y0)/this.k0;this.ns>0?(s=Math.sqrt(r*r+n*n),i=1):(s=-Math.sqrt(r*r+n*n),i=-1);var o=0;if(0!==s&&(o=Math.atan2(i*r,i*n)),0!==s||this.ns>0){if(i=1/this.ns,a=Math.pow(s/(this.a*this.f0),i),-9999===(h=W(this.e,a)))return null}else h=-l;return e=U(o/this.ns+this.long0),t.x=e,t.y=h,t},names:["Lambert Tangential Conformal Conic Projection","Lambert_Conformal_Conic","Lambert_Conformal_Conic_1SP","Lambert_Conformal_Conic_2SP","lcc","Lambert Conic Conformal (1SP)","Lambert Conic Conformal (2SP)"]};var bs={init:function(){this.a=6377397.155,this.es=.006674372230614,this.e=Math.sqrt(this.es),this.lat0||(this.lat0=.863937979737193),this.long0||(this.long0=.4334234309119251),this.k0||(this.k0=.9999),this.s45=.785398163397448,this.s90=2*this.s45,this.fi0=this.lat0,this.e2=this.es,this.e=Math.sqrt(this.e2),this.alfa=Math.sqrt(1+this.e2*Math.pow(Math.cos(this.fi0),4)/(1-this.e2)),this.uq=1.04216856380474,this.u0=Math.asin(Math.sin(this.fi0)/this.alfa),this.g=Math.pow((1+this.e*Math.sin(this.fi0))/(1-this.e*Math.sin(this.fi0)),this.alfa*this.e/2),this.k=Math.tan(this.u0/2+this.s45)/Math.pow(Math.tan(this.fi0/2+this.s45),this.alfa)*this.g,this.k1=this.k0,this.n0=this.a*Math.sqrt(1-this.e2)/(1-this.e2*Math.pow(Math.sin(this.fi0),2)),this.s0=1.37008346281555,this.n=Math.sin(this.s0),this.ro0=this.k1*this.n0/Math.tan(this.s0),this.ad=this.s90-this.uq},forward:function(t){var s,i,a,h,e,r,n,o=t.x,l=t.y,u=U(o-this.long0);return s=Math.pow((1+this.e*Math.sin(l))/(1-this.e*Math.sin(l)),this.alfa*this.e/2),i=2*(Math.atan(this.k*Math.pow(Math.tan(l/2+this.s45),this.alfa)/s)-this.s45),a=-u*this.alfa,h=Math.asin(Math.cos(this.ad)*Math.sin(i)+Math.sin(this.ad)*Math.cos(i)*Math.cos(a)),e=Math.asin(Math.cos(i)*Math.sin(a)/Math.cos(h)),r=this.n*e,n=this.ro0*Math.pow(Math.tan(this.s0/2+this.s45),this.n)/Math.pow(Math.tan(h/2+this.s45),this.n),t.y=n*Math.cos(r)/1,t.x=n*Math.sin(r)/1,this.czech||(t.y*=-1,t.x*=-1),t},inverse:function(t){var s,i,a,h,e,r,n,o=t.x;t.x=t.y,t.y=o,this.czech||(t.y*=-1,t.x*=-1),e=Math.sqrt(t.x*t.x+t.y*t.y),h=Math.atan2(t.y,t.x)/Math.sin(this.s0),a=2*(Math.atan(Math.pow(this.ro0/e,1/this.n)*Math.tan(this.s0/2+this.s45))-this.s45),s=Math.asin(Math.cos(this.ad)*Math.sin(a)-Math.sin(this.ad)*Math.cos(a)*Math.cos(h)),i=Math.asin(Math.cos(a)*Math.sin(h)/Math.cos(s)),t.x=this.long0-i/this.alfa,r=s,n=0;var l=0;do{t.y=2*(Math.atan(Math.pow(this.k,-1/this.alfa)*Math.pow(Math.tan(s/2+this.s45),1/this.alfa)*Math.pow((1+this.e*Math.sin(r))/(1-this.e*Math.sin(r)),this.e/2))-this.s45),Math.abs(r-t.y)<1e-10&&(n=1),r=t.y,l+=1}while(0===n&&l<15);return l>=15?null:t},names:["Krovak","krovak"]};function ws(t,s,i,a,h){return t*h-s*Math.sin(2*h)+i*Math.sin(4*h)-a*Math.sin(6*h)}function As(t){return 1-.25*t*(1+t/16*(3+1.25*t))}function Cs(t){return.375*t*(1+.25*t*(1+.46875*t))}function Ns(t){return.05859375*t*t*(1+.75*t)}function Ps(t){return t*t*t*(35/3072)}function Es(t,s,i){var a=s*i;return t/Math.sqrt(1-a*a)}function Ss(t){return Math.abs(t)1e-7?(1-t*t)*(s/(1-(i=t*s)*i)-.5/t*Math.log((1-i)/(1+i))):2*s}var qs=.3333333333333333,Ls=.17222222222222222,Rs=.10257936507936508,js=.06388888888888888,Gs=.0664021164021164,Ts=.016415012942191543;var zs={init:function(){var t,s=Math.abs(this.lat0);if(Math.abs(s-l)0)switch(this.qp=Os(this.e,1),this.mmf=.5/(1-this.es),this.apa=function(t){var s,i=[];return i[0]=t*qs,s=t*t,i[0]+=s*Ls,i[1]=s*js,s*=t,i[0]+=s*Rs,i[1]+=s*Gs,i[2]=s*Ts,i}(this.es),this.mode){case this.N_POLE:case this.S_POLE:this.dd=1;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp),this.dd=1/this.rq,this.xmf=1,this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp),t=Math.sin(this.lat0),this.sinb1=Os(this.e,t)/this.qp,this.cosb1=Math.sqrt(1-this.sinb1*this.sinb1),this.dd=Math.cos(this.lat0)/(Math.sqrt(1-this.es*t*t)*this.rq*this.cosb1),this.ymf=(this.xmf=this.rq)/this.dd,this.xmf*=this.dd}else this.mode===this.OBLIQ&&(this.sinph0=Math.sin(this.lat0),this.cosph0=Math.cos(this.lat0))},forward:function(t){var s,i,a,h,e,r,n,o,u,c,f=t.x,p=t.y;if(f=U(f-this.long0),this.sphere){if(e=Math.sin(p),c=Math.cos(p),a=Math.cos(f),this.mode===this.OBLIQ||this.mode===this.EQUIT){if((i=this.mode===this.EQUIT?1+c*a:1+this.sinph0*e+this.cosph0*c*a)<=M)return null;s=(i=Math.sqrt(2/i))*c*Math.sin(f),i*=this.mode===this.EQUIT?e:this.cosph0*e-this.sinph0*c*a}else if(this.mode===this.N_POLE||this.mode===this.S_POLE){if(this.mode===this.N_POLE&&(a=-a),Math.abs(p+this.lat0)=0?(s=(u=Math.sqrt(r))*h,i=a*(this.mode===this.S_POLE?u:-u)):s=i=0}}return t.x=this.a*s+this.x0,t.y=this.a*i+this.y0,t},inverse:function(t){t.x-=this.x0,t.y-=this.y0;var s,i,a,h,e,r,n,o,u,c,f=t.x/this.a,p=t.y/this.a;if(this.sphere){var d,y=0,m=0;if((i=.5*(d=Math.sqrt(f*f+p*p)))>1)return null;switch(i=2*Math.asin(i),this.mode!==this.OBLIQ&&this.mode!==this.EQUIT||(m=Math.sin(i),y=Math.cos(i)),this.mode){case this.EQUIT:i=Math.abs(d)<=M?0:Math.asin(p*m/d),f*=m,p=y*d;break;case this.OBLIQ:i=Math.abs(d)<=M?this.lat0:Math.asin(y*this.sinph0+p*m*this.cosph0/d),f*=m*this.cosph0,p=(y-Math.sin(i)*this.sinph0)*d;break;case this.N_POLE:p=-p,i=l-i;break;case this.S_POLE:i-=l}s=0!==p||this.mode!==this.EQUIT&&this.mode!==this.OBLIQ?Math.atan2(f,p):0}else{if(n=0,this.mode===this.OBLIQ||this.mode===this.EQUIT){if(f/=this.dd,p*=this.dd,(r=Math.sqrt(f*f+p*p))1&&(t=t>1?1:-1),Math.asin(t)}var Ds={init:function(){Math.abs(this.lat1+this.lat2)M?this.ns0=(this.ms1*this.ms1-this.ms2*this.ms2)/(this.qs2-this.qs1):this.ns0=this.con,this.c=this.ms1*this.ms1+this.ns0*this.qs1,this.rh=this.a*Math.sqrt(this.c-this.ns0*this.qs0)/this.ns0)},forward:function(t){var s=t.x,i=t.y;this.sin_phi=Math.sin(i),this.cos_phi=Math.cos(i);var a=Os(this.e3,this.sin_phi),h=this.a*Math.sqrt(this.c-this.ns0*a)/this.ns0,e=this.ns0*U(s-this.long0),r=h*Math.sin(e)+this.x0,n=this.rh-h*Math.cos(e)+this.y0;return t.x=r,t.y=n,t},inverse:function(t){var s,i,a,h,e,r;return t.x-=this.x0,t.y=this.rh-t.y+this.y0,this.ns0>=0?(s=Math.sqrt(t.x*t.x+t.y*t.y),a=1):(s=-Math.sqrt(t.x*t.x+t.y*t.y),a=-1),h=0,0!==s&&(h=Math.atan2(a*t.x,a*t.y)),a=s*this.ns0/this.a,this.sphere?r=Math.asin((this.c-a*a)/(2*this.ns0)):(i=(this.c-a*a)/this.ns0,r=this.phi1z(this.e3,i)),e=U(h/this.ns0+this.long0),t.x=e,t.y=r,t},names:["Albers_Conic_Equal_Area","Albers","aea"],phi1z:function(t,s){var i,a,h,e,r=Bs(.5*s);if(t0||Math.abs(e)<=M?(r=this.x0+1*this.a*i*Math.sin(a)/e,n=this.y0+1*this.a*(this.cos_p14*s-this.sin_p14*i*h)/e):(r=this.x0+this.infinity_dist*i*Math.sin(a),n=this.y0+this.infinity_dist*(this.cos_p14*s-this.sin_p14*i*h)),t.x=r,t.y=n,t},inverse:function(t){var s,i,a,h,e,r;return t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,t.x/=this.k0,t.y/=this.k0,(s=Math.sqrt(t.x*t.x+t.y*t.y))?(h=Math.atan2(s,this.rc),i=Math.sin(h),r=Bs((a=Math.cos(h))*this.sin_p14+t.y*i*this.cos_p14/s),e=Math.atan2(t.x*i,s*this.cos_p14*a-t.y*this.sin_p14*i),e=U(this.long0+e)):(r=this.phic0,e=0),t.x=e,t.y=r,t},names:["gnom"]};var Us={init:function(){this.sphere||(this.k0=D(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts)))},forward:function(t){var s,i,a=t.x,h=t.y,e=U(a-this.long0);if(this.sphere)s=this.x0+this.a*e*Math.cos(this.lat_ts),i=this.y0+this.a*Math.sin(h)/Math.cos(this.lat_ts);else{var r=Os(this.e,Math.sin(h));s=this.x0+this.a*this.k0*e,i=this.y0+this.a*r*.5/this.k0}return t.x=s,t.y=i,t},inverse:function(t){var s,i;return t.x-=this.x0,t.y-=this.y0,this.sphere?(s=U(this.long0+t.x/this.a/Math.cos(this.lat_ts)),i=Math.asin(t.y/this.a*Math.cos(this.lat_ts))):(i=function(t,s){var i=1-(1-t*t)/(2*t)*Math.log((1-t)/(1+t));if(Math.abs(Math.abs(s)-i)<1e-6)return s<0?-1*l:l;for(var a,h,e,r,n=Math.asin(.5*s),o=0;o<30;o++)if(h=Math.sin(n),e=Math.cos(n),r=t*h,n+=a=Math.pow(1-r*r,2)/(2*e)*(s/(1-t*t)-h/(1-r*r)+.5/t*Math.log((1-r)/(1+r))),Math.abs(a)<=1e-10)return n;return NaN}(this.e,2*t.y*this.k0/this.a),s=U(this.long0+t.x/(this.a*this.k0))),t.x=s,t.y=i,t},names:["cea"]};var Qs={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.lat0=this.lat0||0,this.long0=this.long0||0,this.lat_ts=this.lat_ts||0,this.title=this.title||"Equidistant Cylindrical (Plate Carre)",this.rc=Math.cos(this.lat_ts)},forward:function(t){var s=t.x,i=t.y,a=U(s-this.long0),h=Ss(i-this.lat0);return t.x=this.x0+this.a*a*this.rc,t.y=this.y0+this.a*h,t},inverse:function(t){var s=t.x,i=t.y;return t.x=U(this.long0+(s-this.x0)/(this.a*this.rc)),t.y=Ss(this.lat0+(i-this.y0)/this.a),t},names:["Equirectangular","Equidistant_Cylindrical","eqc"]};var Ws={init:function(){this.temp=this.b/this.a,this.es=1-Math.pow(this.temp,2),this.e=Math.sqrt(this.es),this.e0=As(this.es),this.e1=Cs(this.es),this.e2=Ns(this.es),this.e3=Ps(this.es),this.ml0=this.a*ws(this.e0,this.e1,this.e2,this.e3,this.lat0)},forward:function(t){var s,i,a,h=t.x,e=t.y,r=U(h-this.long0);if(a=r*Math.sin(e),this.sphere)Math.abs(e)<=M?(s=this.a*r,i=-1*this.a*this.lat0):(s=this.a*Math.sin(a)/Math.tan(e),i=this.a*(Ss(e-this.lat0)+(1-Math.cos(a))/Math.tan(e)));else if(Math.abs(e)<=M)s=this.a*r,i=-1*this.ml0;else{var n=Es(this.a,this.e,Math.sin(e))/Math.tan(e);s=n*Math.sin(a),i=this.a*ws(this.e0,this.e1,this.e2,this.e3,e)-this.ml0+n*(1-Math.cos(a))}return t.x=s+this.x0,t.y=i+this.y0,t},inverse:function(t){var s,i,a,h,e,r,n,o,l;if(a=t.x-this.x0,h=t.y-this.y0,this.sphere)if(Math.abs(h+this.a*this.lat0)<=M)s=U(a/this.a+this.long0),i=0;else{var u;for(r=this.lat0+h/this.a,n=a*a/this.a/this.a+r*r,o=r,e=20;e;--e)if(o+=l=-1*(r*(o*(u=Math.tan(o))+1)-o-.5*(o*o+n)*u)/((o-r)/u-1),Math.abs(l)<=M){i=o;break}s=U(this.long0+Math.asin(a*Math.tan(o)/this.a)/Math.sin(i))}else if(Math.abs(h+this.ml0)<=M)i=0,s=U(this.long0+a/this.a);else{var c,f,p,d,y;for(r=(this.ml0+h)/this.a,n=a*a/this.a/this.a+r*r,o=r,e=20;e;--e)if(y=this.e*Math.sin(o),c=Math.sqrt(1-y*y)*Math.tan(o),f=this.a*ws(this.e0,this.e1,this.e2,this.e3,o),p=this.e0-2*this.e1*Math.cos(2*o)+4*this.e2*Math.cos(4*o)-6*this.e3*Math.cos(6*o),o-=l=(r*(c*(d=f/this.a)+1)-d-.5*c*(d*d+n))/(this.es*Math.sin(2*o)*(d*d+n-2*r*d)/(4*c)+(r-d)*(c*p-2/Math.sin(2*o))-p),Math.abs(l)<=M){i=o;break}c=Math.sqrt(1-this.es*Math.pow(Math.sin(i),2))*Math.tan(i),s=U(this.long0+Math.asin(a*c/this.a)/Math.sin(i))}return t.x=s,t.y=i,t},names:["Polyconic","poly"]};var Zs={init:function(){this.A=[],this.A[1]=.6399175073,this.A[2]=-.1358797613,this.A[3]=.063294409,this.A[4]=-.02526853,this.A[5]=.0117879,this.A[6]=-.0055161,this.A[7]=.0026906,this.A[8]=-.001333,this.A[9]=67e-5,this.A[10]=-34e-5,this.B_re=[],this.B_im=[],this.B_re[1]=.7557853228,this.B_im[1]=0,this.B_re[2]=.249204646,this.B_im[2]=.003371507,this.B_re[3]=-.001541739,this.B_im[3]=.04105856,this.B_re[4]=-.10162907,this.B_im[4]=.01727609,this.B_re[5]=-.26623489,this.B_im[5]=-.36249218,this.B_re[6]=-.6870983,this.B_im[6]=-1.1651967,this.C_re=[],this.C_im=[],this.C_re[1]=1.3231270439,this.C_im[1]=0,this.C_re[2]=-.577245789,this.C_im[2]=-.007809598,this.C_re[3]=.508307513,this.C_im[3]=-.112208952,this.C_re[4]=-.15094762,this.C_im[4]=.18200602,this.C_re[5]=1.01418179,this.C_im[5]=1.64497696,this.C_re[6]=1.9660549,this.C_im[6]=2.5127645,this.D=[],this.D[1]=1.5627014243,this.D[2]=.5185406398,this.D[3]=-.03333098,this.D[4]=-.1052906,this.D[5]=-.0368594,this.D[6]=.007317,this.D[7]=.0122,this.D[8]=.00394,this.D[9]=-.0013},forward:function(t){var s,i=t.x,a=t.y-this.lat0,h=i-this.long0,e=a/o*1e-5,r=h,n=1,l=0;for(s=1;s<=10;s++)n*=e,l+=this.A[s]*n;var u,c=l,f=r,M=1,p=0,d=0,y=0;for(s=1;s<=6;s++)u=p*c+M*f,M=M*c-p*f,p=u,d=d+this.B_re[s]*M-this.B_im[s]*p,y=y+this.B_im[s]*M+this.B_re[s]*p;return t.x=y*this.a+this.x0,t.y=d*this.a+this.y0,t},inverse:function(t){var s,i,a=t.x,h=t.y,e=a-this.x0,r=(h-this.y0)/this.a,n=e/this.a,l=1,u=0,c=0,f=0;for(s=1;s<=6;s++)i=u*r+l*n,l=l*r-u*n,u=i,c=c+this.C_re[s]*l-this.C_im[s]*u,f=f+this.C_im[s]*l+this.C_re[s]*u;for(var M=0;M.999999999999&&(i=.999999999999),s=Math.asin(i);var a=U(this.long0+t.x/(.900316316158*this.a*Math.cos(s)));a<-Math.PI&&(a=-Math.PI),a>Math.PI&&(a=Math.PI),i=(2*s+Math.sin(2*s))/Math.PI,Math.abs(i)>1&&(i=1);var h=Math.asin(i);return t.x=a,t.y=h,t},names:["Mollweide","moll"]};var Js={init:function(){Math.abs(this.lat1+this.lat2)=0?(i=Math.sqrt(t.x*t.x+t.y*t.y),s=1):(i=-Math.sqrt(t.x*t.x+t.y*t.y),s=-1);var e=0;return 0!==i&&(e=Math.atan2(s*t.x,s*t.y)),this.sphere?(h=U(this.long0+e/this.ns),a=Ss(this.g-i/this.a),t.x=h,t.y=a,t):(a=Is(this.g-i/this.a,this.e0,this.e1,this.e2,this.e3),h=U(this.long0+e/this.ns),t.x=h,t.y=a,t)},names:["Equidistant_Conic","eqdc"]};var Ks={init:function(){this.R=this.a},forward:function(t){var s,i,a=t.x,h=t.y,e=U(a-this.long0);Math.abs(h)<=M&&(s=this.x0+this.R*e,i=this.y0);var r=Bs(2*Math.abs(h/Math.PI));(Math.abs(e)<=M||Math.abs(Math.abs(h)-l)<=M)&&(s=this.x0,i=h>=0?this.y0+Math.PI*this.R*Math.tan(.5*r):this.y0+Math.PI*this.R*-Math.tan(.5*r));var n=.5*Math.abs(Math.PI/e-e/Math.PI),o=n*n,u=Math.sin(r),c=Math.cos(r),f=c/(u+c-1),p=f*f,d=f*(2/u-1),y=d*d,m=Math.PI*this.R*(n*(f-y)+Math.sqrt(o*(f-y)*(f-y)-(y+o)*(p-y)))/(y+o);e<0&&(m=-m),s=this.x0+m;var _=o+f;return m=Math.PI*this.R*(d*_-n*Math.sqrt((y+o)*(o+1)-_*_))/(y+o),i=h>=0?this.y0+m:this.y0-m,t.x=s,t.y=i,t},inverse:function(t){var s,i,a,h,e,r,n,o,l,u,c,f;return t.x-=this.x0,t.y-=this.y0,c=Math.PI*this.R,e=(a=t.x/c)*a+(h=t.y/c)*h,c=3*(h*h/(o=-2*(r=-Math.abs(h)*(1+e))+1+2*h*h+e*e)+(2*(n=r-2*h*h+a*a)*n*n/o/o/o-9*r*n/o/o)/27)/(l=(r-n*n/3/o)/o)/(u=2*Math.sqrt(-l/3)),Math.abs(c)>1&&(c=c>=0?1:-1),f=Math.acos(c)/3,i=t.y>=0?(-u*Math.cos(f+Math.PI/3)-n/3/o)*Math.PI:-(-u*Math.cos(f+Math.PI/3)-n/3/o)*Math.PI,s=Math.abs(a)2*l*this.a)return;return i=s/this.a,a=Math.sin(i),h=Math.cos(i),e=this.long0,Math.abs(s)<=M?r=this.lat0:(r=Bs(h*this.sin_p12+t.y*a*this.cos_p12/s),n=Math.abs(this.lat0)-l,e=Math.abs(n)<=M?this.lat0>=0?U(this.long0+Math.atan2(t.x,-t.y)):U(this.long0-Math.atan2(-t.x,t.y)):U(this.long0+Math.atan2(t.x*a,s*this.cos_p12*h-t.y*this.sin_p12*a))),t.x=e,t.y=r,t}return o=As(this.es),u=Cs(this.es),c=Ns(this.es),f=Ps(this.es),Math.abs(this.sin_p12-1)<=M?(r=Is(((p=this.a*ws(o,u,c,f,l))-(s=Math.sqrt(t.x*t.x+t.y*t.y)))/this.a,o,u,c,f),e=U(this.long0+Math.atan2(t.x,-1*t.y)),t.x=e,t.y=r,t):Math.abs(this.sin_p12+1)<=M?(p=this.a*ws(o,u,c,f,l),r=Is(((s=Math.sqrt(t.x*t.x+t.y*t.y))-p)/this.a,o,u,c,f),e=U(this.long0+Math.atan2(t.x,t.y)),t.x=e,t.y=r,t):(s=Math.sqrt(t.x*t.x+t.y*t.y),m=Math.atan2(t.x,t.y),d=Es(this.a,this.e,this.sin_p12),_=Math.cos(m),x=-(g=this.e*this.cos_p12*_)*g/(1-this.es),v=3*this.es*(1-x)*this.sin_p12*this.cos_p12*_/(1-this.es),A=1-x*(w=(b=s/d)-x*(1+x)*Math.pow(b,3)/6-v*(1+3*x)*Math.pow(b,4)/24)*w/2-b*w*w*w/6,y=Math.asin(this.sin_p12*Math.cos(w)+this.cos_p12*Math.sin(w)*_),e=U(this.long0+Math.asin(Math.sin(m)*Math.sin(w)/Math.cos(y))),C=Math.sin(y),r=Math.atan2((C-this.es*A*this.sin_p12)*Math.tan(y),C*(1-this.es)),t.x=e,t.y=r,t)},names:["Azimuthal_Equidistant","aeqd"]};var Ys={init:function(){this.sin_p14=Math.sin(this.lat0),this.cos_p14=Math.cos(this.lat0)},forward:function(t){var s,i,a,h,e,r,n,o=t.x,l=t.y;return a=U(o-this.long0),s=Math.sin(l),i=Math.cos(l),h=Math.cos(a),1,((e=this.sin_p14*s+this.cos_p14*i*h)>0||Math.abs(e)<=M)&&(r=1*this.a*i*Math.sin(a),n=this.y0+1*this.a*(this.cos_p14*s-this.sin_p14*i*h)),t.x=r,t.y=n,t},inverse:function(t){var s,i,a,h,e,r,n;return t.x-=this.x0,t.y-=this.y0,i=Bs((s=Math.sqrt(t.x*t.x+t.y*t.y))/this.a),a=Math.sin(i),h=Math.cos(i),r=this.long0,Math.abs(s)<=M?(n=this.lat0,t.x=r,t.y=n,t):(n=Bs(h*this.sin_p14+t.y*a*this.cos_p14/s),e=Math.abs(this.lat0)-l,Math.abs(e)<=M?(r=this.lat0>=0?U(this.long0+Math.atan2(t.x,-t.y)):U(this.long0-Math.atan2(-t.x,t.y)),t.x=r,t.y=n,t):(r=U(this.long0+Math.atan2(t.x*a,s*this.cos_p14*h-t.y*this.sin_p14*a)),t.x=r,t.y=n,t))},names:["ortho"]},ti=1,si=2,ii=3,ai=4,hi=5,ei=6,ri={AREA_0:1,AREA_1:2,AREA_2:3,AREA_3:4};function ni(t,s,i,a){var h;return ty&&h<=l+y?(a.value=ri.AREA_1,h-=l):h>l+y||h<=-(l+y)?(a.value=ri.AREA_2,h=h>=0?h-_:h+_):(a.value=ri.AREA_3,h+=l)),h}function oi(t,s){var i=t+s;return i<-_?i+=m:i>+_&&(i-=m),i}var li={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.lat0=this.lat0||0,this.long0=this.long0||0,this.lat_ts=this.lat_ts||0,this.title=this.title||"Quadrilateralized Spherical Cube",this.lat0>=l-y/2?this.face=hi:this.lat0<=-(l-y/2)?this.face=ei:Math.abs(this.long0)<=y?this.face=ti:Math.abs(this.long0)<=l+y?this.face=this.long0>0?si:ai:this.face=ii,0!==this.es&&(this.one_minus_f=1-(this.a-this.b)/this.a,this.one_minus_f_squared=this.one_minus_f*this.one_minus_f)},forward:function(t){var s,i,a,h,e,r,n={x:0,y:0},o={value:0};if(t.x-=this.long0,s=0!==this.es?Math.atan(this.one_minus_f_squared*Math.tan(t.y)):t.y,i=t.x,this.face===hi)h=l-s,i>=y&&i<=l+y?(o.value=ri.AREA_0,a=i-l):i>l+y||i<=-(l+y)?(o.value=ri.AREA_1,a=i>0?i-_:i+_):i>-(l+y)&&i<=-y?(o.value=ri.AREA_2,a=i+l):(o.value=ri.AREA_3,a=i);else if(this.face===ei)h=l+s,i>=y&&i<=l+y?(o.value=ri.AREA_0,a=-i+l):i=-y?(o.value=ri.AREA_1,a=-i):i<-y&&i>=-(l+y)?(o.value=ri.AREA_2,a=-i-l):(o.value=ri.AREA_3,a=i>0?-i+_:-i-_);else{var u,c,f,M,p,d;this.face===si?i=oi(i,+l):this.face===ii?i=oi(i,+_):this.face===ai&&(i=oi(i,-l)),M=Math.sin(s),p=Math.cos(s),d=Math.sin(i),u=p*Math.cos(i),c=p*d,f=M,this.face===ti?a=ni(h=Math.acos(u),f,c,o):this.face===si?a=ni(h=Math.acos(c),f,-u,o):this.face===ii?a=ni(h=Math.acos(-u),f,-c,o):this.face===ai?a=ni(h=Math.acos(-c),f,u,o):(h=a=0,o.value=ri.AREA_0)}return r=Math.atan(12/_*(a+Math.acos(Math.sin(a)*Math.cos(y))-l)),e=Math.sqrt((1-Math.cos(h))/(Math.cos(r)*Math.cos(r))/(1-Math.cos(Math.atan(1/Math.cos(a))))),o.value===ri.AREA_1?r+=l:o.value===ri.AREA_2?r+=_:o.value===ri.AREA_3&&(r+=1.5*_),n.x=e*Math.cos(r),n.y=e*Math.sin(r),n.x=n.x*this.a+this.x0,n.y=n.y*this.a+this.y0,t.x=n.x,t.y=n.y,t},inverse:function(t){var s,i,a,h,e,r,n,o,u,c,f,M,p={lam:0,phi:0},d={value:0};if(t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,i=Math.atan(Math.sqrt(t.x*t.x+t.y*t.y)),s=Math.atan2(t.y,t.x),t.x>=0&&t.x>=Math.abs(t.y)?d.value=ri.AREA_0:t.y>=0&&t.y>=Math.abs(t.x)?(d.value=ri.AREA_1,s-=l):t.x<0&&-t.x>=Math.abs(t.y)?(d.value=ri.AREA_2,s=s<0?s+_:s-_):(d.value=ri.AREA_3,s+=l),u=_/12*Math.tan(s),e=Math.sin(u)/(Math.cos(u)-1/Math.sqrt(2)),r=Math.atan(e),(n=1-(a=Math.cos(s))*a*(h=Math.tan(i))*h*(1-Math.cos(Math.atan(1/Math.cos(r)))))<-1?n=-1:n>1&&(n=1),this.face===hi)o=Math.acos(n),p.phi=l-o,d.value===ri.AREA_0?p.lam=r+l:d.value===ri.AREA_1?p.lam=r<0?r+_:r-_:d.value===ri.AREA_2?p.lam=r-l:p.lam=r;else if(this.face===ei)o=Math.acos(n),p.phi=o-l,d.value===ri.AREA_0?p.lam=-r+l:d.value===ri.AREA_1?p.lam=-r:d.value===ri.AREA_2?p.lam=-r-l:p.lam=r<0?-r-_:-r+_;else{var y,m,g;u=(y=n)*y,m=(u+=(g=u>=1?0:Math.sqrt(1-u)*Math.sin(r))*g)>=1?0:Math.sqrt(1-u),d.value===ri.AREA_1?(u=m,m=-g,g=u):d.value===ri.AREA_2?(m=-m,g=-g):d.value===ri.AREA_3&&(u=m,m=g,g=-u),this.face===si?(u=y,y=-m,m=u):this.face===ii?(y=-y,m=-m):this.face===ai&&(u=y,y=m,m=-u),p.phi=Math.acos(-g)-l,p.lam=Math.atan2(m,y),this.face===si?p.lam=oi(p.lam,-l):this.face===ii?p.lam=oi(p.lam,-_):this.face===ai&&(p.lam=oi(p.lam,+l))}return 0!==this.es&&(c=p.phi<0?1:0,f=Math.tan(p.phi),M=this.b/Math.sqrt(f*f+this.one_minus_f_squared),p.phi=Math.atan(Math.sqrt(this.a*this.a-M*M)/(this.one_minus_f*M)),c&&(p.phi=-p.phi)),p.lam+=this.long0,t.x=p.lam,t.y=p.phi,t},names:["Quadrilateralized Spherical Cube","Quadrilateralized_Spherical_Cube","qsc"]},ui=[[1,22199e-21,-715515e-10,31103e-10],[.9986,-482243e-9,-24897e-9,-13309e-10],[.9954,-83103e-8,-448605e-10,-9.86701e-7],[.99,-.00135364,-59661e-9,36777e-10],[.9822,-.00167442,-449547e-11,-572411e-11],[.973,-.00214868,-903571e-10,1.8736e-8],[.96,-.00305085,-900761e-10,164917e-11],[.9427,-.00382792,-653386e-10,-26154e-10],[.9216,-.00467746,-10457e-8,481243e-11],[.8962,-.00536223,-323831e-10,-543432e-11],[.8679,-.00609363,-113898e-9,332484e-11],[.835,-.00698325,-640253e-10,9.34959e-7],[.7986,-.00755338,-500009e-10,9.35324e-7],[.7597,-.00798324,-35971e-9,-227626e-11],[.7186,-.00851367,-701149e-10,-86303e-10],[.6732,-.00986209,-199569e-9,191974e-10],[.6213,-.010418,883923e-10,624051e-11],[.5722,-.00906601,182e-6,624051e-11],[.5322,-.00677797,275608e-9,624051e-11]],ci=[[-520417e-23,.0124,121431e-23,-845284e-16],[.062,.0124,-1.26793e-9,4.22642e-10],[.124,.0124,5.07171e-9,-1.60604e-9],[.186,.0123999,-1.90189e-8,6.00152e-9],[.248,.0124002,7.10039e-8,-2.24e-8],[.31,.0123992,-2.64997e-7,8.35986e-8],[.372,.0124029,9.88983e-7,-3.11994e-7],[.434,.0123893,-369093e-11,-4.35621e-7],[.4958,.0123198,-102252e-10,-3.45523e-7],[.5571,.0121916,-154081e-10,-5.82288e-7],[.6176,.0119938,-241424e-10,-5.25327e-7],[.6769,.011713,-320223e-10,-5.16405e-7],[.7346,.0113541,-397684e-10,-6.09052e-7],[.7903,.0109107,-489042e-10,-104739e-11],[.8435,.0103431,-64615e-9,-1.40374e-9],[.8936,.00969686,-64636e-9,-8547e-9],[.9394,.00840947,-192841e-9,-42106e-10],[.9761,.00616527,-256e-6,-42106e-10],[1,.00328947,-319159e-9,-42106e-10]],fi=.8487,Mi=1.3523,pi=d/5,di=1/pi,yi=18,mi=function(t,s){return t[0]+s*(t[1]+s*(t[2]+s*t[3]))};var _i={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.long0=this.long0||0,this.es=0,this.title=this.title||"Robinson"},forward:function(t){var s=U(t.x-this.long0),i=Math.abs(t.y),a=Math.floor(i*pi);a<0?a=0:a>=yi&&(a=17);var h={x:mi(ui[a],i=d*(i-di*a))*s,y:mi(ci[a],i)};return t.y<0&&(h.y=-h.y),h.x=h.x*this.a*fi+this.x0,h.y=h.y*this.a*Mi+this.y0,h},inverse:function(t){var s={x:(t.x-this.x0)/(this.a*fi),y:Math.abs(t.y-this.y0)/(this.a*Mi)};if(s.y>=1)s.x/=ui[18][0],s.y=t.y<0?-l:l;else{var i=Math.floor(s.y*yi);for(i<0?i=0:i>=yi&&(i=17);;)if(ci[i][0]>s.y)--i;else{if(!(ci[i+1][0]<=s.y))break;++i}var a=ci[i],h=5*(s.y-a[0])/(ci[i+1][0]-a[0]);h=function(t,s,i,a){for(var h=s;a;--a){var e=t(h);if(h-=e,Math.abs(e)1e10)throw new Error;if(this.radius_g=1+this.radius_g_1,this.C=this.radius_g*this.radius_g-1,0!==this.es){var t=1-this.es,s=1/t;this.radius_p=Math.sqrt(t),this.radius_p2=t,this.radius_p_inv2=s,this.shape="ellipse"}else this.radius_p=1,this.radius_p2=1,this.radius_p_inv2=1,this.shape="sphere";this.title||(this.title="Geostationary Satellite View")},forward:function(t){var s,i,a,h,e=t.x,r=t.y;if(e-=this.long0,"ellipse"===this.shape){r=Math.atan(this.radius_p2*Math.tan(r));var n=this.radius_p/os(this.radius_p*Math.cos(r),Math.sin(r));if(i=n*Math.cos(e)*Math.cos(r),a=n*Math.sin(e)*Math.cos(r),h=n*Math.sin(r),(this.radius_g-i)*i-a*a-h*h*this.radius_p_inv2<0)return t.x=Number.NaN,t.y=Number.NaN,t;s=this.radius_g-i,this.flip_axis?(t.x=this.radius_g_1*Math.atan(a/os(h,s)),t.y=this.radius_g_1*Math.atan(h/s)):(t.x=this.radius_g_1*Math.atan(a/s),t.y=this.radius_g_1*Math.atan(h/os(a,s)))}else"sphere"===this.shape&&(s=Math.cos(r),i=Math.cos(e)*s,a=Math.sin(e)*s,h=Math.sin(r),s=this.radius_g-i,this.flip_axis?(t.x=this.radius_g_1*Math.atan(a/os(h,s)),t.y=this.radius_g_1*Math.atan(h/s)):(t.x=this.radius_g_1*Math.atan(a/s),t.y=this.radius_g_1*Math.atan(h/os(a,s))));return t.x=t.x*this.a,t.y=t.y*this.a,t},inverse:function(t){var s,i,a,h,e=-1,r=0,n=0;if(t.x=t.x/this.a,t.y=t.y/this.a,"ellipse"===this.shape){this.flip_axis?(n=Math.tan(t.y/this.radius_g_1),r=Math.tan(t.x/this.radius_g_1)*os(1,n)):(r=Math.tan(t.x/this.radius_g_1),n=Math.tan(t.y/this.radius_g_1)*os(1,r));var o=n/this.radius_p;if(s=r*r+o*o+e*e,(a=(i=2*this.radius_g*e)*i-4*s*this.C)<0)return t.x=Number.NaN,t.y=Number.NaN,t;h=(-i-Math.sqrt(a))/(2*s),e=this.radius_g+h*e,r*=h,n*=h,t.x=Math.atan2(r,e),t.y=Math.atan(n*Math.cos(t.x)/e),t.y=Math.atan(this.radius_p_inv2*Math.tan(t.y))}else if("sphere"===this.shape){if(this.flip_axis?(n=Math.tan(t.y/this.radius_g_1),r=Math.tan(t.x/this.radius_g_1)*Math.sqrt(1+n*n)):(r=Math.tan(t.x/this.radius_g_1),n=Math.tan(t.y/this.radius_g_1)*Math.sqrt(1+r*r)),s=r*r+n*n+e*e,(a=(i=2*this.radius_g*e)*i-4*s*this.C)<0)return t.x=Number.NaN,t.y=Number.NaN,t;h=(-i-Math.sqrt(a))/(2*s),e=this.radius_g+h*e,r*=h,n*=h,t.x=Math.atan2(r,e),t.y=Math.atan(n*Math.cos(t.x)/e)}return t.x=t.x+this.long0,t},names:["Geostationary Satellite View","Geostationary_Satellite","geos"]};At.defaultDatum="WGS84",At.Proj=lt,At.WGS84=new At.Proj("WGS84"),At.Point=Ut,At.toPoint=_t,At.defs=j,At.nadgrid=function(t,s){var i=new DataView(s),a=function(t){var s=t.getInt32(8,!1);if(11===s)return!1;s=t.getInt32(8,!0),11!==s&&console.warn("Failed to detect nadgrid endian-ness, defaulting to little-endian");return!0}(i),h=function(t,s){return{nFields:t.getInt32(8,s),nSubgridFields:t.getInt32(24,s),nSubgrids:t.getInt32(40,s),shiftType:et(t,56,64).trim(),fromSemiMajorAxis:t.getFloat64(120,s),fromSemiMinorAxis:t.getFloat64(136,s),toSemiMajorAxis:t.getFloat64(152,s),toSemiMinorAxis:t.getFloat64(168,s)}}(i,a),e=function(t,s,i){for(var a=176,h=[],e=0;e{let s=new Si(Ei),i=s.writable.getWriter(),a=s.readable.getReader();i.write(t),i.close();let h,e,r=[],n=0,o=0;for(;!(e=await a.read()).done;)h=e.value,r.push(h),n+=h.length;return r.length-1?(h=new Uint8Array(n),r.map((t=>{h.set(t,o),o+=t.length})),h):r[0]}}catch{}var Ii=new TextDecoder,ki=t=>{throw new Error("but-unzip~"+t)},Oi=t=>Ii.decode(t);function*qi(t,s=Pi){let i=(t=>{let s=t.length-20,i=Math.max(s-65516,2);for(;-1!==(s=t.lastIndexOf(80,s-1))&&(75!==t[s+1]||5!==t[s+2]||6!==t[s+3])&&s>i;);return s})(t);-1===i&&ki(2);let a=(s,a)=>t.subarray(i+=s,i+=a),h=new DataView(t.buffer,t.byteOffset),e=t=>h.getUint16(t+i,!0),r=t=>h.getUint32(t+i,!0),n=e(10);for(n!==e(8)&&ki(3),i=r(16);n--;){let t,h=e(10),n=e(28),o=e(30),l=e(32),u=r(20),c=r(42),f=Oi(a(46,n)),M=Oi(a(o,l)),p=i;i=c,t=a(30+e(26)+e(28),u),yield{filename:f,comment:M,read:()=>8&h?s(t):h?ki(1):t},i=p}}const Li=/.+\.(shp|dbf|json|prj|cpg)$/i;const Ri=globalThis.URL;var ji=(t,s)=>{if(!s)return t;const i=new Ri(t);return i.pathname=`${i.pathname}.${s}`,i.href};async function Gi(t,s){const i=ji(t,s),a="prj"===s||"cpg"===s;try{const t=await fetch(i);if(t.status>399)throw new Error(t.statusText);if(a)return t.text();const s=await t.arrayBuffer();return new DataView(s)}catch(t){if(a||"dbf"===s)return!1;throw t}}function Ti(t){let s=0,i=1;const a=t.length;let h,e;const r=[t[0][0],t[0][1],t[0][0],t[0][1]];for(;ir[2]&&(r[2]=e[0]),e[1]>r[3]&&(r[3]=e[1]);return{ring:t,clockWise:s>0,bbox:r,children:[]}}function zi(t,s){return!(t.bbox[0]>s.bbox[0])&&(!(t.bbox[1]>s.bbox[1])&&(!(t.bbox[2]20&&(s-=20),!(s in Bi))throw new Error(`I don't know shp type "${s}"`);var i;this.parseFunc=this[Bi[s]],this.parseCoord=(i=t)?function(t,s){const a=[t.getFloat64(s,!0),t.getFloat64(s+8,!0)];return i.inverse(a)}:function(t,s){return[t.getFloat64(s,!0),t.getFloat64(s+8,!0)]}},Di.prototype.getShpCode=function(){return this.parseHeader().shpCode},Di.prototype.parseHeader=function(){const t=this.buffer;return{length:t.getInt32(24)<<1,version:t.getInt32(28,!0),shpCode:t.getInt32(32,!0),bbox:[t.getFloat64(36,!0),t.getFloat64(44,!0),t.getFloat64(52,!0),t.getFloat64(60,!0)]}},Di.prototype.getRows=function(){let t=100;const s=this.buffer.byteLength-8,i=[];let a;for(;t<=s&&(a=this.getRow(t),a);)t+=8,t+=a.len,a.type?i.push(this.parseFunc(a.data)):i.push(null);return i},Di.prototype.getRow=function(t){const s=this.buffer.getInt32(t),i=this.buffer.getInt32(t+4)<<1;return 0===i?{id:s,len:i,type:0}:t+i+8>this.buffer.byteLength?void 0:{id:s,len:i,data:new DataView(this.buffer.buffer,this.buffer.byteOffset+t+12,i-4),type:this.buffer.getInt32(t+8,!0)}};var Ui=/^(?:ANSI\s)?(\d+)$/m;function Qi(t,s){if(!t)return a;try{new TextDecoder(t.trim())}catch(h){var i=Ui.exec(t);return i&&!s?Qi("windows-"+i[1],!0):(t=void 0,a)}return a;function a(s){var i=new TextDecoder(t||void 0);return(i.decode(s,{stream:!0})+i.decode()).replace(/\0/g,"").trim()}}function Wi(t,s,i,a,h){var e=h(new Uint8Array(t.buffer.slice(t.byteOffset+s,t.byteOffset+s+i)));switch(a){case"N":case"F":case"O":return parseFloat(e,10);case"D":return new Date(e.slice(0,4),parseInt(e.slice(4,6),10)-1,e.slice(6,8));case"L":return"y"===e.toLowerCase()||"t"===e.toLowerCase();default:return e}}function Zi(t,s,i,a){for(var h,e,r={},n=0,o=i.length;n{if(t)return"string"==typeof t?t:$i(t)||ArrayBuffer.isView(t)||Yi(t)?Xi.decode(t):void 0},Ki=t=>{if(!t)throw new Error("forgot to pass buffer");if(Yi(t))return t;if($i(t))return new DataView(t);if($i(t.buffer))return new DataView(t.buffer,t.byteOffset,t.byteLength);throw new Error("invalid buffer like object")};function $i(t){return t instanceof globalThis.ArrayBuffer||"[object ArrayBuffer]"===Object.prototype.toString.call(t)}function Yi(t){return t instanceof globalThis.DataView||"[object DataView]"===Object.prototype.toString.call(t)}const ta=function([t,s]){const i={type:"FeatureCollection",features:[]};let a=0;const h=t.length;for(s||(s=[]);a{if(!t)throw new Error("forgot to pass buffer");if($i(t))return new Uint8Array(t);if($i(t.buffer))return 1===t.BYTES_PER_ELEMENT?t:new Uint8Array(t.buffer,t.byteOffset,t.byteLength);throw new Error("invalid buffer like object")})(t);const a=await(async t=>{const s={},i=[];for(const a of qi(t))Li.test(a.filename)&&i.push(Promise.resolve(a.read()).then((t=>s[a.filename]=t)));await Promise.all(i);const a={},h=new TextDecoder;for(const[t,i]of Object.entries(s))"shp"===t.slice(-3).toLowerCase()||"dbf"===t.slice(-3).toLowerCase()?a[t]=new DataView(i.buffer,i.byteOffset,i.byteLength):a[t]=h.decode(i);return a})(t),h=[];for(i in s=s||[],a)-1===i.indexOf("__MACOSX")&&(".shp"===i.slice(-4).toLowerCase()?(h.push(i.slice(0,-4)),a[i.slice(0,-3)+i.slice(-3).toLowerCase()]=a[i]):".prj"===i.slice(-4).toLowerCase()?a[i.slice(0,-3)+i.slice(-3).toLowerCase()]=At(a[i]):".json"===i.slice(-5).toLowerCase()||s.indexOf(i.split(".").pop())>-1?h.push(i.slice(0,-3)+i.slice(-3).toLowerCase()):".dbf"!==i.slice(-4).toLowerCase()&&".cpg"!==i.slice(-4).toLowerCase()||(a[i.slice(0,-3)+i.slice(-3).toLowerCase()]=a[i]));if(!h.length)throw new Error("no layers founds");const e=h.map((function(t){let i,h;const e=t.lastIndexOf(".");return e>-1&&t.slice(e).indexOf("json")>-1?(i=JSON.parse(a[t]),i.fileName=t.slice(0,e)):s.indexOf(t.slice(e+1))>-1?(i=a[t],i.fileName=t):(a[t+".dbf"]&&(h=Hi(a[t+".dbf"],a[t+".cpg"])),i=ta([Fi(a[t+".shp"],a[t+".prj"]),h]),i.fileName=t),i}));return 1===e.length?e[0]:e};const ia=async t=>{const s=await Promise.all([Gi(t,"shp"),Gi(t,"prj")]);let i=!1;try{s[1]&&(i=At(s[1]))}catch(t){i=!1}return Fi(s[0],i)},aa=async t=>{const[s,i]=await Promise.all([Gi(t,"dbf"),Gi(t,"cpg")]);if(s)return Hi(s,i)},ha=(t,s)=>new Vi(t,globalThis?.document?.location).pathname.slice(-4).toLowerCase()===s,ea=async function(t,s){if("string"!=typeof t){if($i(t)||ArrayBuffer.isView(t)||Yi(t))return sa(t);if(t.shp)return(({shp:t,dbf:s,cpg:i,prj:a})=>{const h=[ra(t,a)];return s&&h.push(na(s,i)),ta(h)})(t);throw new TypeError("must be a string, some sort of Buffer, or an object with at least a .shp property")}if(ha(t,".zip"))return async function(t,s){const i=await Gi(t);return sa(i,s)}(t,s);ha(t,".shp")&&(t=t.slice(0,-4));const i=await Promise.all([ia(t),aa(t)]);return ta(i)},ra=function(t,s){if(t=Ki(t),"string"==typeof(s=Ji(s)))try{s=At(s)}catch(t){s=!1}return Fi(t,s)},na=function(t,s){return Hi(t=Ki(t),s=Ji(s))};export{ta as combine,ea as default,ea as getShapefile,na as parseDbf,ra as parseShp,sa as parseZip}; diff --git a/package.json b/package.json index 15fcf5e..983918e 100644 --- a/package.json +++ b/package.json @@ -3,17 +3,19 @@ "version": "6.0.1", "description": "Load shapefiles in pure JavaScript", "main": "lib/index.js", + "exports": { + "import": "./lib/index.js", + "require": "./dist/shp.js" + }, "type": "module", "repository": { "type": "git", "url": "git://github.com/calvinmetcalf/shapefile-js.git" }, "scripts": { - "test": "mocha ./test/test.js", - "build-test": "rollup -c -i ./test/test.js -o ./test/bundle.js -f iife", + "test": "mocha --require test/fixtures.js ./test/test.js", "build": "rollup -c", - "serve": "node test/server.js", - "build-min": "rollup -c -o dist/shp.min.js -p terser" + "test-browser": "SERVING=true node test/server.js" }, "author": "Calvin Metcalf", "license": "MIT", @@ -25,7 +27,7 @@ "chai-promised": "^1.0.2", "eslint": "^8.24.0", "express": "^4.17.2", - "mocha": "^7.1.2", + "mocha": "^8.2.0", "morgan": "^1.10.0", "rollup": "^4.13.0", "semistandard": "^16.0.1" @@ -35,4 +37,4 @@ "parsedbf": "^2.0.0", "proj4": "^2.1.4" } -} +} \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js index 9f432a9..9fd3807 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,12 +1,32 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'; -export default ({ - input: 'lib/browser.js', +import terser from '@rollup/plugin-terser'; + +export default [{ + input: './lib/browser.js', plugins: [ nodeResolve({ browser: true }) ], - output: { + output: [{ file: './dist/shp.js', format: 'umd', name: 'shp' - } -}) \ No newline at end of file + }, { + file: './dist/shp.min.js', + format: 'umd', + name: 'shp', + plugins: [terser()] + }] +}, { + input: './lib/index.js', + plugins: [ + nodeResolve({ browser: true }) + ], + output: [{ + file: './dist/shp.esm.js', + format: 'esm' + }, { + file: './dist/shp.esm.min.js', + format: 'esm', + plugins: [terser()] + }] +}] \ No newline at end of file diff --git a/test/fixtures.js b/test/fixtures.js new file mode 100644 index 0000000..28c7df2 --- /dev/null +++ b/test/fixtures.js @@ -0,0 +1,21 @@ +import server from './server.js' +export async function mochaGlobalSetup() { + return new Promise((yes, no) => { + this.server = server.listen(3000, (err) => { + if (err) { + return no(err); + } + yes() + }); + }); +} +export async function mochaGlobalTeardown() { + return new Promise((yes, no) => { + this.server.close((err) => { + if (err) { + return no(err); + } + yes(); + }); + }); +}; \ No newline at end of file diff --git a/test/index.html b/test/index.html index c4d988e..9618dff 100644 --- a/test/index.html +++ b/test/index.html @@ -1,4 +1,5 @@ + Mocha Tests @@ -8,15 +9,18 @@ - - -
- + + + + +
+ - + + \ No newline at end of file diff --git a/test/server.js b/test/server.js index 9c8d35c..cdfcd27 100644 --- a/test/server.js +++ b/test/server.js @@ -2,10 +2,38 @@ import express from 'express'; import morgan from 'morgan'; import path from 'path'; +import { rollup } from 'rollup'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; + const app = express(); -app.use(morgan('dev')); +if (process.env.SERVING) { + app.use(morgan('dev')); +} +app.get('/test/bundle-browser.js', (req, res) => { + rollup({ + input: path.join(import.meta.dirname, 'test.js'), + plugins: [ + nodeResolve({ browser: true }) + ], + }) + .then(result => { + return result.generate({ + format: 'iife' + }) + }) + .then(({ output: [{ code }] }) => { + res.type('.js'); + res.send(code); + }).catch(e => { + console.log(e); + res.sendStatus(500) + }) +}) + app.use('/', express.static(path.join(import.meta.dirname, '..'))); -app.listen(3000, () => { - console.log('go to http://localhost:3000/test/ to test in the browser'); - console.log('or `npm run test` in another window'); -}); +export default app; +if (process.env.SERVING) { + app.listen(3000, () => { + console.log('go to http://localhost:3000/test/ to test in the browser'); + }); +} \ No newline at end of file