UNPKG

@loaders.gl/shapefile

Version:

Loader for the Shapefile Format

1,581 lines (1,553 loc) 206 kB
(function webpackUniversalModuleDefinition(root, factory) { if (typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if (typeof define === 'function' && define.amd) define([], factory); else if (typeof exports === 'object') exports['loaders'] = factory(); else root['loaders'] = factory();})(globalThis, function () { "use strict"; var __exports__ = (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // external-global-plugin:@loaders.gl/core var require_core = __commonJS({ "external-global-plugin:@loaders.gl/core"(exports4, module) { module.exports = globalThis.loaders; } }); // bundle.ts var bundle_exports = {}; __export(bundle_exports, { DBFLoader: () => DBFLoader, DBFWorkerLoader: () => DBFWorkerLoader, SHPLoader: () => SHPLoader, SHPWorkerLoader: () => SHPWorkerLoader, ShapefileLoader: () => ShapefileLoader, _BinaryChunkReader: () => BinaryChunkReader, _BinaryReader: () => BinaryReader, _zipBatchIterators: () => zipBatchIterators }); __reExport(bundle_exports, __toESM(require_core(), 1)); // src/lib/streaming/binary-chunk-reader.ts var BinaryChunkReader = class { offset; arrayBuffers; ended; maxRewindBytes; constructor(options) { const { maxRewindBytes = 0 } = options || {}; this.offset = 0; this.arrayBuffers = []; this.ended = false; this.maxRewindBytes = maxRewindBytes; } /** * @param arrayBuffer */ write(arrayBuffer) { this.arrayBuffers.push(arrayBuffer); } end() { this.arrayBuffers = []; this.ended = true; } /** * Has enough bytes available in array buffers * * @param bytes Number of bytes * @return boolean */ hasAvailableBytes(bytes) { let bytesAvailable = -this.offset; for (const arrayBuffer of this.arrayBuffers) { bytesAvailable += arrayBuffer.byteLength; if (bytesAvailable >= bytes) { return true; } } return false; } /** * Find offsets of byte ranges within this.arrayBuffers * * @param bytes Byte length to read * @return Arrays with byte ranges pointing to this.arrayBuffers, Output type is nested array, e.g. [ [0, [1, 2]], ...] */ findBufferOffsets(bytes) { let offset = -this.offset; const selectedBuffers = []; for (let i = 0; i < this.arrayBuffers.length; i++) { const buf = this.arrayBuffers[i]; if (offset + buf.byteLength <= 0) { offset += buf.byteLength; continue; } const start2 = offset <= 0 ? Math.abs(offset) : 0; let end; if (start2 + bytes <= buf.byteLength) { end = start2 + bytes; selectedBuffers.push([i, [start2, end]]); return selectedBuffers; } end = buf.byteLength; selectedBuffers.push([i, [start2, end]]); bytes -= buf.byteLength - start2; offset += buf.byteLength; } return null; } /** * Get the required number of bytes from the iterator * * @param bytes Number of bytes * @return DataView with data */ getDataView(bytes) { const bufferOffsets = this.findBufferOffsets(bytes); if (!bufferOffsets && this.ended) { throw new Error("binary data exhausted"); } if (!bufferOffsets) { return null; } if (bufferOffsets.length === 1) { const [bufferIndex, [start2, end]] = bufferOffsets[0]; const arrayBuffer = this.arrayBuffers[bufferIndex]; const view2 = new DataView(arrayBuffer, start2, end - start2); this.offset += bytes; this.disposeBuffers(); return view2; } const view = new DataView(this._combineArrayBuffers(bufferOffsets)); this.offset += bytes; this.disposeBuffers(); return view; } /** * Dispose of old array buffers */ disposeBuffers() { while (this.arrayBuffers.length > 0 && this.offset - this.maxRewindBytes >= this.arrayBuffers[0].byteLength) { this.offset -= this.arrayBuffers[0].byteLength; this.arrayBuffers.shift(); } } /** * Copy multiple ArrayBuffers into one contiguous ArrayBuffer * * In contrast to concatenateArrayBuffers, this only copies the necessary * portions of the source arrays, rather than first copying the entire arrays * then taking a part of them. * * @param bufferOffsets List of internal array offsets * @return New contiguous ArrayBuffer */ _combineArrayBuffers(bufferOffsets) { let byteLength = 0; for (const bufferOffset of bufferOffsets) { const [start2, end] = bufferOffset[1]; byteLength += end - start2; } const result = new Uint8Array(byteLength); let resultOffset = 0; for (const bufferOffset of bufferOffsets) { const [bufferIndex, [start2, end]] = bufferOffset; const sourceArray = new Uint8Array(this.arrayBuffers[bufferIndex]); result.set(sourceArray.subarray(start2, end), resultOffset); resultOffset += end - start2; } return result.buffer; } /** * @param bytes */ skip(bytes) { this.offset += bytes; } /** * @param bytes */ rewind(bytes) { this.offset -= bytes; } }; // src/lib/parsers/parse-shp-header.ts var LITTLE_ENDIAN = true; var BIG_ENDIAN = false; var SHP_MAGIC_NUMBER = 9994; function parseSHPHeader(headerView) { const header = { magic: headerView.getInt32(0, BIG_ENDIAN), // Length is stored as # of 2-byte words; multiply by 2 to get # of bytes length: headerView.getInt32(24, BIG_ENDIAN) * 2, version: headerView.getInt32(28, LITTLE_ENDIAN), type: headerView.getInt32(32, LITTLE_ENDIAN), bbox: { minX: headerView.getFloat64(36, LITTLE_ENDIAN), minY: headerView.getFloat64(44, LITTLE_ENDIAN), minZ: headerView.getFloat64(68, LITTLE_ENDIAN), minM: headerView.getFloat64(84, LITTLE_ENDIAN), maxX: headerView.getFloat64(52, LITTLE_ENDIAN), maxY: headerView.getFloat64(60, LITTLE_ENDIAN), maxZ: headerView.getFloat64(76, LITTLE_ENDIAN), maxM: headerView.getFloat64(92, LITTLE_ENDIAN) } }; if (header.magic !== SHP_MAGIC_NUMBER) { console.error(`SHP file: bad magic number ${header.magic}`); } if (header.version !== 1e3) { console.error(`SHP file: bad version ${header.version}`); } return header; } // src/lib/parsers/parse-shp-geometry.ts var LITTLE_ENDIAN2 = true; function parseRecord(view, options) { const { _maxDimensions = 4 } = options?.shp || {}; let offset = 0; const type = view.getInt32(offset, LITTLE_ENDIAN2); offset += Int32Array.BYTES_PER_ELEMENT; switch (type) { case 0: return parseNull(); case 1: return parsePoint(view, offset, Math.min(2, _maxDimensions)); case 3: return parsePoly(view, offset, Math.min(2, _maxDimensions), "LineString"); case 5: return parsePoly(view, offset, Math.min(2, _maxDimensions), "Polygon"); case 8: return parseMultiPoint(view, offset, Math.min(2, _maxDimensions)); case 11: return parsePoint(view, offset, Math.min(4, _maxDimensions)); case 13: return parsePoly(view, offset, Math.min(4, _maxDimensions), "LineString"); case 15: return parsePoly(view, offset, Math.min(4, _maxDimensions), "Polygon"); case 18: return parseMultiPoint(view, offset, Math.min(4, _maxDimensions)); case 21: return parsePoint(view, offset, Math.min(3, _maxDimensions)); case 23: return parsePoly(view, offset, Math.min(3, _maxDimensions), "LineString"); case 25: return parsePoly(view, offset, Math.min(3, _maxDimensions), "Polygon"); case 28: return parseMultiPoint(view, offset, Math.min(3, _maxDimensions)); default: throw new Error(`unsupported shape type: ${type}`); } } function parseNull() { return null; } function parsePoint(view, offset, dim) { let positions; [positions, offset] = parsePositions(view, offset, 1, dim); return { positions: { value: positions, size: dim }, type: "Point" }; } function parseMultiPoint(view, offset, dim) { offset += 4 * Float64Array.BYTES_PER_ELEMENT; const nPoints = view.getInt32(offset, LITTLE_ENDIAN2); offset += Int32Array.BYTES_PER_ELEMENT; let xyPositions = null; let mPositions = null; let zPositions = null; [xyPositions, offset] = parsePositions(view, offset, nPoints, 2); if (dim === 4) { offset += 2 * Float64Array.BYTES_PER_ELEMENT; [zPositions, offset] = parsePositions(view, offset, nPoints, 1); } if (dim >= 3) { offset += 2 * Float64Array.BYTES_PER_ELEMENT; [mPositions, offset] = parsePositions(view, offset, nPoints, 1); } const positions = concatPositions(xyPositions, mPositions, zPositions); return { positions: { value: positions, size: dim }, type: "Point" }; } function parsePoly(view, offset, dim, type) { offset += 4 * Float64Array.BYTES_PER_ELEMENT; const nParts = view.getInt32(offset, LITTLE_ENDIAN2); offset += Int32Array.BYTES_PER_ELEMENT; const nPoints = view.getInt32(offset, LITTLE_ENDIAN2); offset += Int32Array.BYTES_PER_ELEMENT; const bufferOffset = view.byteOffset + offset; const bufferLength = nParts * Int32Array.BYTES_PER_ELEMENT; const ringIndices = new Int32Array(nParts + 1); ringIndices.set(new Int32Array(view.buffer.slice(bufferOffset, bufferOffset + bufferLength))); ringIndices[nParts] = nPoints; offset += nParts * Int32Array.BYTES_PER_ELEMENT; let xyPositions = null; let mPositions = null; let zPositions = null; [xyPositions, offset] = parsePositions(view, offset, nPoints, 2); if (dim === 4) { offset += 2 * Float64Array.BYTES_PER_ELEMENT; [zPositions, offset] = parsePositions(view, offset, nPoints, 1); } if (dim >= 3) { offset += 2 * Float64Array.BYTES_PER_ELEMENT; [mPositions, offset] = parsePositions(view, offset, nPoints, 1); } const positions = concatPositions(xyPositions, mPositions, zPositions); if (type === "LineString") { return { type, positions: { value: positions, size: dim }, pathIndices: { value: ringIndices, size: 1 } }; } const polygonIndices = []; for (let i = 1; i < ringIndices.length; i++) { const startRingIndex = ringIndices[i - 1]; const endRingIndex = ringIndices[i]; const ring = xyPositions.subarray(startRingIndex * 2, endRingIndex * 2); const sign = getWindingDirection(ring); if (sign > 0) { polygonIndices.push(startRingIndex); } } polygonIndices.push(nPoints); return { type, positions: { value: positions, size: dim }, primitivePolygonIndices: { value: ringIndices, size: 1 }, // TODO: Dynamically choose Uint32Array over Uint16Array only when // necessary. I believe the implementation requires nPoints to be the // largest value in the array, so you should be able to use Uint32Array only // when nPoints > 65535. polygonIndices: { value: new Uint32Array(polygonIndices), size: 1 } }; } function parsePositions(view, offset, nPoints, dim) { const bufferOffset = view.byteOffset + offset; const bufferLength = nPoints * dim * Float64Array.BYTES_PER_ELEMENT; return [ new Float64Array(view.buffer.slice(bufferOffset, bufferOffset + bufferLength)), offset + bufferLength ]; } function concatPositions(xyPositions, mPositions, zPositions) { if (!(mPositions || zPositions)) { return xyPositions; } let arrayLength = xyPositions.length; let nDim = 2; if (zPositions && zPositions.length) { arrayLength += zPositions.length; nDim++; } if (mPositions && mPositions.length) { arrayLength += mPositions.length; nDim++; } const positions = new Float64Array(arrayLength); for (let i = 0; i < xyPositions.length / 2; i++) { positions[nDim * i] = xyPositions[i * 2]; positions[nDim * i + 1] = xyPositions[i * 2 + 1]; } if (zPositions && zPositions.length) { for (let i = 0; i < zPositions.length; i++) { positions[nDim * i + 2] = zPositions[i]; } } if (mPositions && mPositions.length) { for (let i = 0; i < mPositions.length; i++) { positions[nDim * i + (nDim - 1)] = mPositions[i]; } } return positions; } function getWindingDirection(positions) { return Math.sign(getSignedArea(positions)); } function getSignedArea(positions) { let area = 0; const nCoords = positions.length / 2 - 1; for (let i = 0; i < nCoords; i++) { area += (positions[i * 2] + positions[(i + 1) * 2]) * (positions[i * 2 + 1] - positions[(i + 1) * 2 + 1]); } return area / 2; } // src/lib/parsers/parse-shp.ts var LITTLE_ENDIAN3 = true; var BIG_ENDIAN2 = false; var SHP_HEADER_SIZE = 100; var SHP_RECORD_HEADER_SIZE = 12; var STATE = { EXPECTING_HEADER: 0, EXPECTING_RECORD: 1, END: 2, ERROR: 3 }; var SHPParser = class { options = {}; binaryReader = new BinaryChunkReader({ maxRewindBytes: SHP_RECORD_HEADER_SIZE }); state = STATE.EXPECTING_HEADER; result = { geometries: [], // Initialize with number values to make TS happy // These are initialized for real in STATE.EXPECTING_HEADER progress: { bytesTotal: NaN, bytesUsed: NaN, rows: NaN }, currentIndex: NaN }; constructor(options) { this.options = options; } write(arrayBuffer) { this.binaryReader.write(arrayBuffer); this.state = parseState(this.state, this.result, this.binaryReader, this.options); } end() { this.binaryReader.end(); this.state = parseState(this.state, this.result, this.binaryReader, this.options); if (this.state !== STATE.END) { this.state = STATE.ERROR; this.result.error = "SHP incomplete file"; } } }; function parseSHP(arrayBuffer, options) { const shpParser = new SHPParser(options); shpParser.write(arrayBuffer); shpParser.end(); return shpParser.result; } async function* parseSHPInBatches(asyncIterator, options) { const parser = new SHPParser(options); let headerReturned = false; for await (const arrayBuffer of asyncIterator) { parser.write(arrayBuffer); if (!headerReturned && parser.result.header) { headerReturned = true; yield parser.result.header; } if (parser.result.geometries.length > 0) { yield parser.result.geometries; parser.result.geometries = []; } } parser.end(); if (parser.result.geometries.length > 0) { yield parser.result.geometries; } return; } function parseState(state, result, binaryReader, options) { while (true) { try { switch (state) { case STATE.ERROR: case STATE.END: return state; case STATE.EXPECTING_HEADER: const dataView = binaryReader.getDataView(SHP_HEADER_SIZE); if (!dataView) { return state; } result.header = parseSHPHeader(dataView); result.progress = { bytesUsed: 0, bytesTotal: result.header.length, rows: 0 }; result.currentIndex = 1; state = STATE.EXPECTING_RECORD; break; case STATE.EXPECTING_RECORD: while (binaryReader.hasAvailableBytes(SHP_RECORD_HEADER_SIZE)) { const recordHeaderView = binaryReader.getDataView(SHP_RECORD_HEADER_SIZE); const recordHeader = { recordNumber: recordHeaderView.getInt32(0, BIG_ENDIAN2), // 2 byte words; includes the four words of record header byteLength: recordHeaderView.getInt32(4, BIG_ENDIAN2) * 2, // This is actually part of the record, not the header... type: recordHeaderView.getInt32(8, LITTLE_ENDIAN3) }; if (!binaryReader.hasAvailableBytes(recordHeader.byteLength - 4)) { binaryReader.rewind(SHP_RECORD_HEADER_SIZE); return state; } const invalidRecord = recordHeader.byteLength < 4 || recordHeader.type !== result.header?.type || recordHeader.recordNumber !== result.currentIndex; if (invalidRecord) { binaryReader.rewind(SHP_RECORD_HEADER_SIZE - 4); } else { binaryReader.rewind(4); const recordView = binaryReader.getDataView(recordHeader.byteLength); const geometry = parseRecord(recordView, options); result.geometries.push(geometry); result.currentIndex++; result.progress.rows = result.currentIndex - 1; } } if (binaryReader.ended) { state = STATE.END; } return state; default: state = STATE.ERROR; result.error = `illegal parser state ${state}`; return state; } } catch (error) { state = STATE.ERROR; result.error = `SHP parsing failed: ${error?.message}`; return state; } } } // src/shp-loader.ts var VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest"; var SHP_MAGIC_NUMBER2 = [0, 0, 39, 10]; var SHPWorkerLoader = { dataType: null, batchType: null, name: "SHP", id: "shp", module: "shapefile", version: VERSION, worker: true, category: "geometry", extensions: ["shp"], mimeTypes: ["application/octet-stream"], // ISSUE: This also identifies SHX files, which are identical to SHP for the first 100 bytes... tests: [new Uint8Array(SHP_MAGIC_NUMBER2).buffer], options: { shp: { _maxDimensions: 4 } } }; var SHPLoader = { ...SHPWorkerLoader, parse: async (arrayBuffer, options) => parseSHP(arrayBuffer, options), parseSync: parseSHP, parseInBatches: (arrayBufferIterator, options) => parseSHPInBatches(arrayBufferIterator, options) }; // ../loader-utils/src/loader-types.ts async function parseFromContext(data, loaders, options, context) { return context._parse(data, loaders, options, context); } async function parseInBatchesFromContext(data, loader, options, context) { if (!context._parseInBatches) { throw new Error("parseInBatches"); } return context._parseInBatches(data, loader, options, context); } // ../gis/src/lib/binary-features/binary-to-geojson.ts function binaryToGeometry(data, startIndex, endIndex) { switch (data.type) { case "Point": return pointToGeoJson(data, startIndex, endIndex); case "LineString": return lineStringToGeoJson(data, startIndex, endIndex); case "Polygon": return polygonToGeoJson(data, startIndex, endIndex); default: const unexpectedInput = data; throw new Error(`Unsupported geometry type: ${unexpectedInput?.type}`); } } function polygonToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) { const { positions } = data; const polygonIndices = data.polygonIndices.value.filter((x) => x >= startIndex && x <= endIndex); const primitivePolygonIndices = data.primitivePolygonIndices.value.filter( (x) => x >= startIndex && x <= endIndex ); const multi = polygonIndices.length > 2; if (!multi) { const coordinates2 = []; for (let i = 0; i < primitivePolygonIndices.length - 1; i++) { const startRingIndex = primitivePolygonIndices[i]; const endRingIndex = primitivePolygonIndices[i + 1]; const ringCoordinates = ringToGeoJson(positions, startRingIndex, endRingIndex); coordinates2.push(ringCoordinates); } return { type: "Polygon", coordinates: coordinates2 }; } const coordinates = []; for (let i = 0; i < polygonIndices.length - 1; i++) { const startPolygonIndex = polygonIndices[i]; const endPolygonIndex = polygonIndices[i + 1]; const polygonCoordinates = polygonToGeoJson( data, startPolygonIndex, endPolygonIndex ).coordinates; coordinates.push(polygonCoordinates); } return { type: "MultiPolygon", coordinates }; } function lineStringToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) { const { positions } = data; const pathIndices = data.pathIndices.value.filter((x) => x >= startIndex && x <= endIndex); const multi = pathIndices.length > 2; if (!multi) { const coordinates2 = ringToGeoJson(positions, pathIndices[0], pathIndices[1]); return { type: "LineString", coordinates: coordinates2 }; } const coordinates = []; for (let i = 0; i < pathIndices.length - 1; i++) { const ringCoordinates = ringToGeoJson(positions, pathIndices[i], pathIndices[i + 1]); coordinates.push(ringCoordinates); } return { type: "MultiLineString", coordinates }; } function pointToGeoJson(data, startIndex, endIndex) { const { positions } = data; const coordinates = ringToGeoJson(positions, startIndex, endIndex); const multi = coordinates.length > 1; if (multi) { return { type: "MultiPoint", coordinates }; } return { type: "Point", coordinates: coordinates[0] }; } function ringToGeoJson(positions, startIndex, endIndex) { startIndex = startIndex || 0; endIndex = endIndex || positions.value.length / positions.size; const ringCoordinates = []; for (let j = startIndex; j < endIndex; j++) { const coord = Array(); for (let k = j * positions.size; k < (j + 1) * positions.size; k++) { coord.push(Number(positions.value[k])); } ringCoordinates.push(coord); } return ringCoordinates; } // ../gis/src/lib/binary-features/transform.ts function transformGeoJsonCoords(features, fn) { for (const feature of features) { feature.geometry.coordinates = coordMap(feature.geometry.coordinates, fn); } return features; } function coordMap(array, fn) { if (isCoord(array)) { return fn(array); } return array.map((item) => { return coordMap(item, fn); }); } function isCoord(array) { return Array.isArray(array) && Number.isFinite(array[0]) && Number.isFinite(array[1]); } // ../../node_modules/proj4/lib/global.js function global_default(defs2) { defs2("EPSG:4326", "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"); defs2("EPSG:4269", "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees"); defs2("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"); defs2.WGS84 = defs2["EPSG:4326"]; defs2["EPSG:3785"] = defs2["EPSG:3857"]; defs2.GOOGLE = defs2["EPSG:3857"]; defs2["EPSG:900913"] = defs2["EPSG:3857"]; defs2["EPSG:102113"] = defs2["EPSG:3857"]; } // ../../node_modules/proj4/lib/constants/values.js var PJD_3PARAM = 1; var PJD_7PARAM = 2; var PJD_WGS84 = 4; var PJD_NODATUM = 5; var SEC_TO_RAD = 484813681109536e-20; var HALF_PI = Math.PI / 2; var SIXTH = 0.16666666666666666; var RA4 = 0.04722222222222222; var RA6 = 0.022156084656084655; var EPSLN = 1e-10; var D2R = 0.017453292519943295; var R2D = 57.29577951308232; var FORTPI = Math.PI / 4; var TWO_PI = Math.PI * 2; var SPI = 3.14159265359; // ../../node_modules/proj4/lib/constants/PrimeMeridian.js var exports = {}; exports.greenwich = 0; exports.lisbon = -9.131906111111; exports.paris = 2.337229166667; exports.bogota = -74.080916666667; exports.madrid = -3.687938888889; exports.rome = 12.452333333333; exports.bern = 7.439583333333; exports.jakarta = 106.807719444444; exports.ferro = -17.666666666667; exports.brussels = 4.367975; exports.stockholm = 18.058277777778; exports.athens = 23.7163375; exports.oslo = 10.722916666667; // ../../node_modules/proj4/lib/constants/units.js var units_default = { ft: { to_meter: 0.3048 }, "us-ft": { to_meter: 1200 / 3937 } }; // ../../node_modules/proj4/lib/match.js 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]; } } } // ../../node_modules/proj4/lib/projString.js function projString_default(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; }, lat_1: function(v) { self.lat1 = v * D2R; }, lat_2: function(v) { self.lat2 = v * D2R; }, lat_ts: function(v) { self.lat_ts = v * D2R; }, lon_0: function(v) { self.long0 = v * D2R; }, lon_1: function(v) { self.long1 = v * D2R; }, lon_2: function(v) { self.long2 = v * D2R; }, alpha: function(v) { self.alpha = parseFloat(v) * D2R; }, lonc: function(v) { self.longc = v * D2R; }, 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_default, v); if (unit) { self.to_meter = unit.to_meter; } }, from_greenwich: function(v) { self.from_greenwich = v * D2R; }, pm: function(v) { var pm = match(exports, v); self.from_greenwich = (pm ? pm : parseFloat(v)) * D2R; }, 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; } } }; 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; } // ../../node_modules/wkt-parser/parser.js var parser_default = parseString; 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\-\+]/; 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(); } // ../../node_modules/wkt-parser/process.js 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); } } // ../../node_modules/wkt-parser/index.js var D2R2 = 0.017453292519943295; 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 * D2R2; } 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 (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_parser_default(wkt) { var lisp = parser_default(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; } // ../../node_modules/proj4/lib/defs.js function defs(name) { var that = this; if (arguments.length === 2) { var def = arguments[1]; if (typeof def === "string") { if (def.charAt(0) === "+") { defs[name] = projString_default(arguments[1]); } else { defs[name] = wkt_parser_default(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; } } global_default(defs); var defs_default = defs; // ../../node_modules/proj4/lib/parseCode.js function testObj(code) { return typeof code === "string"; } function testDef(code) { return code in defs_default; } 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)) { if (testDef(code)) { return defs_default[code]; } if (testWKT(code)) { var out = wkt_parser_default(code); if (checkMercator(out)) { return defs_default["EPSG:3857"]; } var maybeProjStr = checkProjStr(out); if (maybeProjStr) { return projString_default(maybeProjStr); } return out; } if (testProj(code)) { return projString_default(code); } } else { return code; } } var parseCode_default = parse; // ../../node_modules/proj4/lib/extend.js function extend_default(destination, source) { destination = destination || {}; var value, property; if (!source) { return destination; } for (property in source) { value = source[property]; if (value !== void 0) { destination[property] = value; } } return destination; } // ../../node_modules/proj4/lib/common/msfnz.js function msfnz_default(eccent, sinphi, cosphi) { var con = eccent * sinphi; return cosphi / Math.sqrt(1 - con * con); } // ../../node_modules/proj4/lib/common/sign.js function sign_default(x) { return x < 0 ? -1 : 1; } // ../../node_modules/proj4/lib/common/adjust_lon.js function adjust_lon_default(x) { return Math.abs(x) <= SPI ? x : x - sign_default(x) * TWO_PI; } // ../../node_modules/proj4/lib/common/tsfnz.js function tsfnz_default(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; } // ../../node_modules/proj4/lib/common/phi2z.js function phi2z_default(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) <= 1e-10) { return phi; } } return -9999; } // ../../node_modules/proj4/lib/projections/merc.js function init() { 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_default(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; } } } } function forward(p) { var lon = p.x; var lat = p.y; 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_default(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_default(this.e, lat, sinphi); x = this.x0 + this.a * this.k0 * adjust_lon_default(lon - this.long0); y = this.y0 - this.a * this.k0 * Math.log(ts); } p.x = x; p.y = y; return p; } } function inverse(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_default(this.e, ts); if (lat === -9999) { return null; } } lon = adjust_lon_default(this.long0 + x / (this.a * this.k0)); p.x = lon; p.y = lat; return p; } var names = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "merc"]; var merc_default = { in