@loaders.gl/shapefile
Version:
Loader for the Shapefile Format
1,581 lines (1,553 loc) • 206 kB
JavaScript
(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