'use strict'; 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); } } var index = function(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; }; module.exports = index;