UNPKG

@loaders.gl/wkt

Version:

Loader and Writer for the WKT (Well Known Text) Format

477 lines (469 loc) 13.1 kB
"use strict"; (() => { // ../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); })();