@loaders.gl/wkt
Version:
Loader and Writer for the WKT (Well Known Text) Format
477 lines (469 loc) • 13.1 kB
JavaScript
;
(() => {
// ../worker-utils/src/lib/node/worker_threads-browser.ts
var parentPort = null;
// ../worker-utils/src/lib/worker-utils/get-transfer-list.ts
function getTransferList(object, recursive = true, transfers) {
const transfersSet = transfers || /* @__PURE__ */ new Set();
if (!object) {
} else if (isTransferable(object)) {
transfersSet.add(object);
} else if (isTransferable(object.buffer)) {
transfersSet.add(object.buffer);
} else if (ArrayBuffer.isView(object)) {
} else if (recursive && typeof object === "object") {
for (const key in object) {
getTransferList(object[key], recursive, transfersSet);
}
}
return transfers === void 0 ? Array.from(transfersSet) : [];
}
function isTransferable(object) {
if (!object) {
return false;
}
if (object instanceof ArrayBuffer) {
return true;
}
if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
return true;
}
if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
return true;
}
if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
return true;
}
return false;
}
// ../worker-utils/src/lib/worker-farm/worker-body.ts
async function getParentPort() {
return parentPort;
}
var onMessageWrapperMap = /* @__PURE__ */ new Map();
var WorkerBody = class {
/** Check that we are actually in a worker thread */
static async inWorkerThread() {
return typeof self !== "undefined" || Boolean(await getParentPort());
}
/*
* (type: WorkerMessageType, payload: WorkerMessagePayload) => any
*/
static set onmessage(onMessage) {
async function handleMessage(message) {
const parentPort2 = await getParentPort();
const { type, payload } = parentPort2 ? message : message.data;
onMessage(type, payload);
}
getParentPort().then((parentPort2) => {
if (parentPort2) {
parentPort2.on("message", (message) => {
handleMessage(message);
});
parentPort2.on("exit", () => console.debug("Node worker closing"));
} else {
globalThis.onmessage = handleMessage;
}
});
}
static async addEventListener(onMessage) {
let onMessageWrapper = onMessageWrapperMap.get(onMessage);
if (!onMessageWrapper) {
onMessageWrapper = async (message) => {
if (!isKnownMessage(message)) {
return;
}
const parentPort3 = await getParentPort();
const { type, payload } = parentPort3 ? message : message.data;
onMessage(type, payload);
};
}
const parentPort2 = await getParentPort();
if (parentPort2) {
console.error("not implemented");
} else {
globalThis.addEventListener("message", onMessageWrapper);
}
}
static async removeEventListener(onMessage) {
const onMessageWrapper = onMessageWrapperMap.get(onMessage);
onMessageWrapperMap.delete(onMessage);
const parentPort2 = await getParentPort();
if (parentPort2) {
console.error("not implemented");
} else {
globalThis.removeEventListener("message", onMessageWrapper);
}
}
/**
* Send a message from a worker to creating thread (main thread)
* @param type
* @param payload
*/
static async postMessage(type, payload) {
const data = { source: "loaders.gl", type, payload };
const transferList = getTransferList(payload);
const parentPort2 = await getParentPort();
if (parentPort2) {
parentPort2.postMessage(data, transferList);
} else {
globalThis.postMessage(data, transferList);
}
}
};
function isKnownMessage(message) {
const { type, data } = message;
return type === "message" && data && typeof data.source === "string" && data.source.startsWith("loaders.gl");
}
// ../loader-utils/src/lib/worker-loader-utils/create-loader-worker.ts
var requestId = 0;
async function createLoaderWorker(loader) {
if (!await WorkerBody.inWorkerThread()) {
return;
}
WorkerBody.onmessage = async (type, payload) => {
switch (type) {
case "process":
try {
const { input, options = {}, context = {} } = payload;
const result = await parseData({
loader,
arrayBuffer: input,
options,
// @ts-expect-error fetch missing
context: {
...context,
_parse: parseOnMainThread
}
});
WorkerBody.postMessage("done", { result });
} catch (error) {
const message = error instanceof Error ? error.message : "";
WorkerBody.postMessage("error", { error: message });
}
break;
default:
}
};
}
function parseOnMainThread(arrayBuffer, loader, options, context) {
return new Promise((resolve, reject) => {
const id = requestId++;
const onMessage = (type, payload2) => {
if (payload2.id !== id) {
return;
}
switch (type) {
case "done":
WorkerBody.removeEventListener(onMessage);
resolve(payload2.result);
break;
case "error":
WorkerBody.removeEventListener(onMessage);
reject(payload2.error);
break;
default:
}
};
WorkerBody.addEventListener(onMessage);
const payload = { id, input: arrayBuffer, options };
WorkerBody.postMessage("process", payload);
});
}
async function parseData({
loader,
arrayBuffer,
options,
context
}) {
let data;
let parser;
if (loader.parseSync || loader.parse) {
data = arrayBuffer;
parser = loader.parseSync || loader.parse;
} else if (loader.parseTextSync) {
const textDecoder = new TextDecoder();
data = textDecoder.decode(arrayBuffer);
parser = loader.parseTextSync;
} else {
throw new Error(`Could not load data with ${loader.name} loader`);
}
options = {
...options,
modules: loader && loader.options && loader.options.modules || {},
worker: false
};
return await parser(data, { ...options }, context, loader);
}
// src/lib/utils/version.ts
var VERSION = true ? "4.3.3" : "latest";
// src/lib/parse-wkt.ts
var numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/;
var tuples = new RegExp("^" + numberRegexp.source + "(\\s" + numberRegexp.source + "){1,}");
var WKT_MAGIC_STRINGS = [
"POINT(",
"LINESTRING(",
"POLYGON(",
"MULTIPOINT(",
"MULTILINESTRING(",
"MULTIPOLYGON(",
"GEOMETRYCOLLECTION("
// We only support this "geojson" subset of the OGC simple features standard
];
function isWKT(input) {
return WKT_MAGIC_STRINGS.some((magicString) => input.startsWith(magicString));
}
function parseWKT(input, options) {
return parseWKTToGeometry(input, options);
}
function parseWKTToGeometry(input, options) {
const parts = input.split(";");
let _ = parts.pop();
const srid = (parts.shift() || "").split("=").pop();
const state = { parts, _, i: 0 };
const geometry = parseGeometry(state);
return options?.wkt?.crs ? addCRS(geometry, srid) : geometry;
}
function parseGeometry(state) {
return parsePoint(state) || parseLineString(state) || parsePolygon(state) || parseMultiPoint(state) || parseMultiLineString(state) || parseMultiPolygon(state) || parseGeometryCollection(state);
}
function addCRS(obj, srid) {
if (obj && srid?.match(/\d+/)) {
const crs = {
type: "name",
properties: {
name: "urn:ogc:def:crs:EPSG::" + srid
}
};
obj.crs = crs;
}
return obj;
}
function parsePoint(state) {
if (!$(/^(POINT(\sz)?)/i, state)) {
return null;
}
white(state);
if (!$(/^(\()/, state)) {
return null;
}
const c = coords(state);
if (!c) {
return null;
}
white(state);
if (!$(/^(\))/, state)) {
return null;
}
return {
type: "Point",
coordinates: c[0]
};
}
function parseMultiPoint(state) {
if (!$(/^(MULTIPOINT)/i, state)) {
return null;
}
white(state);
const newCoordsFormat = state._?.substring(state._?.indexOf("(") + 1, state._.length - 1).replace(/\(/g, "").replace(/\)/g, "");
state._ = "MULTIPOINT (" + newCoordsFormat + ")";
const c = multicoords(state);
if (!c) {
return null;
}
white(state);
return {
type: "MultiPoint",
coordinates: c
};
}
function parseLineString(state) {
if (!$(/^(LINESTRING(\sz)?)/i, state)) {
return null;
}
white(state);
if (!$(/^(\()/, state)) {
return null;
}
const c = coords(state);
if (!c) {
return null;
}
if (!$(/^(\))/, state)) {
return null;
}
return {
type: "LineString",
coordinates: c
};
}
function parseMultiLineString(state) {
if (!$(/^(MULTILINESTRING)/i, state))
return null;
white(state);
const c = multicoords(state);
if (!c) {
return null;
}
white(state);
return {
// @ts-ignore
type: "MultiLineString",
// @ts-expect-error
coordinates: c
};
}
function parsePolygon(state) {
if (!$(/^(POLYGON(\sz)?)/i, state)) {
return null;
}
white(state);
const c = multicoords(state);
if (!c) {
return null;
}
return {
// @ts-ignore
type: "Polygon",
// @ts-expect-error
coordinates: c
};
}
function parseMultiPolygon(state) {
if (!$(/^(MULTIPOLYGON)/i, state)) {
return null;
}
white(state);
const c = multicoords(state);
if (!c) {
return null;
}
return {
type: "MultiPolygon",
// @ts-expect-error
coordinates: c
};
}
function parseGeometryCollection(state) {
const geometries = [];
let geometry;
if (!$(/^(GEOMETRYCOLLECTION)/i, state)) {
return null;
}
white(state);
if (!$(/^(\()/, state)) {
return null;
}
while (geometry = parseGeometry(state)) {
geometries.push(geometry);
white(state);
$(/^(,)/, state);
white(state);
}
if (!$(/^(\))/, state)) {
return null;
}
return {
type: "GeometryCollection",
geometries
};
}
function multicoords(state) {
white(state);
let depth = 0;
const rings = [];
const stack = [rings];
let pointer = rings;
let elem;
while (elem = $(/^(\()/, state) || $(/^(\))/, state) || $(/^(,)/, state) || $(tuples, state)) {
if (elem === "(") {
stack.push(pointer);
pointer = [];
stack[stack.length - 1].push(pointer);
depth++;
} else if (elem === ")") {
if (pointer.length === 0)
return null;
pointer = stack.pop();
if (!pointer)
return null;
depth--;
if (depth === 0)
break;
} else if (elem === ",") {
pointer = [];
stack[stack.length - 1].push(pointer);
} else if (!elem.split(/\s/g).some(isNaN)) {
Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat));
} else {
return null;
}
white(state);
}
if (depth !== 0)
return null;
return rings;
}
function coords(state) {
const list = [];
let item;
let pt;
while (pt = $(tuples, state) || $(/^(,)/, state)) {
if (pt === ",") {
list.push(item);
item = [];
} else if (!pt.split(/\s/g).some(isNaN)) {
if (!item)
item = [];
Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat));
}
white(state);
}
if (item)
list.push(item);
else
return null;
return list.length ? list : null;
}
function $(regexp, state) {
const match = state._?.substring(state.i).match(regexp);
if (!match)
return null;
else {
state.i += match[0].length;
return match[0];
}
}
function white(state) {
$(/^\s*/, state);
}
// src/wkt-loader.ts
var WKTWorkerLoader = {
dataType: null,
batchType: null,
name: "WKT (Well-Known Text)",
id: "wkt",
module: "wkt",
version: VERSION,
worker: true,
extensions: ["wkt"],
mimeTypes: ["text/plain"],
category: "geometry",
text: true,
tests: WKT_MAGIC_STRINGS,
testText: isWKT,
options: {
wkt: {
shape: "geojson-geometry",
crs: true
}
}
};
var WKTLoader = {
...WKTWorkerLoader,
parse: async (arrayBuffer, options) => parseWKT(new TextDecoder().decode(arrayBuffer), options),
parseTextSync: (string, options) => parseWKT(string, options)
};
// src/workers/wkt-worker.ts
createLoaderWorker(WKTLoader);
})();