@loaders.gl/arrow 4.4.0-alpha.1 → 4.4.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/arrow-loader.js +1 -0
  2. package/dist/arrow-loader.js.map +1 -0
  3. package/dist/arrow-worker.js +29 -3
  4. package/dist/arrow-writer.js +2 -1
  5. package/dist/arrow-writer.js.map +1 -0
  6. package/dist/dist.dev.js +1509 -1458
  7. package/dist/dist.min.js +5 -5
  8. package/dist/exports/arrow-format.js +1 -0
  9. package/dist/exports/arrow-format.js.map +1 -0
  10. package/dist/exports/arrow-loader.js +2 -1
  11. package/dist/exports/arrow-loader.js.map +1 -0
  12. package/dist/exports/geoarrow-loader.js +1 -0
  13. package/dist/exports/geoarrow-loader.js.map +1 -0
  14. package/dist/geoarrow-loader.js +1 -0
  15. package/dist/geoarrow-loader.js.map +1 -0
  16. package/dist/geoarrow-writer.js +2 -1
  17. package/dist/geoarrow-writer.js.map +1 -0
  18. package/dist/index.cjs +7 -5
  19. package/dist/index.cjs.map +4 -4
  20. package/dist/index.js +1 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lib/encoders/encode-arrow.d.ts.map +1 -1
  23. package/dist/lib/encoders/encode-arrow.js +3 -1
  24. package/dist/lib/encoders/encode-arrow.js.map +1 -0
  25. package/dist/lib/encoders/encode-geoarrow.d.ts.map +1 -1
  26. package/dist/lib/encoders/encode-geoarrow.js +3 -1
  27. package/dist/lib/encoders/encode-geoarrow.js.map +1 -0
  28. package/dist/lib/parsers/parse-arrow.d.ts +1 -1
  29. package/dist/lib/parsers/parse-arrow.d.ts.map +1 -1
  30. package/dist/lib/parsers/parse-arrow.js +3 -1
  31. package/dist/lib/parsers/parse-arrow.js.map +1 -0
  32. package/dist/lib/parsers/parse-geoarrow.d.ts +1 -1
  33. package/dist/lib/parsers/parse-geoarrow.d.ts.map +1 -1
  34. package/dist/lib/parsers/parse-geoarrow.js +1 -0
  35. package/dist/lib/parsers/parse-geoarrow.js.map +1 -0
  36. package/dist/lib/types.js +1 -0
  37. package/dist/lib/types.js.map +1 -0
  38. package/dist/triangulate-on-worker.js +2 -1
  39. package/dist/triangulate-on-worker.js.map +1 -0
  40. package/dist/workers/arrow-worker.js +1 -0
  41. package/dist/workers/arrow-worker.js.map +1 -0
  42. package/dist/workers/hard-clone.js +1 -0
  43. package/dist/workers/hard-clone.js.map +1 -0
  44. package/dist/workers/triangulation-worker-node.js +1 -0
  45. package/dist/workers/triangulation-worker-node.js.map +1 -0
  46. package/dist/workers/triangulation-worker.js +1 -0
  47. package/dist/workers/triangulation-worker.js.map +1 -0
  48. package/package.json +12 -9
  49. package/src/lib/encoders/encode-arrow.ts +2 -1
  50. package/src/lib/encoders/encode-geoarrow.ts +2 -1
  51. package/src/lib/parsers/parse-arrow.ts +5 -2
  52. package/src/lib/parsers/parse-geoarrow.ts +3 -1
package/dist/dist.dev.js CHANGED
@@ -12842,1647 +12842,1698 @@ return true;`);
12842
12842
  };
12843
12843
  }
12844
12844
 
12845
- // src/lib/parsers/parse-arrow.ts
12846
- function parseArrowSync(arrayBuffer, options) {
12847
- const shape = options?.shape || "arrow-table";
12848
- const arrowTable = tableFromIPC([new Uint8Array(arrayBuffer)]);
12849
- return convertArrowToTable(arrowTable, shape);
12850
- }
12851
- function parseArrowInBatches(asyncIterator, options) {
12852
- async function* makeArrowAsyncIterator() {
12853
- const readers = RecordBatchReader.readAll(asyncIterator);
12854
- for await (const reader of readers) {
12855
- for await (const recordBatch of reader) {
12856
- if (options?.arrow?.batchDebounceMs !== void 0 && options?.arrow?.batchDebounceMs > 0) {
12857
- await new Promise((resolve) => setTimeout(resolve, options.arrow?.batchDebounceMs || 0));
12858
- }
12859
- const arrowTabledBatch = {
12860
- shape: "arrow-table",
12861
- batchType: "data",
12862
- data: new Table([recordBatch]),
12863
- length: recordBatch.data.length
12864
- };
12865
- yield arrowTabledBatch;
12866
- }
12867
- break;
12845
+ // ../loader-utils/src/lib/javascript-utils/is-type.ts
12846
+ var isSharedArrayBuffer = (value) => typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
12847
+
12848
+ // ../worker-utils/src/lib/npm-tag.ts
12849
+ var NPM_TAG = "beta";
12850
+
12851
+ // ../worker-utils/src/lib/env-utils/version.ts
12852
+ var warningIssued = false;
12853
+ function getVersion() {
12854
+ if (!globalThis._loadersgl_?.version) {
12855
+ globalThis._loadersgl_ = globalThis._loadersgl_ || {};
12856
+ if (typeof __VERSION__ === "undefined" && !warningIssued) {
12857
+ console.warn(
12858
+ "loaders.gl: The __VERSION__ variable is not injected using babel plugin. Latest unstable workers would be fetched from the CDN."
12859
+ );
12860
+ globalThis._loadersgl_.version = NPM_TAG;
12861
+ warningIssued = true;
12862
+ } else {
12863
+ globalThis._loadersgl_.version = __VERSION__;
12868
12864
  }
12869
12865
  }
12870
- return makeArrowAsyncIterator();
12866
+ return globalThis._loadersgl_.version;
12871
12867
  }
12868
+ var VERSION2 = getVersion();
12872
12869
 
12873
- // src/arrow-loader.ts
12874
- var ArrowLoader = {
12875
- ...ArrowWorkerLoader,
12876
- parse: async (arraybuffer, options) => parseArrowSync(arraybuffer, options?.arrow),
12877
- parseSync: (arraybuffer, options) => parseArrowSync(arraybuffer, options?.arrow),
12878
- parseInBatches: parseArrowInBatches
12870
+ // ../worker-utils/src/lib/env-utils/assert.ts
12871
+ function assert(condition, message) {
12872
+ if (!condition) {
12873
+ throw new Error(message || "loaders.gl assertion failed.");
12874
+ }
12875
+ }
12876
+
12877
+ // ../worker-utils/src/lib/env-utils/globals.ts
12878
+ var globals = {
12879
+ self: typeof self !== "undefined" && self,
12880
+ window: typeof window !== "undefined" && window,
12881
+ global: typeof global !== "undefined" && global,
12882
+ document: typeof document !== "undefined" && document
12879
12883
  };
12884
+ var self_ = globals.self || globals.window || globals.global || {};
12885
+ var window_ = globals.window || globals.self || globals.global || {};
12886
+ var global_ = globals.global || globals.self || globals.window || {};
12887
+ var document_ = globals.document || {};
12888
+ var isBrowser = (
12889
+ // @ts-ignore process.browser
12890
+ typeof process !== "object" || String(process) !== "[object process]" || process.browser
12891
+ );
12892
+ var isMobile = typeof window !== "undefined" && typeof window.orientation !== "undefined";
12893
+ var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version);
12894
+ var nodeVersion = matches && parseFloat(matches[1]) || 0;
12880
12895
 
12881
- // src/lib/encoders/encode-arrow.ts
12882
- function encodeArrowSync(data) {
12883
- const vectors = {};
12884
- for (const arrayData of data) {
12885
- const arrayVector = createVector(arrayData.array, arrayData.type);
12886
- vectors[arrayData.name] = arrayVector;
12896
+ // ../worker-utils/src/lib/worker-farm/worker-job.ts
12897
+ var WorkerJob = class {
12898
+ name;
12899
+ workerThread;
12900
+ isRunning = true;
12901
+ /** Promise that resolves when Job is done */
12902
+ result;
12903
+ _resolve = () => {
12904
+ };
12905
+ _reject = () => {
12906
+ };
12907
+ constructor(jobName, workerThread) {
12908
+ this.name = jobName;
12909
+ this.workerThread = workerThread;
12910
+ this.result = new Promise((resolve, reject) => {
12911
+ this._resolve = resolve;
12912
+ this._reject = reject;
12913
+ });
12887
12914
  }
12888
- const table = new Table(vectors);
12889
- const arrowBuffer = tableToIPC(table);
12890
- return arrowBuffer;
12891
- }
12892
- function createVector(array, type) {
12893
- switch (type) {
12894
- case 1 /* DATE */:
12895
- return vectorFromArray(array);
12896
- case 0 /* FLOAT */:
12897
- default:
12898
- return vectorFromArray(array);
12915
+ /**
12916
+ * Send a message to the job's worker thread
12917
+ * @param data any data structure, ideally consisting mostly of transferrable objects
12918
+ */
12919
+ postMessage(type, payload) {
12920
+ this.workerThread.postMessage({
12921
+ source: "loaders.gl",
12922
+ // Lets worker ignore unrelated messages
12923
+ type,
12924
+ payload
12925
+ });
12899
12926
  }
12900
- }
12901
-
12902
- // src/arrow-writer.ts
12903
- var VERSION2 = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
12904
- var ArrowWriter = {
12905
- name: "Apache Arrow",
12906
- id: "arrow",
12907
- module: "arrow",
12908
- version: VERSION2,
12909
- extensions: ["arrow", "feather"],
12910
- mimeTypes: [
12911
- "application/vnd.apache.arrow.file",
12912
- "application/vnd.apache.arrow.stream",
12913
- "application/octet-stream"
12914
- ],
12915
- binary: true,
12916
- options: {},
12917
- encode: async function encodeArrow(data, options) {
12918
- return encodeArrowSync(data);
12919
- },
12920
- encodeSync(data, options) {
12921
- return encodeArrowSync(data);
12927
+ /**
12928
+ * Call to resolve the `result` Promise with the supplied value
12929
+ */
12930
+ done(value) {
12931
+ assert(this.isRunning);
12932
+ this.isRunning = false;
12933
+ this._resolve(value);
12934
+ }
12935
+ /**
12936
+ * Call to reject the `result` Promise with the supplied error
12937
+ */
12938
+ error(error) {
12939
+ assert(this.isRunning);
12940
+ this.isRunning = false;
12941
+ this._reject(error);
12922
12942
  }
12923
12943
  };
12924
12944
 
12925
- // src/exports/geoarrow-loader.ts
12926
- var GeoArrowWorkerLoader = {
12927
- ...ArrowWorkerLoader,
12928
- options: {
12929
- arrow: {
12930
- shape: "arrow-table"
12931
- }
12945
+ // ../worker-utils/src/lib/node/worker_threads-browser.ts
12946
+ var NodeWorker = class {
12947
+ terminate() {
12932
12948
  }
12933
12949
  };
12934
12950
 
12935
- // ../geoarrow/src/metadata/metadata-utils.ts
12936
- function getMetadataValue(metadata, key) {
12937
- return metadata instanceof Map ? metadata.get(key) || null : metadata[key] || null;
12938
- }
12939
-
12940
- // ../geoarrow/src/metadata/geoarrow-metadata.ts
12941
- var GEOARROW_ENCODINGS = [
12942
- "geoarrow.multipolygon",
12943
- "geoarrow.polygon",
12944
- "geoarrow.multilinestring",
12945
- "geoarrow.linestring",
12946
- "geoarrow.multipoint",
12947
- "geoarrow.point",
12948
- "geoarrow.wkb",
12949
- "geoarrow.wkt"
12950
- ];
12951
- var GEOARROW_ENCODING = "ARROW:extension:name";
12952
- var GEOARROW_METADATA = "ARROW:extension:metadata";
12953
- function getGeometryColumnsFromSchema(schema) {
12954
- const geometryColumns = {};
12955
- for (const field of schema.fields || []) {
12956
- const metadata = getGeometryMetadataForField(field?.metadata || {});
12957
- if (metadata) {
12958
- geometryColumns[field.name] = metadata;
12951
+ // ../worker-utils/src/lib/worker-utils/get-loadable-worker-url.ts
12952
+ var workerURLCache = /* @__PURE__ */ new Map();
12953
+ function getLoadableWorkerURL(props) {
12954
+ assert(props.source && !props.url || !props.source && props.url);
12955
+ let workerURL = workerURLCache.get(props.source || props.url);
12956
+ if (!workerURL) {
12957
+ if (props.url) {
12958
+ workerURL = getLoadableWorkerURLFromURL(props.url);
12959
+ workerURLCache.set(props.url, workerURL);
12960
+ }
12961
+ if (props.source) {
12962
+ workerURL = getLoadableWorkerURLFromSource(props.source);
12963
+ workerURLCache.set(props.source, workerURL);
12959
12964
  }
12960
12965
  }
12961
- return geometryColumns;
12966
+ assert(workerURL);
12967
+ return workerURL;
12962
12968
  }
12963
- function getGeometryMetadataForField(fieldMetadata) {
12964
- let metadata = null;
12965
- let geoEncoding = getMetadataValue(fieldMetadata, GEOARROW_ENCODING);
12966
- if (geoEncoding) {
12967
- geoEncoding = geoEncoding.toLowerCase();
12968
- if (geoEncoding === "wkb") {
12969
- geoEncoding = "geoarrow.wkb";
12970
- }
12971
- if (geoEncoding === "wkt") {
12972
- geoEncoding = "geoarrow.wkt";
12973
- }
12974
- if (!GEOARROW_ENCODINGS.includes(geoEncoding)) {
12975
- console.warn(`Invalid GeoArrow encoding: ${geoEncoding}`);
12976
- } else {
12977
- metadata ||= {};
12978
- metadata.encoding = geoEncoding;
12979
- }
12969
+ function getLoadableWorkerURLFromURL(url) {
12970
+ if (!url.startsWith("http")) {
12971
+ return url;
12980
12972
  }
12981
- const columnMetadata = getMetadataValue(fieldMetadata, GEOARROW_METADATA);
12982
- if (columnMetadata) {
12983
- try {
12984
- metadata = JSON.parse(columnMetadata);
12985
- } catch (error) {
12986
- console.warn("Failed to parse GeoArrow metadata", error);
12973
+ const workerSource = buildScriptSource(url);
12974
+ return getLoadableWorkerURLFromSource(workerSource);
12975
+ }
12976
+ function getLoadableWorkerURLFromSource(workerSource) {
12977
+ const blob = new Blob([workerSource], { type: "application/javascript" });
12978
+ return URL.createObjectURL(blob);
12979
+ }
12980
+ function buildScriptSource(workerUrl) {
12981
+ return `try {
12982
+ importScripts('${workerUrl}');
12983
+ } catch (error) {
12984
+ console.error(error);
12985
+ throw error;
12986
+ }`;
12987
+ }
12988
+
12989
+ // ../worker-utils/src/lib/worker-utils/get-transfer-list.ts
12990
+ function getTransferList(object, recursive = true, transfers) {
12991
+ const transfersSet = transfers || /* @__PURE__ */ new Set();
12992
+ if (!object) {
12993
+ } else if (isTransferable(object)) {
12994
+ transfersSet.add(object);
12995
+ } else if (isTransferable(object.buffer)) {
12996
+ transfersSet.add(object.buffer);
12997
+ } else if (ArrayBuffer.isView(object)) {
12998
+ } else if (recursive && typeof object === "object") {
12999
+ for (const key in object) {
13000
+ getTransferList(object[key], recursive, transfersSet);
12987
13001
  }
12988
13002
  }
12989
- return metadata || null;
13003
+ return transfers === void 0 ? Array.from(transfersSet) : [];
12990
13004
  }
12991
-
12992
- // ../gis/src/lib/geometry-converters/convert-binary-geometry-to-geojson.ts
12993
- function convertBinaryGeometryToGeometry(data, startIndex, endIndex) {
12994
- switch (data.type) {
12995
- case "Point":
12996
- return pointToGeoJson(data, startIndex, endIndex);
12997
- case "LineString":
12998
- return lineStringToGeoJson(data, startIndex, endIndex);
12999
- case "Polygon":
13000
- return polygonToGeoJson(data, startIndex, endIndex);
13001
- default:
13002
- const unexpectedInput = data;
13003
- throw new Error(`Unsupported geometry type: ${unexpectedInput?.type}`);
13005
+ function isTransferable(object) {
13006
+ if (!object) {
13007
+ return false;
13004
13008
  }
13005
- }
13006
- function polygonToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) {
13007
- const { positions } = data;
13008
- const polygonIndices = data.polygonIndices.value.filter((x) => x >= startIndex && x <= endIndex);
13009
- const primitivePolygonIndices = data.primitivePolygonIndices.value.filter(
13010
- (x) => x >= startIndex && x <= endIndex
13011
- );
13012
- const multi = polygonIndices.length > 2;
13013
- if (!multi) {
13014
- const coordinates2 = [];
13015
- for (let i = 0; i < primitivePolygonIndices.length - 1; i++) {
13016
- const startRingIndex = primitivePolygonIndices[i];
13017
- const endRingIndex = primitivePolygonIndices[i + 1];
13018
- const ringCoordinates = ringToGeoJson(positions, startRingIndex, endRingIndex);
13019
- coordinates2.push(ringCoordinates);
13020
- }
13021
- return { type: "Polygon", coordinates: coordinates2 };
13009
+ if (object instanceof ArrayBuffer) {
13010
+ return true;
13022
13011
  }
13023
- const coordinates = [];
13024
- for (let i = 0; i < polygonIndices.length - 1; i++) {
13025
- const startPolygonIndex = polygonIndices[i];
13026
- const endPolygonIndex = polygonIndices[i + 1];
13027
- const polygonCoordinates = polygonToGeoJson(
13028
- data,
13029
- startPolygonIndex,
13030
- endPolygonIndex
13031
- ).coordinates;
13032
- coordinates.push(polygonCoordinates);
13012
+ if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
13013
+ return true;
13033
13014
  }
13034
- return { type: "MultiPolygon", coordinates };
13035
- }
13036
- function lineStringToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) {
13037
- const { positions } = data;
13038
- const pathIndices = data.pathIndices.value.filter((x) => x >= startIndex && x <= endIndex);
13039
- const multi = pathIndices.length > 2;
13040
- if (!multi) {
13041
- const coordinates2 = ringToGeoJson(positions, pathIndices[0], pathIndices[1]);
13042
- return { type: "LineString", coordinates: coordinates2 };
13015
+ if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
13016
+ return true;
13043
13017
  }
13044
- const coordinates = [];
13045
- for (let i = 0; i < pathIndices.length - 1; i++) {
13046
- const ringCoordinates = ringToGeoJson(positions, pathIndices[i], pathIndices[i + 1]);
13047
- coordinates.push(ringCoordinates);
13018
+ if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
13019
+ return true;
13048
13020
  }
13049
- return { type: "MultiLineString", coordinates };
13021
+ return false;
13050
13022
  }
13051
- function pointToGeoJson(data, startIndex, endIndex) {
13052
- const { positions } = data;
13053
- const coordinates = ringToGeoJson(positions, startIndex, endIndex);
13054
- const multi = coordinates.length > 1;
13055
- if (multi) {
13056
- return { type: "MultiPoint", coordinates };
13023
+ function getTransferListForWriter(object) {
13024
+ if (object === null) {
13025
+ return {};
13057
13026
  }
13058
- return { type: "Point", coordinates: coordinates[0] };
13059
- }
13060
- function ringToGeoJson(positions, startIndex, endIndex) {
13061
- startIndex = startIndex || 0;
13062
- endIndex = endIndex || positions.value.length / positions.size;
13063
- const ringCoordinates = [];
13064
- for (let j = startIndex; j < endIndex; j++) {
13065
- const coord = Array();
13066
- for (let k = j * positions.size; k < (j + 1) * positions.size; k++) {
13067
- coord.push(Number(positions.value[k]));
13027
+ const clone = Object.assign({}, object);
13028
+ Object.keys(clone).forEach((key) => {
13029
+ if (typeof object[key] === "object" && !ArrayBuffer.isView(object[key]) && !(object[key] instanceof Array)) {
13030
+ clone[key] = getTransferListForWriter(object[key]);
13031
+ } else if (typeof clone[key] === "function" || clone[key] instanceof RegExp) {
13032
+ clone[key] = {};
13033
+ } else {
13034
+ clone[key] = object[key];
13068
13035
  }
13069
- ringCoordinates.push(coord);
13070
- }
13071
- return ringCoordinates;
13036
+ });
13037
+ return clone;
13072
13038
  }
13073
13039
 
13074
- // ../gis/src/lib/utils/concat-typed-arrays.ts
13075
- function concatTypedArrays(arrays) {
13076
- let byteLength = 0;
13077
- for (let i = 0; i < arrays.length; ++i) {
13078
- byteLength += arrays[i].byteLength;
13040
+ // ../worker-utils/src/lib/worker-farm/worker-thread.ts
13041
+ var NOOP = () => {
13042
+ };
13043
+ var WorkerThread = class {
13044
+ name;
13045
+ source;
13046
+ url;
13047
+ terminated = false;
13048
+ worker;
13049
+ onMessage;
13050
+ onError;
13051
+ _loadableURL = "";
13052
+ /** Checks if workers are supported on this platform */
13053
+ static isSupported() {
13054
+ return typeof Worker !== "undefined" && isBrowser || typeof NodeWorker !== "undefined" && !isBrowser;
13079
13055
  }
13080
- const buffer = new Uint8Array(byteLength);
13081
- let byteOffset = 0;
13082
- for (let i = 0; i < arrays.length; ++i) {
13083
- const data = new Uint8Array(arrays[i].buffer);
13084
- byteLength = data.length;
13085
- for (let j = 0; j < byteLength; ++j) {
13086
- buffer[byteOffset++] = data[j];
13087
- }
13056
+ constructor(props) {
13057
+ const { name, source, url } = props;
13058
+ assert(source || url);
13059
+ this.name = name;
13060
+ this.source = source;
13061
+ this.url = url;
13062
+ this.onMessage = NOOP;
13063
+ this.onError = (error) => console.log(error);
13064
+ this.worker = isBrowser ? this._createBrowserWorker() : this._createNodeWorker();
13088
13065
  }
13089
- return buffer;
13090
- }
13091
-
13092
- // ../gis/src/lib/binary-geometry-api/concat-binary-geometry.ts
13093
- function concatenateBinaryPointGeometries(binaryPointGeometries, dimension) {
13094
- const positions = binaryPointGeometries.map((geometry) => geometry.positions.value);
13095
- const concatenatedPositions = new Float64Array(concatTypedArrays(positions).buffer);
13096
- return {
13097
- type: "Point",
13098
- positions: { value: concatenatedPositions, size: dimension }
13099
- };
13100
- }
13101
- function concatenateBinaryLineGeometries(binaryLineGeometries, dimension) {
13102
- const lines = binaryLineGeometries.map((geometry) => geometry.positions.value);
13103
- const concatenatedPositions = new Float64Array(concatTypedArrays(lines).buffer);
13104
- const pathIndices = lines.map((line) => line.length / dimension).map(cumulativeSum(0));
13105
- pathIndices.unshift(0);
13106
- return {
13107
- type: "LineString",
13108
- positions: { value: concatenatedPositions, size: dimension },
13109
- pathIndices: { value: new Uint32Array(pathIndices), size: 1 }
13110
- };
13111
- }
13112
- function concatenateBinaryPolygonGeometries(binaryPolygonGeometries, dimension) {
13113
- const polygons = [];
13114
- const primitivePolygons = [];
13115
- for (const binaryPolygon of binaryPolygonGeometries) {
13116
- const { positions, primitivePolygonIndices: primitivePolygonIndices2 } = binaryPolygon;
13117
- polygons.push(positions.value);
13118
- primitivePolygons.push(primitivePolygonIndices2.value);
13066
+ /**
13067
+ * Terminate this worker thread
13068
+ * @note Can free up significant memory
13069
+ */
13070
+ destroy() {
13071
+ this.onMessage = NOOP;
13072
+ this.onError = NOOP;
13073
+ this.worker.terminate();
13074
+ this.terminated = true;
13119
13075
  }
13120
- const concatenatedPositions = new Float64Array(concatTypedArrays(polygons).buffer);
13121
- const polygonIndices = polygons.map((p) => p.length / dimension).map(cumulativeSum(0));
13122
- polygonIndices.unshift(0);
13123
- const primitivePolygonIndices = [0];
13124
- for (const primitivePolygon of primitivePolygons) {
13125
- primitivePolygonIndices.push(
13126
- ...primitivePolygon.filter((x) => x > 0).map((x) => x + primitivePolygonIndices[primitivePolygonIndices.length - 1])
13127
- );
13076
+ get isRunning() {
13077
+ return Boolean(this.onMessage);
13128
13078
  }
13129
- return {
13130
- type: "Polygon",
13131
- positions: { value: concatenatedPositions, size: dimension },
13132
- polygonIndices: { value: new Uint32Array(polygonIndices), size: 1 },
13133
- primitivePolygonIndices: { value: new Uint32Array(primitivePolygonIndices), size: 1 }
13134
- };
13135
- }
13136
- var cumulativeSum = (sum) => (value) => sum += value;
13137
-
13138
- // ../gis/src/lib/geometry-converters/wkb/helpers/wkb-types.ts
13139
- var EWKB_FLAG_Z = 2147483648;
13140
- var EWKB_FLAG_M = 1073741824;
13141
- var EWKB_FLAG_SRID = 536870912;
13142
- var WKT_MAGIC_STRINGS = [
13143
- "POINT(",
13144
- "LINESTRING(",
13145
- "POLYGON(",
13146
- "MULTIPOINT(",
13147
- "MULTILINESTRING(",
13148
- "MULTIPOLYGON(",
13149
- "GEOMETRYCOLLECTION("
13150
- ];
13151
- var textEncoder = new TextEncoder();
13152
- var WKT_MAGIC_BYTES = WKT_MAGIC_STRINGS.map((string) => textEncoder.encode(string));
13153
-
13154
- // ../gis/src/lib/geometry-converters/wkb/helpers/parse-wkb-header.ts
13155
- function isWKT(input) {
13156
- return getWKTGeometryType(input) !== null;
13157
- }
13158
- function getWKTGeometryType(input) {
13159
- if (typeof input === "string") {
13160
- const index2 = WKT_MAGIC_STRINGS.findIndex((magicString) => input.startsWith(magicString));
13161
- return index2 >= 0 ? index2 + 1 : null;
13079
+ /**
13080
+ * Send a message to this worker thread
13081
+ * @param data any data structure, ideally consisting mostly of transferrable objects
13082
+ * @param transferList If not supplied, calculated automatically by traversing data
13083
+ */
13084
+ postMessage(data, transferList) {
13085
+ transferList = transferList || getTransferList(data);
13086
+ this.worker.postMessage(data, transferList);
13162
13087
  }
13163
- const inputArray = new Uint8Array(input);
13164
- const index = WKT_MAGIC_BYTES.findIndex(
13165
- (magicBytes) => magicBytes.every((value, index2) => value === inputArray[index2])
13166
- );
13167
- return index >= 0 ? index + 1 : null;
13168
- }
13169
- function parseWKBHeader(dataView, target) {
13170
- const wkbHeader = Object.assign(target || {}, {
13171
- type: "wkb",
13172
- variant: "wkb",
13173
- geometryType: 1,
13174
- dimensions: 2,
13175
- coordinates: "xy",
13176
- littleEndian: true,
13177
- byteOffset: 0
13178
- });
13179
- if (isWKT(dataView.buffer)) {
13180
- throw new Error("WKB: Cannot parse WKT data");
13088
+ // PRIVATE
13089
+ /**
13090
+ * Generate a standard Error from an ErrorEvent
13091
+ * @param event
13092
+ */
13093
+ _getErrorFromErrorEvent(event) {
13094
+ let message = "Failed to load ";
13095
+ message += `worker ${this.name} from ${this.url}. `;
13096
+ if (event.message) {
13097
+ message += `${event.message} in `;
13098
+ }
13099
+ if (event.lineno) {
13100
+ message += `:${event.lineno}:${event.colno}`;
13101
+ }
13102
+ return new Error(message);
13181
13103
  }
13182
- wkbHeader.littleEndian = dataView.getUint8(wkbHeader.byteOffset) === 1;
13183
- wkbHeader.byteOffset++;
13184
- const geometryCode = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
13185
- wkbHeader.byteOffset += 4;
13186
- wkbHeader.geometryType = geometryCode & 7;
13187
- const isoType = (geometryCode - wkbHeader.geometryType) / 1e3;
13188
- switch (isoType) {
13189
- case 0:
13190
- break;
13191
- case 1:
13192
- wkbHeader.variant = "iso-wkb";
13193
- wkbHeader.dimensions = 3;
13194
- wkbHeader.coordinates = "xyz";
13195
- break;
13196
- case 2:
13197
- wkbHeader.variant = "iso-wkb";
13198
- wkbHeader.dimensions = 3;
13199
- wkbHeader.coordinates = "xym";
13200
- break;
13201
- case 3:
13202
- wkbHeader.variant = "iso-wkb";
13203
- wkbHeader.dimensions = 4;
13204
- wkbHeader.coordinates = "xyzm";
13205
- break;
13206
- default:
13207
- throw new Error(`WKB: Unsupported iso-wkb type: ${isoType}`);
13208
- }
13209
- const ewkbZ = geometryCode & EWKB_FLAG_Z;
13210
- const ewkbM = geometryCode & EWKB_FLAG_M;
13211
- const ewkbSRID = geometryCode & EWKB_FLAG_SRID;
13212
- if (ewkbZ && ewkbM) {
13213
- wkbHeader.variant = "ewkb";
13214
- wkbHeader.dimensions = 4;
13215
- wkbHeader.coordinates = "xyzm";
13216
- } else if (ewkbZ) {
13217
- wkbHeader.variant = "ewkb";
13218
- wkbHeader.dimensions = 3;
13219
- wkbHeader.coordinates = "xyz";
13220
- } else if (ewkbM) {
13221
- wkbHeader.variant = "ewkb";
13222
- wkbHeader.dimensions = 3;
13223
- wkbHeader.coordinates = "xym";
13104
+ /**
13105
+ * Creates a worker thread on the browser
13106
+ */
13107
+ _createBrowserWorker() {
13108
+ this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url });
13109
+ const worker = new Worker(this._loadableURL, { name: this.name });
13110
+ worker.onmessage = (event) => {
13111
+ if (!event.data) {
13112
+ this.onError(new Error("No data received"));
13113
+ } else {
13114
+ this.onMessage(event.data);
13115
+ }
13116
+ };
13117
+ worker.onerror = (error) => {
13118
+ this.onError(this._getErrorFromErrorEvent(error));
13119
+ this.terminated = true;
13120
+ };
13121
+ worker.onmessageerror = (event) => console.error(event);
13122
+ return worker;
13224
13123
  }
13225
- if (ewkbSRID) {
13226
- wkbHeader.variant = "ewkb";
13227
- wkbHeader.srid = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
13228
- wkbHeader.byteOffset += 4;
13124
+ /**
13125
+ * Creates a worker thread in node.js
13126
+ * @todo https://nodejs.org/api/async_hooks.html#async-resource-worker-pool
13127
+ */
13128
+ _createNodeWorker() {
13129
+ let worker;
13130
+ if (this.url) {
13131
+ const absolute = this.url.includes(":/") || this.url.startsWith("/");
13132
+ const url = absolute ? this.url : `./${this.url}`;
13133
+ const type = this.url.endsWith(".ts") || this.url.endsWith(".mjs") ? "module" : "commonjs";
13134
+ worker = new NodeWorker(url, { eval: false, type });
13135
+ } else if (this.source) {
13136
+ worker = new NodeWorker(this.source, { eval: true });
13137
+ } else {
13138
+ throw new Error("no worker");
13139
+ }
13140
+ worker.on("message", (data) => {
13141
+ this.onMessage(data);
13142
+ });
13143
+ worker.on("error", (error) => {
13144
+ this.onError(error);
13145
+ });
13146
+ worker.on("exit", (code) => {
13147
+ });
13148
+ return worker;
13229
13149
  }
13230
- return wkbHeader;
13231
- }
13150
+ };
13232
13151
 
13233
- // ../gis/src/lib/geometry-converters/wkb/convert-wkb-to-binary-geometry.ts
13234
- function convertWKBToBinaryGeometry(arrayBuffer) {
13235
- const dataView = new DataView(arrayBuffer);
13236
- const wkbHeader = parseWKBHeader(dataView);
13237
- const { geometryType, dimensions, littleEndian } = wkbHeader;
13238
- const offset = wkbHeader.byteOffset;
13239
- switch (geometryType) {
13240
- case 1 /* Point */:
13241
- const point = parsePoint(dataView, offset, dimensions, littleEndian);
13242
- return point.geometry;
13243
- case 2 /* LineString */:
13244
- const line = parseLineString(dataView, offset, dimensions, littleEndian);
13245
- return line.geometry;
13246
- case 3 /* Polygon */:
13247
- const polygon = parsePolygon(dataView, offset, dimensions, littleEndian);
13248
- return polygon.geometry;
13249
- case 4 /* MultiPoint */:
13250
- const multiPoint = parseMultiPoint(dataView, offset, dimensions, littleEndian);
13251
- multiPoint.type = "Point";
13252
- return multiPoint;
13253
- case 5 /* MultiLineString */:
13254
- const multiLine = parseMultiLineString(dataView, offset, dimensions, littleEndian);
13255
- multiLine.type = "LineString";
13256
- return multiLine;
13257
- case 6 /* MultiPolygon */:
13258
- const multiPolygon = parseMultiPolygon(dataView, offset, dimensions, littleEndian);
13259
- multiPolygon.type = "Polygon";
13260
- return multiPolygon;
13261
- default:
13262
- throw new Error(`WKB: Unsupported geometry type: ${geometryType}`);
13263
- }
13264
- }
13265
- function parsePoint(dataView, offset, dimension, littleEndian) {
13266
- const positions = new Float64Array(dimension);
13267
- for (let i = 0; i < dimension; i++) {
13268
- positions[i] = dataView.getFloat64(offset, littleEndian);
13269
- offset += 8;
13270
- }
13271
- return {
13272
- geometry: { type: "Point", positions: { value: positions, size: dimension } },
13273
- offset
13152
+ // ../worker-utils/src/lib/worker-farm/worker-pool.ts
13153
+ var WorkerPool = class {
13154
+ name = "unnamed";
13155
+ source;
13156
+ // | Function;
13157
+ url;
13158
+ maxConcurrency = 1;
13159
+ maxMobileConcurrency = 1;
13160
+ onDebug = () => {
13274
13161
  };
13275
- }
13276
- function parseLineString(dataView, offset, dimension, littleEndian) {
13277
- const nPoints = dataView.getUint32(offset, littleEndian);
13278
- offset += 4;
13279
- const positions = new Float64Array(nPoints * dimension);
13280
- for (let i = 0; i < nPoints * dimension; i++) {
13281
- positions[i] = dataView.getFloat64(offset, littleEndian);
13282
- offset += 8;
13283
- }
13284
- const pathIndices = [0];
13285
- if (nPoints > 0) {
13286
- pathIndices.push(nPoints);
13162
+ reuseWorkers = true;
13163
+ props = {};
13164
+ jobQueue = [];
13165
+ idleQueue = [];
13166
+ count = 0;
13167
+ isDestroyed = false;
13168
+ /** Checks if workers are supported on this platform */
13169
+ static isSupported() {
13170
+ return WorkerThread.isSupported();
13287
13171
  }
13288
- return {
13289
- geometry: {
13290
- type: "LineString",
13291
- positions: { value: positions, size: dimension },
13292
- pathIndices: { value: new Uint32Array(pathIndices), size: 1 }
13293
- },
13294
- offset
13295
- };
13296
- }
13297
- var cumulativeSum2 = (sum) => (value) => sum += value;
13298
- function parsePolygon(dataView, offset, dimension, littleEndian) {
13299
- const nRings = dataView.getUint32(offset, littleEndian);
13300
- offset += 4;
13301
- const rings = [];
13302
- for (let i = 0; i < nRings; i++) {
13303
- const parsed = parseLineString(dataView, offset, dimension, littleEndian);
13304
- const { positions } = parsed.geometry;
13305
- offset = parsed.offset;
13306
- rings.push(positions.value);
13172
+ /**
13173
+ * @param processor - worker function
13174
+ * @param maxConcurrency - max count of workers
13175
+ */
13176
+ constructor(props) {
13177
+ this.source = props.source;
13178
+ this.url = props.url;
13179
+ this.setProps(props);
13307
13180
  }
13308
- const concatenatedPositions = new Float64Array(concatTypedArrays(rings).buffer);
13309
- const polygonIndices = [0];
13310
- if (concatenatedPositions.length > 0) {
13311
- polygonIndices.push(concatenatedPositions.length / dimension);
13181
+ /**
13182
+ * Terminates all workers in the pool
13183
+ * @note Can free up significant memory
13184
+ */
13185
+ destroy() {
13186
+ this.idleQueue.forEach((worker) => worker.destroy());
13187
+ this.isDestroyed = true;
13312
13188
  }
13313
- const primitivePolygonIndices = rings.map((l) => l.length / dimension).map(cumulativeSum2(0));
13314
- primitivePolygonIndices.unshift(0);
13315
- return {
13316
- geometry: {
13317
- type: "Polygon",
13318
- positions: { value: concatenatedPositions, size: dimension },
13319
- polygonIndices: {
13320
- value: new Uint32Array(polygonIndices),
13321
- size: 1
13322
- },
13323
- primitivePolygonIndices: { value: new Uint32Array(primitivePolygonIndices), size: 1 }
13324
- },
13325
- offset
13326
- };
13327
- }
13328
- function parseMultiPoint(dataView, offset, dimension, littleEndian) {
13329
- const nPoints = dataView.getUint32(offset, littleEndian);
13330
- offset += 4;
13331
- const binaryPointGeometries = [];
13332
- for (let i = 0; i < nPoints; i++) {
13333
- const littleEndianPoint = dataView.getUint8(offset) === 1;
13334
- offset++;
13335
- if (dataView.getUint32(offset, littleEndianPoint) % 1e3 !== 1) {
13336
- throw new Error("WKB: Inner geometries of MultiPoint not of type Point");
13189
+ setProps(props) {
13190
+ this.props = { ...this.props, ...props };
13191
+ if (props.name !== void 0) {
13192
+ this.name = props.name;
13337
13193
  }
13338
- offset += 4;
13339
- const parsed = parsePoint(dataView, offset, dimension, littleEndianPoint);
13340
- offset = parsed.offset;
13341
- binaryPointGeometries.push(parsed.geometry);
13342
- }
13343
- return concatenateBinaryPointGeometries(binaryPointGeometries, dimension);
13344
- }
13345
- function parseMultiLineString(dataView, offset, dimension, littleEndian) {
13346
- const nLines = dataView.getUint32(offset, littleEndian);
13347
- offset += 4;
13348
- const binaryLineGeometries = [];
13349
- for (let i = 0; i < nLines; i++) {
13350
- const littleEndianLine = dataView.getUint8(offset) === 1;
13351
- offset++;
13352
- if (dataView.getUint32(offset, littleEndianLine) % 1e3 !== 2) {
13353
- throw new Error("WKB: Inner geometries of MultiLineString not of type LineString");
13194
+ if (props.maxConcurrency !== void 0) {
13195
+ this.maxConcurrency = props.maxConcurrency;
13354
13196
  }
13355
- offset += 4;
13356
- const parsed = parseLineString(dataView, offset, dimension, littleEndianLine);
13357
- offset = parsed.offset;
13358
- binaryLineGeometries.push(parsed.geometry);
13359
- }
13360
- return concatenateBinaryLineGeometries(binaryLineGeometries, dimension);
13361
- }
13362
- function parseMultiPolygon(dataView, offset, dimension, littleEndian) {
13363
- const nPolygons = dataView.getUint32(offset, littleEndian);
13364
- offset += 4;
13365
- const binaryPolygonGeometries = [];
13366
- for (let i = 0; i < nPolygons; i++) {
13367
- const littleEndianPolygon = dataView.getUint8(offset) === 1;
13368
- offset++;
13369
- if (dataView.getUint32(offset, littleEndianPolygon) % 1e3 !== 3) {
13370
- throw new Error("WKB: Inner geometries of MultiPolygon not of type Polygon");
13197
+ if (props.maxMobileConcurrency !== void 0) {
13198
+ this.maxMobileConcurrency = props.maxMobileConcurrency;
13199
+ }
13200
+ if (props.reuseWorkers !== void 0) {
13201
+ this.reuseWorkers = props.reuseWorkers;
13202
+ }
13203
+ if (props.onDebug !== void 0) {
13204
+ this.onDebug = props.onDebug;
13371
13205
  }
13372
- offset += 4;
13373
- const parsed = parsePolygon(dataView, offset, dimension, littleEndianPolygon);
13374
- offset = parsed.offset;
13375
- binaryPolygonGeometries.push(parsed.geometry);
13376
13206
  }
13377
- return concatenateBinaryPolygonGeometries(binaryPolygonGeometries, dimension);
13378
- }
13379
-
13380
- // ../gis/src/lib/geometry-converters/wkb/convert-wkb-to-geometry.ts
13381
- function convertWKBToGeometry(arrayBuffer) {
13382
- const binaryGeometry = convertWKBToBinaryGeometry(arrayBuffer);
13383
- return convertBinaryGeometryToGeometry(binaryGeometry);
13384
- }
13385
-
13386
- // ../gis/src/lib/geometry-converters/wkb/convert-wkt-to-geometry.ts
13387
- var numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/;
13388
- var tuples = new RegExp("^" + numberRegexp.source + "(\\s" + numberRegexp.source + "){1,}");
13389
- function convertWKTToGeometry(input, options) {
13390
- const parts = input.split(";");
13391
- let _ = parts.pop();
13392
- const srid = (parts.shift() || "").split("=").pop();
13393
- const state = { parts, _, i: 0 };
13394
- const geometry = parseGeometry(state);
13395
- return options?.wkt?.crs ? addCRS(geometry, srid) : geometry;
13396
- }
13397
- function parseGeometry(state) {
13398
- return parsePoint2(state) || parseLineString2(state) || parsePolygon2(state) || parseMultiPoint2(state) || parseMultiLineString2(state) || parseMultiPolygon2(state) || parseGeometryCollection(state);
13399
- }
13400
- function addCRS(obj, srid) {
13401
- if (obj && srid?.match(/\d+/)) {
13402
- const crs = {
13403
- type: "name",
13404
- properties: {
13405
- name: "urn:ogc:def:crs:EPSG::" + srid
13207
+ async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) {
13208
+ const startPromise = new Promise((onStart) => {
13209
+ this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart });
13210
+ return this;
13211
+ });
13212
+ this._startQueuedJob();
13213
+ return await startPromise;
13214
+ }
13215
+ // PRIVATE
13216
+ /**
13217
+ * Starts first queued job if worker is available or can be created
13218
+ * Called when job is started and whenever a worker returns to the idleQueue
13219
+ */
13220
+ async _startQueuedJob() {
13221
+ if (!this.jobQueue.length) {
13222
+ return;
13223
+ }
13224
+ const workerThread = this._getAvailableWorker();
13225
+ if (!workerThread) {
13226
+ return;
13227
+ }
13228
+ const queuedJob = this.jobQueue.shift();
13229
+ if (queuedJob) {
13230
+ this.onDebug({
13231
+ message: "Starting job",
13232
+ name: queuedJob.name,
13233
+ workerThread,
13234
+ backlog: this.jobQueue.length
13235
+ });
13236
+ const job = new WorkerJob(queuedJob.name, workerThread);
13237
+ workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload);
13238
+ workerThread.onError = (error) => queuedJob.onError(job, error);
13239
+ queuedJob.onStart(job);
13240
+ try {
13241
+ await job.result;
13242
+ } catch (error) {
13243
+ console.error(`Worker exception: ${error}`);
13244
+ } finally {
13245
+ this.returnWorkerToQueue(workerThread);
13406
13246
  }
13407
- };
13408
- obj.crs = crs;
13247
+ }
13248
+ }
13249
+ /**
13250
+ * Returns a worker to the idle queue
13251
+ * Destroys the worker if
13252
+ * - pool is destroyed
13253
+ * - if this pool doesn't reuse workers
13254
+ * - if maxConcurrency has been lowered
13255
+ * @param worker
13256
+ */
13257
+ returnWorkerToQueue(worker) {
13258
+ const shouldDestroyWorker = (
13259
+ // Workers on Node.js prevent the process from exiting.
13260
+ // Until we figure out how to close them before exit, we always destroy them
13261
+ !isBrowser || // If the pool is destroyed, there is no reason to keep the worker around
13262
+ this.isDestroyed || // If the app has disabled worker reuse, any completed workers should be destroyed
13263
+ !this.reuseWorkers || // If concurrency has been lowered, this worker might be surplus to requirements
13264
+ this.count > this._getMaxConcurrency()
13265
+ );
13266
+ if (shouldDestroyWorker) {
13267
+ worker.destroy();
13268
+ this.count--;
13269
+ } else {
13270
+ this.idleQueue.push(worker);
13271
+ }
13272
+ if (!this.isDestroyed) {
13273
+ this._startQueuedJob();
13274
+ }
13409
13275
  }
13410
- return obj;
13411
- }
13412
- function parsePoint2(state) {
13413
- if (!$(/^(POINT(\sz)?)/i, state)) {
13276
+ /**
13277
+ * Returns idle worker or creates new worker if maxConcurrency has not been reached
13278
+ */
13279
+ _getAvailableWorker() {
13280
+ if (this.idleQueue.length > 0) {
13281
+ return this.idleQueue.shift() || null;
13282
+ }
13283
+ if (this.count < this._getMaxConcurrency()) {
13284
+ this.count++;
13285
+ const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
13286
+ return new WorkerThread({ name, source: this.source, url: this.url });
13287
+ }
13414
13288
  return null;
13415
13289
  }
13416
- white(state);
13417
- if (!$(/^(\()/, state)) {
13418
- return null;
13290
+ _getMaxConcurrency() {
13291
+ return isMobile ? this.maxMobileConcurrency : this.maxConcurrency;
13419
13292
  }
13420
- const c = coords(state);
13421
- if (!c) {
13422
- return null;
13293
+ };
13294
+
13295
+ // ../worker-utils/src/lib/worker-farm/worker-farm.ts
13296
+ var DEFAULT_PROPS = {
13297
+ maxConcurrency: 3,
13298
+ maxMobileConcurrency: 1,
13299
+ reuseWorkers: true,
13300
+ onDebug: () => {
13423
13301
  }
13424
- white(state);
13425
- if (!$(/^(\))/, state)) {
13426
- return null;
13302
+ };
13303
+ var _WorkerFarm = class {
13304
+ props;
13305
+ workerPools = /* @__PURE__ */ new Map();
13306
+ /** Checks if workers are supported on this platform */
13307
+ static isSupported() {
13308
+ return WorkerThread.isSupported();
13427
13309
  }
13428
- return {
13429
- type: "Point",
13430
- coordinates: c[0]
13431
- };
13432
- }
13433
- function parseMultiPoint2(state) {
13434
- if (!$(/^(MULTIPOINT)/i, state)) {
13435
- return null;
13310
+ /** Get the singleton instance of the global worker farm */
13311
+ static getWorkerFarm(props = {}) {
13312
+ _WorkerFarm._workerFarm = _WorkerFarm._workerFarm || new _WorkerFarm({});
13313
+ _WorkerFarm._workerFarm.setProps(props);
13314
+ return _WorkerFarm._workerFarm;
13436
13315
  }
13437
- white(state);
13438
- const newCoordsFormat = state._?.substring(state._?.indexOf("(") + 1, state._.length - 1).replace(/\(/g, "").replace(/\)/g, "");
13439
- state._ = "MULTIPOINT (" + newCoordsFormat + ")";
13440
- const c = multicoords(state);
13441
- if (!c) {
13442
- return null;
13316
+ /** get global instance with WorkerFarm.getWorkerFarm() */
13317
+ constructor(props) {
13318
+ this.props = { ...DEFAULT_PROPS };
13319
+ this.setProps(props);
13320
+ this.workerPools = /* @__PURE__ */ new Map();
13443
13321
  }
13444
- white(state);
13445
- return {
13446
- type: "MultiPoint",
13447
- coordinates: c
13448
- };
13449
- }
13450
- function parseLineString2(state) {
13451
- if (!$(/^(LINESTRING(\sz)?)/i, state)) {
13452
- return null;
13322
+ /**
13323
+ * Terminate all workers in the farm
13324
+ * @note Can free up significant memory
13325
+ */
13326
+ destroy() {
13327
+ for (const workerPool of this.workerPools.values()) {
13328
+ workerPool.destroy();
13329
+ }
13330
+ this.workerPools = /* @__PURE__ */ new Map();
13453
13331
  }
13454
- white(state);
13455
- if (!$(/^(\()/, state)) {
13456
- return null;
13332
+ /**
13333
+ * Set props used when initializing worker pools
13334
+ * @param props
13335
+ */
13336
+ setProps(props) {
13337
+ this.props = { ...this.props, ...props };
13338
+ for (const workerPool of this.workerPools.values()) {
13339
+ workerPool.setProps(this._getWorkerPoolProps());
13340
+ }
13457
13341
  }
13458
- const c = coords(state);
13459
- if (!c) {
13460
- return null;
13342
+ /**
13343
+ * Returns a worker pool for the specified worker
13344
+ * @param options - only used first time for a specific worker name
13345
+ * @param options.name - the name of the worker - used to identify worker pool
13346
+ * @param options.url -
13347
+ * @param options.source -
13348
+ * @example
13349
+ * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
13350
+ */
13351
+ getWorkerPool(options) {
13352
+ const { name, source, url } = options;
13353
+ let workerPool = this.workerPools.get(name);
13354
+ if (!workerPool) {
13355
+ workerPool = new WorkerPool({
13356
+ name,
13357
+ source,
13358
+ url
13359
+ });
13360
+ workerPool.setProps(this._getWorkerPoolProps());
13361
+ this.workerPools.set(name, workerPool);
13362
+ }
13363
+ return workerPool;
13461
13364
  }
13462
- if (!$(/^(\))/, state)) {
13463
- return null;
13365
+ _getWorkerPoolProps() {
13366
+ return {
13367
+ maxConcurrency: this.props.maxConcurrency,
13368
+ maxMobileConcurrency: this.props.maxMobileConcurrency,
13369
+ reuseWorkers: this.props.reuseWorkers,
13370
+ onDebug: this.props.onDebug
13371
+ };
13464
13372
  }
13465
- return {
13466
- type: "LineString",
13467
- coordinates: c
13468
- };
13373
+ };
13374
+ var WorkerFarm = _WorkerFarm;
13375
+ // singleton
13376
+ __publicField(WorkerFarm, "_workerFarm");
13377
+
13378
+ // ../worker-utils/src/lib/worker-api/get-worker-url.ts
13379
+ function getWorkerName(worker) {
13380
+ const warning = worker.version !== VERSION2 ? ` (worker-utils@${VERSION2})` : "";
13381
+ return `${worker.name}@${worker.version}${warning}`;
13469
13382
  }
13470
- function parseMultiLineString2(state) {
13471
- if (!$(/^(MULTILINESTRING)/i, state))
13472
- return null;
13473
- white(state);
13474
- const c = multicoords(state);
13475
- if (!c) {
13476
- return null;
13383
+ function getWorkerURL(worker, options = {}) {
13384
+ const workerOptions = options[worker.id] || {};
13385
+ const workerFile = isBrowser ? `${worker.id}-worker.js` : `${worker.id}-worker-node.js`;
13386
+ let url = workerOptions.workerUrl;
13387
+ if (!url && worker.id === "compression") {
13388
+ url = options.workerUrl;
13477
13389
  }
13478
- white(state);
13479
- return {
13480
- // @ts-ignore
13481
- type: "MultiLineString",
13482
- // @ts-expect-error
13483
- coordinates: c
13484
- };
13485
- }
13486
- function parsePolygon2(state) {
13487
- if (!$(/^(POLYGON(\sz)?)/i, state)) {
13488
- return null;
13390
+ const workerType = options._workerType || options?.core?._workerType;
13391
+ if (workerType === "test") {
13392
+ if (isBrowser) {
13393
+ url = `modules/${worker.module}/dist/${workerFile}`;
13394
+ } else {
13395
+ url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`;
13396
+ }
13489
13397
  }
13490
- white(state);
13491
- const c = multicoords(state);
13492
- if (!c) {
13493
- return null;
13398
+ if (!url) {
13399
+ let version = worker.version;
13400
+ if (version === "latest") {
13401
+ version = NPM_TAG;
13402
+ }
13403
+ const versionTag = version ? `@${version}` : "";
13404
+ url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
13494
13405
  }
13495
- return {
13496
- // @ts-ignore
13497
- type: "Polygon",
13498
- // @ts-expect-error
13499
- coordinates: c
13500
- };
13406
+ assert(url);
13407
+ return url;
13501
13408
  }
13502
- function parseMultiPolygon2(state) {
13503
- if (!$(/^(MULTIPOLYGON)/i, state)) {
13504
- return null;
13409
+
13410
+ // ../worker-utils/src/lib/worker-api/process-on-worker.ts
13411
+ async function processOnWorker(worker, data, options = {}, context = {}) {
13412
+ const name = getWorkerName(worker);
13413
+ const workerFarm = WorkerFarm.getWorkerFarm(options);
13414
+ const { source } = options;
13415
+ const workerPoolProps = { name, source };
13416
+ if (!source) {
13417
+ workerPoolProps.url = getWorkerURL(worker, options);
13505
13418
  }
13506
- white(state);
13507
- const c = multicoords(state);
13508
- if (!c) {
13509
- return null;
13419
+ const workerPool = workerFarm.getWorkerPool(workerPoolProps);
13420
+ const jobName = options.jobName || worker.name;
13421
+ const job = await workerPool.startJob(
13422
+ jobName,
13423
+ // eslint-disable-next-line
13424
+ onMessage.bind(null, context)
13425
+ );
13426
+ const transferableOptions = getTransferListForWriter(options);
13427
+ job.postMessage("process", { input: data, options: transferableOptions });
13428
+ const result = await job.result;
13429
+ return result.result;
13430
+ }
13431
+ async function onMessage(context, job, type, payload) {
13432
+ switch (type) {
13433
+ case "done":
13434
+ job.done(payload);
13435
+ break;
13436
+ case "error":
13437
+ job.error(new Error(payload.error));
13438
+ break;
13439
+ case "process":
13440
+ const { id, input, options } = payload;
13441
+ try {
13442
+ if (!context.process) {
13443
+ job.postMessage("error", { id, error: "Worker not set up to process on main thread" });
13444
+ return;
13445
+ }
13446
+ const result = await context.process(input, options);
13447
+ job.postMessage("done", { id, result });
13448
+ } catch (error) {
13449
+ const message = error instanceof Error ? error.message : "unknown error";
13450
+ job.postMessage("error", { id, error: message });
13451
+ }
13452
+ break;
13453
+ default:
13454
+ console.warn(`process-on-worker: unknown message ${type}`);
13510
13455
  }
13511
- return {
13512
- type: "MultiPolygon",
13513
- // @ts-expect-error
13514
- coordinates: c
13515
- };
13516
13456
  }
13517
- function parseGeometryCollection(state) {
13518
- const geometries = [];
13519
- let geometry;
13520
- if (!$(/^(GEOMETRYCOLLECTION)/i, state)) {
13521
- return null;
13522
- }
13523
- white(state);
13524
- if (!$(/^(\()/, state)) {
13525
- return null;
13457
+
13458
+ // ../loader-utils/src/lib/iterators/async-iteration.ts
13459
+ async function* toArrayBufferIterator(asyncIterator) {
13460
+ for await (const chunk of asyncIterator) {
13461
+ yield copyToArrayBuffer(chunk);
13526
13462
  }
13527
- while (geometry = parseGeometry(state)) {
13528
- geometries.push(geometry);
13529
- white(state);
13530
- $(/^(,)/, state);
13531
- white(state);
13463
+ }
13464
+ function copyToArrayBuffer(chunk) {
13465
+ if (chunk instanceof ArrayBuffer) {
13466
+ return chunk;
13532
13467
  }
13533
- if (!$(/^(\))/, state)) {
13534
- return null;
13468
+ if (ArrayBuffer.isView(chunk)) {
13469
+ const { buffer, byteOffset, byteLength } = chunk;
13470
+ return copyFromBuffer(buffer, byteOffset, byteLength);
13535
13471
  }
13536
- return {
13537
- type: "GeometryCollection",
13538
- geometries
13539
- };
13472
+ return copyFromBuffer(chunk);
13540
13473
  }
13541
- function multicoords(state) {
13542
- white(state);
13543
- let depth = 0;
13544
- const rings = [];
13545
- const stack = [rings];
13546
- let pointer = rings;
13547
- let elem;
13548
- while (elem = $(/^(\()/, state) || $(/^(\))/, state) || $(/^(,)/, state) || $(tuples, state)) {
13549
- if (elem === "(") {
13550
- stack.push(pointer);
13551
- pointer = [];
13552
- stack[stack.length - 1].push(pointer);
13553
- depth++;
13554
- } else if (elem === ")") {
13555
- if (pointer.length === 0)
13556
- return null;
13557
- pointer = stack.pop();
13558
- if (!pointer)
13559
- return null;
13560
- depth--;
13561
- if (depth === 0)
13562
- break;
13563
- } else if (elem === ",") {
13564
- pointer = [];
13565
- stack[stack.length - 1].push(pointer);
13566
- } else if (!elem.split(/\s/g).some(isNaN)) {
13567
- Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat));
13568
- } else {
13569
- return null;
13570
- }
13571
- white(state);
13572
- }
13573
- if (depth !== 0)
13574
- return null;
13575
- return rings;
13474
+ function copyFromBuffer(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
13475
+ const view = new Uint8Array(buffer, byteOffset, byteLength);
13476
+ const copy = new Uint8Array(view.length);
13477
+ copy.set(view);
13478
+ return copy.buffer;
13576
13479
  }
13577
- function coords(state) {
13578
- const list = [];
13579
- let item;
13580
- let pt;
13581
- while (pt = $(tuples, state) || $(/^(,)/, state)) {
13582
- if (pt === ",") {
13583
- list.push(item);
13584
- item = [];
13585
- } else if (!pt.split(/\s/g).some(isNaN)) {
13586
- if (!item)
13587
- item = [];
13588
- Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat));
13589
- }
13590
- white(state);
13480
+
13481
+ // ../loader-utils/src/lib/binary-utils/memory-conversion-utils.ts
13482
+ function ensureArrayBuffer(bufferSource) {
13483
+ if (bufferSource instanceof ArrayBuffer) {
13484
+ return bufferSource;
13591
13485
  }
13592
- if (item)
13593
- list.push(item);
13594
- else
13595
- return null;
13596
- return list.length ? list : null;
13597
- }
13598
- function $(regexp, state) {
13599
- const match = state._?.substring(state.i).match(regexp);
13600
- if (!match)
13601
- return null;
13602
- else {
13603
- state.i += match[0].length;
13604
- return match[0];
13486
+ if (isSharedArrayBuffer(bufferSource)) {
13487
+ return copyToArrayBuffer2(bufferSource);
13488
+ }
13489
+ const { buffer, byteOffset, byteLength } = bufferSource;
13490
+ if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength) {
13491
+ return buffer;
13605
13492
  }
13493
+ return copyToArrayBuffer2(buffer, byteOffset, byteLength);
13606
13494
  }
13607
- function white(state) {
13608
- $(/^\s*/, state);
13495
+ function copyToArrayBuffer2(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
13496
+ const view = new Uint8Array(buffer, byteOffset, byteLength);
13497
+ const copy = new Uint8Array(view.length);
13498
+ copy.set(view);
13499
+ return copy.buffer;
13609
13500
  }
13610
13501
 
13611
- // ../gis/src/lib/geometry-converters/convert-geoarrow-to-geojson.ts
13612
- function convertGeoArrowGeometryToGeoJSON(arrowCellValue, encoding) {
13613
- encoding = encoding?.toLowerCase();
13614
- if (!encoding || !arrowCellValue) {
13615
- return null;
13616
- }
13617
- switch (encoding) {
13618
- case "geoarrow.multipolygon":
13619
- return arrowMultiPolygonToGeometry(arrowCellValue);
13620
- case "geoarrow.polygon":
13621
- return arrowPolygonToGeometry(arrowCellValue);
13622
- case "geoarrow.multipoint":
13623
- return arrowMultiPointToGeometry(arrowCellValue);
13624
- case "geoarrow.point":
13625
- return arrowPointToGeometry(arrowCellValue);
13626
- case "geoarrow.multilinestring":
13627
- return arrowMultiLineStringToGeometry(arrowCellValue);
13628
- case "geoarrow.linestring":
13629
- return arrowLineStringToGeometry(arrowCellValue);
13630
- case "geoarrow.wkb":
13631
- return arrowWKBToGeometry(arrowCellValue);
13632
- case "geoarrow.wkt":
13633
- return arrowWKTToGeometry(arrowCellValue);
13634
- default: {
13635
- throw Error(`GeoArrow encoding not supported ${encoding}`);
13502
+ // src/lib/parsers/parse-arrow.ts
13503
+ function parseArrowSync(arrayBuffer, options) {
13504
+ const shape = options?.shape || "arrow-table";
13505
+ const arrowTable = tableFromIPC([new Uint8Array(arrayBuffer)]);
13506
+ return convertArrowToTable(arrowTable, shape);
13507
+ }
13508
+ function parseArrowInBatches(asyncIterator, options) {
13509
+ async function* makeArrowAsyncIterator() {
13510
+ const readers = RecordBatchReader.readAll(toArrayBufferIterator(asyncIterator));
13511
+ for await (const reader of readers) {
13512
+ for await (const recordBatch of reader) {
13513
+ if (options?.arrow?.batchDebounceMs !== void 0 && options?.arrow?.batchDebounceMs > 0) {
13514
+ await new Promise((resolve) => setTimeout(resolve, options.arrow?.batchDebounceMs || 0));
13515
+ }
13516
+ const arrowTabledBatch = {
13517
+ shape: "arrow-table",
13518
+ batchType: "data",
13519
+ data: new Table([recordBatch]),
13520
+ length: recordBatch.data.length
13521
+ };
13522
+ yield arrowTabledBatch;
13523
+ }
13524
+ break;
13636
13525
  }
13637
13526
  }
13527
+ return makeArrowAsyncIterator();
13638
13528
  }
13639
- function arrowWKBToGeometry(arrowCellValue) {
13640
- const arrayBuffer = arrowCellValue.buffer.slice(
13641
- arrowCellValue.byteOffset,
13642
- arrowCellValue.byteOffset + arrowCellValue.byteLength
13643
- );
13644
- return convertWKBToGeometry(arrayBuffer);
13529
+
13530
+ // src/arrow-loader.ts
13531
+ var ArrowLoader = {
13532
+ ...ArrowWorkerLoader,
13533
+ parse: async (arraybuffer, options) => parseArrowSync(arraybuffer, options?.arrow),
13534
+ parseSync: (arraybuffer, options) => parseArrowSync(arraybuffer, options?.arrow),
13535
+ parseInBatches: parseArrowInBatches
13536
+ };
13537
+
13538
+ // src/lib/encoders/encode-arrow.ts
13539
+ function encodeArrowSync(data) {
13540
+ const vectors = {};
13541
+ for (const arrayData of data) {
13542
+ const arrayVector = createVector(arrayData.array, arrayData.type);
13543
+ vectors[arrayData.name] = arrayVector;
13544
+ }
13545
+ const table = new Table(vectors);
13546
+ const arrowBuffer = tableToIPC(table);
13547
+ return ensureArrayBuffer(arrowBuffer);
13645
13548
  }
13646
- function arrowWKTToGeometry(arrowCellValue) {
13647
- const string = arrowCellValue;
13648
- return convertWKTToGeometry(string);
13549
+ function createVector(array, type) {
13550
+ switch (type) {
13551
+ case 1 /* DATE */:
13552
+ return vectorFromArray(array);
13553
+ case 0 /* FLOAT */:
13554
+ default:
13555
+ return vectorFromArray(array);
13556
+ }
13649
13557
  }
13650
- function arrowMultiPolygonToGeometry(arrowMultiPolygon) {
13651
- const multiPolygon = [];
13652
- for (let m = 0; m < arrowMultiPolygon.length; m++) {
13653
- const arrowPolygon = arrowMultiPolygon.get(m);
13654
- const polygon = [];
13655
- for (let i = 0; arrowPolygon && i < arrowPolygon?.length; i++) {
13656
- const arrowRing = arrowPolygon?.get(i);
13657
- const ring = [];
13658
- for (let j = 0; arrowRing && j < arrowRing.length; j++) {
13659
- const arrowCoord = arrowRing.get(j);
13660
- const coord = Array.from(arrowCoord);
13661
- ring.push(coord);
13662
- }
13663
- polygon.push(ring);
13558
+
13559
+ // src/arrow-writer.ts
13560
+ var VERSION3 = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
13561
+ var ArrowWriter = {
13562
+ name: "Apache Arrow",
13563
+ id: "arrow",
13564
+ module: "arrow",
13565
+ version: VERSION3,
13566
+ extensions: ["arrow", "feather"],
13567
+ mimeTypes: [
13568
+ "application/vnd.apache.arrow.file",
13569
+ "application/vnd.apache.arrow.stream",
13570
+ "application/octet-stream"
13571
+ ],
13572
+ binary: true,
13573
+ options: {},
13574
+ encode: async function encodeArrow(data, options) {
13575
+ return encodeArrowSync(data);
13576
+ },
13577
+ encodeSync(data, options) {
13578
+ return encodeArrowSync(data);
13579
+ }
13580
+ };
13581
+
13582
+ // src/exports/geoarrow-loader.ts
13583
+ var GeoArrowWorkerLoader = {
13584
+ ...ArrowWorkerLoader,
13585
+ options: {
13586
+ arrow: {
13587
+ shape: "arrow-table"
13664
13588
  }
13665
- multiPolygon.push(polygon);
13666
13589
  }
13667
- const geometry = {
13668
- type: "MultiPolygon",
13669
- coordinates: multiPolygon
13670
- };
13671
- return geometry;
13590
+ };
13591
+
13592
+ // ../geoarrow/src/metadata/metadata-utils.ts
13593
+ function getMetadataValue(metadata, key) {
13594
+ return metadata instanceof Map ? metadata.get(key) || null : metadata[key] || null;
13672
13595
  }
13673
- function arrowPolygonToGeometry(arrowPolygon) {
13674
- const polygon = [];
13675
- for (let i = 0; arrowPolygon && i < arrowPolygon.length; i++) {
13676
- const arrowRing = arrowPolygon.get(i);
13677
- const ring = [];
13678
- for (let j = 0; arrowRing && j < arrowRing.length; j++) {
13679
- const arrowCoord = arrowRing.get(j);
13680
- const coords2 = Array.from(arrowCoord);
13681
- ring.push(coords2);
13596
+
13597
+ // ../geoarrow/src/metadata/geoarrow-metadata.ts
13598
+ var GEOARROW_ENCODINGS = [
13599
+ "geoarrow.multipolygon",
13600
+ "geoarrow.polygon",
13601
+ "geoarrow.multilinestring",
13602
+ "geoarrow.linestring",
13603
+ "geoarrow.multipoint",
13604
+ "geoarrow.point",
13605
+ "geoarrow.wkb",
13606
+ "geoarrow.wkt"
13607
+ ];
13608
+ var GEOARROW_ENCODING = "ARROW:extension:name";
13609
+ var GEOARROW_METADATA = "ARROW:extension:metadata";
13610
+ function getGeometryColumnsFromSchema(schema) {
13611
+ const geometryColumns = {};
13612
+ for (const field of schema.fields || []) {
13613
+ const metadata = getGeometryMetadataForField(field?.metadata || {});
13614
+ if (metadata) {
13615
+ geometryColumns[field.name] = metadata;
13682
13616
  }
13683
- polygon.push(ring);
13684
13617
  }
13685
- const geometry = {
13686
- type: "Polygon",
13687
- coordinates: polygon
13688
- };
13689
- return geometry;
13618
+ return geometryColumns;
13690
13619
  }
13691
- function arrowMultiPointToGeometry(arrowMultiPoint) {
13692
- const multiPoint = [];
13693
- for (let i = 0; arrowMultiPoint && i < arrowMultiPoint.length; i++) {
13694
- const arrowPoint = arrowMultiPoint.get(i);
13695
- if (arrowPoint) {
13696
- const coord = Array.from(arrowPoint);
13697
- multiPoint.push(coord);
13620
+ function getGeometryMetadataForField(fieldMetadata) {
13621
+ let metadata = null;
13622
+ let geoEncoding = getMetadataValue(fieldMetadata, GEOARROW_ENCODING);
13623
+ if (geoEncoding) {
13624
+ geoEncoding = geoEncoding.toLowerCase();
13625
+ if (geoEncoding === "wkb") {
13626
+ geoEncoding = "geoarrow.wkb";
13698
13627
  }
13699
- }
13700
- return {
13701
- type: "MultiPoint",
13702
- coordinates: multiPoint
13703
- };
13704
- }
13705
- function arrowPointToGeometry(arrowPoint) {
13706
- const point = Array.from(arrowPoint);
13707
- return {
13708
- type: "Point",
13709
- coordinates: point
13710
- };
13711
- }
13712
- function arrowMultiLineStringToGeometry(arrowMultiLineString) {
13713
- const multiLineString = [];
13714
- for (let i = 0; arrowMultiLineString && i < arrowMultiLineString.length; i++) {
13715
- const arrowLineString = arrowMultiLineString.get(i);
13716
- const lineString = [];
13717
- for (let j = 0; arrowLineString && j < arrowLineString.length; j++) {
13718
- const arrowCoord = arrowLineString.get(j);
13719
- if (arrowCoord) {
13720
- const coords2 = Array.from(arrowCoord);
13721
- lineString.push(coords2);
13722
- }
13628
+ if (geoEncoding === "wkt") {
13629
+ geoEncoding = "geoarrow.wkt";
13630
+ }
13631
+ if (!GEOARROW_ENCODINGS.includes(geoEncoding)) {
13632
+ console.warn(`Invalid GeoArrow encoding: ${geoEncoding}`);
13633
+ } else {
13634
+ metadata ||= {};
13635
+ metadata.encoding = geoEncoding;
13723
13636
  }
13724
- multiLineString.push(lineString);
13725
13637
  }
13726
- return {
13727
- type: "MultiLineString",
13728
- coordinates: multiLineString
13729
- };
13730
- }
13731
- function arrowLineStringToGeometry(arrowLineString) {
13732
- const lineString = [];
13733
- for (let i = 0; arrowLineString && i < arrowLineString.length; i++) {
13734
- const arrowCoord = arrowLineString.get(i);
13735
- if (arrowCoord) {
13736
- const coords2 = Array.from(arrowCoord);
13737
- lineString.push(coords2);
13638
+ const columnMetadata = getMetadataValue(fieldMetadata, GEOARROW_METADATA);
13639
+ if (columnMetadata) {
13640
+ try {
13641
+ metadata = JSON.parse(columnMetadata);
13642
+ } catch (error) {
13643
+ console.warn("Failed to parse GeoArrow metadata", error);
13738
13644
  }
13739
13645
  }
13740
- return {
13741
- type: "LineString",
13742
- coordinates: lineString
13743
- };
13646
+ return metadata || null;
13744
13647
  }
13745
13648
 
13746
- // ../gis/src/lib/table-converters/convert-geoarrow-table.ts
13747
- function convertGeoArrowToTable(arrowTable, shape) {
13748
- switch (shape) {
13749
- case "arrow-table":
13750
- return convertArrowToArrowTable2(arrowTable);
13751
- case "array-row-table":
13752
- return convertArrowToArrayRowTable2(arrowTable);
13753
- case "object-row-table":
13754
- return convertArrowToObjectRowTable2(arrowTable);
13755
- case "columnar-table":
13756
- return convertArrowToColumnarTable2(arrowTable);
13757
- case "geojson-table":
13758
- return convertArrowToGeoJSONTable2(arrowTable);
13649
+ // ../gis/src/lib/geometry-converters/convert-binary-geometry-to-geojson.ts
13650
+ function convertBinaryGeometryToGeometry(data, startIndex, endIndex) {
13651
+ switch (data.type) {
13652
+ case "Point":
13653
+ return pointToGeoJson(data, startIndex, endIndex);
13654
+ case "LineString":
13655
+ return lineStringToGeoJson(data, startIndex, endIndex);
13656
+ case "Polygon":
13657
+ return polygonToGeoJson(data, startIndex, endIndex);
13759
13658
  default:
13760
- throw new Error(shape);
13761
- }
13762
- }
13763
- function convertArrowToArrowTable2(arrowTable) {
13764
- return {
13765
- shape: "arrow-table",
13766
- schema: convertArrowToSchema(arrowTable.schema),
13767
- data: arrowTable
13768
- };
13769
- }
13770
- function convertArrowToArrayRowTable2(arrowTable) {
13771
- const columnarTable = convertArrowToColumnarTable2(arrowTable);
13772
- return convertTable(columnarTable, "array-row-table");
13773
- }
13774
- function convertArrowToObjectRowTable2(arrowTable) {
13775
- const columnarTable = convertArrowToColumnarTable2(arrowTable);
13776
- return convertTable(columnarTable, "object-row-table");
13777
- }
13778
- function convertArrowToColumnarTable2(arrowTable) {
13779
- const columns = {};
13780
- for (const field of arrowTable.schema.fields) {
13781
- const arrowColumn = arrowTable.getChild(field.name);
13782
- const values = arrowColumn?.toArray();
13783
- columns[field.name] = values;
13659
+ const unexpectedInput = data;
13660
+ throw new Error(`Unsupported geometry type: ${unexpectedInput?.type}`);
13784
13661
  }
13785
- const schema = convertArrowToSchema(arrowTable.schema);
13786
- return {
13787
- shape: "columnar-table",
13788
- schema,
13789
- data: columns
13790
- };
13791
13662
  }
13792
- function convertArrowToGeoJSONTable2(arrowTable) {
13793
- const schema = convertArrowToSchema(arrowTable.schema);
13794
- const geometryColumns = getGeometryColumnsFromSchema(schema);
13795
- const encoding = geometryColumns.geometry.encoding;
13796
- const features = [];
13797
- const propertyColumnNames = arrowTable.schema.fields.map((field) => field.name).filter((name) => !(name in geometryColumns));
13798
- const propertiesTable = arrowTable.select(propertyColumnNames);
13799
- const arrowGeometryColumn = arrowTable.getChild("geometry");
13800
- for (let row = 0; row < arrowTable.numRows; row++) {
13801
- const arrowGeometry = arrowGeometryColumn?.get(row);
13802
- const feature = convertGeoArrowGeometryToGeoJSON(arrowGeometry, encoding);
13803
- if (feature) {
13804
- const properties = propertiesTable.get(row)?.toJSON() || {};
13805
- features.push({ type: "Feature", geometry: feature, properties });
13663
+ function polygonToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) {
13664
+ const { positions } = data;
13665
+ const polygonIndices = data.polygonIndices.value.filter((x) => x >= startIndex && x <= endIndex);
13666
+ const primitivePolygonIndices = data.primitivePolygonIndices.value.filter(
13667
+ (x) => x >= startIndex && x <= endIndex
13668
+ );
13669
+ const multi = polygonIndices.length > 2;
13670
+ if (!multi) {
13671
+ const coordinates2 = [];
13672
+ for (let i = 0; i < primitivePolygonIndices.length - 1; i++) {
13673
+ const startRingIndex = primitivePolygonIndices[i];
13674
+ const endRingIndex = primitivePolygonIndices[i + 1];
13675
+ const ringCoordinates = ringToGeoJson(positions, startRingIndex, endRingIndex);
13676
+ coordinates2.push(ringCoordinates);
13806
13677
  }
13678
+ return { type: "Polygon", coordinates: coordinates2 };
13807
13679
  }
13808
- return {
13809
- shape: "geojson-table",
13810
- type: "FeatureCollection",
13811
- schema,
13812
- features
13813
- };
13814
- }
13815
-
13816
- // src/lib/parsers/parse-geoarrow.ts
13817
- function parseGeoArrowSync(arrayBuffer, options) {
13818
- const table = parseArrowSync(arrayBuffer, { shape: "arrow-table" });
13819
- switch (options?.shape) {
13820
- case "geojson-table":
13821
- return convertGeoArrowToTable(table.data, "geojson-table");
13822
- default:
13823
- return table;
13680
+ const coordinates = [];
13681
+ for (let i = 0; i < polygonIndices.length - 1; i++) {
13682
+ const startPolygonIndex = polygonIndices[i];
13683
+ const endPolygonIndex = polygonIndices[i + 1];
13684
+ const polygonCoordinates = polygonToGeoJson(
13685
+ data,
13686
+ startPolygonIndex,
13687
+ endPolygonIndex
13688
+ ).coordinates;
13689
+ coordinates.push(polygonCoordinates);
13824
13690
  }
13691
+ return { type: "MultiPolygon", coordinates };
13825
13692
  }
13826
- function parseGeoArrowInBatches(asyncIterator) {
13827
- return parseArrowInBatches(asyncIterator);
13828
- }
13829
-
13830
- // src/geoarrow-loader.ts
13831
- var GeoArrowLoader = {
13832
- ...GeoArrowWorkerLoader,
13833
- parse: async (arraybuffer, options) => parseGeoArrowSync(arraybuffer, options?.arrow),
13834
- parseSync: (arraybuffer, options) => parseGeoArrowSync(arraybuffer, options?.arrow),
13835
- parseInBatches: parseGeoArrowInBatches
13836
- };
13837
-
13838
- // src/workers/hard-clone.ts
13839
- function hardClone(data, force = false) {
13840
- if ("data" in data) {
13841
- return new Vector(data.data.map((data2) => hardClone(data2, force)));
13842
- }
13843
- const clonedChildren = [];
13844
- for (const childData of data.children) {
13845
- clonedChildren.push(hardClone(childData, force));
13693
+ function lineStringToGeoJson(data, startIndex = -Infinity, endIndex = Infinity) {
13694
+ const { positions } = data;
13695
+ const pathIndices = data.pathIndices.value.filter((x) => x >= startIndex && x <= endIndex);
13696
+ const multi = pathIndices.length > 2;
13697
+ if (!multi) {
13698
+ const coordinates2 = ringToGeoJson(positions, pathIndices[0], pathIndices[1]);
13699
+ return { type: "LineString", coordinates: coordinates2 };
13846
13700
  }
13847
- let clonedDictionary;
13848
- if (data.dictionary !== void 0) {
13849
- clonedDictionary = hardClone(data.dictionary, force);
13701
+ const coordinates = [];
13702
+ for (let i = 0; i < pathIndices.length - 1; i++) {
13703
+ const ringCoordinates = ringToGeoJson(positions, pathIndices[i], pathIndices[i + 1]);
13704
+ coordinates.push(ringCoordinates);
13850
13705
  }
13851
- const clonedBuffers = {
13852
- [BufferType.OFFSET]: cloneBuffer(data.buffers[BufferType.OFFSET], force),
13853
- [BufferType.DATA]: cloneBuffer(data.buffers[BufferType.DATA], force),
13854
- [BufferType.VALIDITY]: cloneBuffer(data.buffers[BufferType.VALIDITY], force),
13855
- [BufferType.TYPE]: cloneBuffer(data.buffers[BufferType.TYPE], force)
13856
- };
13857
- return new Data(
13858
- data.type,
13859
- data.offset,
13860
- data.length,
13861
- // @ts-expect-error _nullCount is protected. We're using it here to mimic
13862
- // `Data.clone`
13863
- data._nullCount,
13864
- clonedBuffers,
13865
- clonedChildren,
13866
- clonedDictionary
13867
- );
13868
- }
13869
- function isTypedArraySliced(arr) {
13870
- return !(arr.byteOffset === 0 && arr.byteLength === arr.buffer.byteLength);
13706
+ return { type: "MultiLineString", coordinates };
13871
13707
  }
13872
- function cloneBuffer(arr, force) {
13873
- if (arr === void 0) {
13874
- return arr;
13875
- }
13876
- if (!force && !isTypedArraySliced(arr)) {
13877
- return arr;
13708
+ function pointToGeoJson(data, startIndex, endIndex) {
13709
+ const { positions } = data;
13710
+ const coordinates = ringToGeoJson(positions, startIndex, endIndex);
13711
+ const multi = coordinates.length > 1;
13712
+ if (multi) {
13713
+ return { type: "MultiPoint", coordinates };
13878
13714
  }
13879
- return arr.slice();
13715
+ return { type: "Point", coordinates: coordinates[0] };
13880
13716
  }
13881
-
13882
- // ../worker-utils/src/lib/npm-tag.ts
13883
- var NPM_TAG = "beta";
13884
-
13885
- // ../worker-utils/src/lib/env-utils/version.ts
13886
- function getVersion() {
13887
- if (!globalThis._loadersgl_?.version) {
13888
- globalThis._loadersgl_ = globalThis._loadersgl_ || {};
13889
- if (typeof __VERSION__ === "undefined") {
13890
- console.warn(
13891
- "loaders.gl: The __VERSION__ variable is not injected using babel plugin. Latest unstable workers would be fetched from the CDN."
13892
- );
13893
- globalThis._loadersgl_.version = NPM_TAG;
13894
- } else {
13895
- globalThis._loadersgl_.version = __VERSION__;
13717
+ function ringToGeoJson(positions, startIndex, endIndex) {
13718
+ startIndex = startIndex || 0;
13719
+ endIndex = endIndex || positions.value.length / positions.size;
13720
+ const ringCoordinates = [];
13721
+ for (let j = startIndex; j < endIndex; j++) {
13722
+ const coord = Array();
13723
+ for (let k = j * positions.size; k < (j + 1) * positions.size; k++) {
13724
+ coord.push(Number(positions.value[k]));
13896
13725
  }
13726
+ ringCoordinates.push(coord);
13897
13727
  }
13898
- return globalThis._loadersgl_.version;
13728
+ return ringCoordinates;
13899
13729
  }
13900
- var VERSION3 = getVersion();
13901
13730
 
13902
- // ../worker-utils/src/lib/env-utils/assert.ts
13903
- function assert(condition, message) {
13904
- if (!condition) {
13905
- throw new Error(message || "loaders.gl assertion failed.");
13731
+ // ../gis/src/lib/utils/concat-typed-arrays.ts
13732
+ function concatTypedArrays(arrays) {
13733
+ let byteLength = 0;
13734
+ for (let i = 0; i < arrays.length; ++i) {
13735
+ byteLength += arrays[i].byteLength;
13736
+ }
13737
+ const buffer = new Uint8Array(byteLength);
13738
+ let byteOffset = 0;
13739
+ for (let i = 0; i < arrays.length; ++i) {
13740
+ const data = new Uint8Array(arrays[i].buffer);
13741
+ byteLength = data.length;
13742
+ for (let j = 0; j < byteLength; ++j) {
13743
+ buffer[byteOffset++] = data[j];
13744
+ }
13906
13745
  }
13746
+ return buffer;
13907
13747
  }
13908
13748
 
13909
- // ../worker-utils/src/lib/env-utils/globals.ts
13910
- var globals = {
13911
- self: typeof self !== "undefined" && self,
13912
- window: typeof window !== "undefined" && window,
13913
- global: typeof global !== "undefined" && global,
13914
- document: typeof document !== "undefined" && document
13915
- };
13916
- var self_ = globals.self || globals.window || globals.global || {};
13917
- var window_ = globals.window || globals.self || globals.global || {};
13918
- var global_ = globals.global || globals.self || globals.window || {};
13919
- var document_ = globals.document || {};
13920
- var isBrowser = (
13921
- // @ts-ignore process.browser
13922
- typeof process !== "object" || String(process) !== "[object process]" || process.browser
13923
- );
13924
- var isMobile = typeof window !== "undefined" && typeof window.orientation !== "undefined";
13925
- var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version);
13926
- var nodeVersion = matches && parseFloat(matches[1]) || 0;
13927
-
13928
- // ../worker-utils/src/lib/worker-farm/worker-job.ts
13929
- var WorkerJob = class {
13930
- name;
13931
- workerThread;
13932
- isRunning = true;
13933
- /** Promise that resolves when Job is done */
13934
- result;
13935
- _resolve = () => {
13749
+ // ../gis/src/lib/binary-geometry-api/concat-binary-geometry.ts
13750
+ function concatenateBinaryPointGeometries(binaryPointGeometries, dimension) {
13751
+ const positions = binaryPointGeometries.map((geometry) => geometry.positions.value);
13752
+ const concatenatedPositions = new Float64Array(concatTypedArrays(positions).buffer);
13753
+ return {
13754
+ type: "Point",
13755
+ positions: { value: concatenatedPositions, size: dimension }
13936
13756
  };
13937
- _reject = () => {
13757
+ }
13758
+ function concatenateBinaryLineGeometries(binaryLineGeometries, dimension) {
13759
+ const lines = binaryLineGeometries.map((geometry) => geometry.positions.value);
13760
+ const concatenatedPositions = new Float64Array(concatTypedArrays(lines).buffer);
13761
+ const pathIndices = lines.map((line) => line.length / dimension).map(cumulativeSum(0));
13762
+ pathIndices.unshift(0);
13763
+ return {
13764
+ type: "LineString",
13765
+ positions: { value: concatenatedPositions, size: dimension },
13766
+ pathIndices: { value: new Uint32Array(pathIndices), size: 1 }
13938
13767
  };
13939
- constructor(jobName, workerThread) {
13940
- this.name = jobName;
13941
- this.workerThread = workerThread;
13942
- this.result = new Promise((resolve, reject) => {
13943
- this._resolve = resolve;
13944
- this._reject = reject;
13945
- });
13768
+ }
13769
+ function concatenateBinaryPolygonGeometries(binaryPolygonGeometries, dimension) {
13770
+ const polygons = [];
13771
+ const primitivePolygons = [];
13772
+ for (const binaryPolygon of binaryPolygonGeometries) {
13773
+ const { positions, primitivePolygonIndices: primitivePolygonIndices2 } = binaryPolygon;
13774
+ polygons.push(positions.value);
13775
+ primitivePolygons.push(primitivePolygonIndices2.value);
13946
13776
  }
13947
- /**
13948
- * Send a message to the job's worker thread
13949
- * @param data any data structure, ideally consisting mostly of transferrable objects
13950
- */
13951
- postMessage(type, payload) {
13952
- this.workerThread.postMessage({
13953
- source: "loaders.gl",
13954
- // Lets worker ignore unrelated messages
13955
- type,
13956
- payload
13957
- });
13777
+ const concatenatedPositions = new Float64Array(concatTypedArrays(polygons).buffer);
13778
+ const polygonIndices = polygons.map((p) => p.length / dimension).map(cumulativeSum(0));
13779
+ polygonIndices.unshift(0);
13780
+ const primitivePolygonIndices = [0];
13781
+ for (const primitivePolygon of primitivePolygons) {
13782
+ primitivePolygonIndices.push(
13783
+ ...primitivePolygon.filter((x) => x > 0).map((x) => x + primitivePolygonIndices[primitivePolygonIndices.length - 1])
13784
+ );
13958
13785
  }
13959
- /**
13960
- * Call to resolve the `result` Promise with the supplied value
13961
- */
13962
- done(value) {
13963
- assert(this.isRunning);
13964
- this.isRunning = false;
13965
- this._resolve(value);
13786
+ return {
13787
+ type: "Polygon",
13788
+ positions: { value: concatenatedPositions, size: dimension },
13789
+ polygonIndices: { value: new Uint32Array(polygonIndices), size: 1 },
13790
+ primitivePolygonIndices: { value: new Uint32Array(primitivePolygonIndices), size: 1 }
13791
+ };
13792
+ }
13793
+ var cumulativeSum = (sum) => (value) => sum += value;
13794
+
13795
+ // ../gis/src/lib/geometry-converters/wkb/helpers/wkb-types.ts
13796
+ var EWKB_FLAG_Z = 2147483648;
13797
+ var EWKB_FLAG_M = 1073741824;
13798
+ var EWKB_FLAG_SRID = 536870912;
13799
+ var WKT_MAGIC_STRINGS = [
13800
+ "POINT(",
13801
+ "LINESTRING(",
13802
+ "POLYGON(",
13803
+ "MULTIPOINT(",
13804
+ "MULTILINESTRING(",
13805
+ "MULTIPOLYGON(",
13806
+ "GEOMETRYCOLLECTION("
13807
+ ];
13808
+ var textEncoder = new TextEncoder();
13809
+ var WKT_MAGIC_BYTES = WKT_MAGIC_STRINGS.map((string) => textEncoder.encode(string));
13810
+
13811
+ // ../gis/src/lib/geometry-converters/wkb/helpers/parse-wkb-header.ts
13812
+ function isWKT(input) {
13813
+ return getWKTGeometryType(input) !== null;
13814
+ }
13815
+ function getWKTGeometryType(input) {
13816
+ if (typeof input === "string") {
13817
+ const index2 = WKT_MAGIC_STRINGS.findIndex((magicString) => input.startsWith(magicString));
13818
+ return index2 >= 0 ? index2 + 1 : null;
13966
13819
  }
13967
- /**
13968
- * Call to reject the `result` Promise with the supplied error
13969
- */
13970
- error(error) {
13971
- assert(this.isRunning);
13972
- this.isRunning = false;
13973
- this._reject(error);
13820
+ const inputArray = new Uint8Array(input);
13821
+ const index = WKT_MAGIC_BYTES.findIndex(
13822
+ (magicBytes) => magicBytes.every((value, index2) => value === inputArray[index2])
13823
+ );
13824
+ return index >= 0 ? index + 1 : null;
13825
+ }
13826
+ function parseWKBHeader(dataView, target) {
13827
+ const wkbHeader = Object.assign(target || {}, {
13828
+ type: "wkb",
13829
+ variant: "wkb",
13830
+ geometryType: 1,
13831
+ dimensions: 2,
13832
+ coordinates: "xy",
13833
+ littleEndian: true,
13834
+ byteOffset: 0
13835
+ });
13836
+ if (isWKT(dataView.buffer)) {
13837
+ throw new Error("WKB: Cannot parse WKT data");
13974
13838
  }
13975
- };
13976
-
13977
- // ../worker-utils/src/lib/node/worker_threads-browser.ts
13978
- var NodeWorker = class {
13979
- terminate() {
13839
+ wkbHeader.littleEndian = dataView.getUint8(wkbHeader.byteOffset) === 1;
13840
+ wkbHeader.byteOffset++;
13841
+ const geometryCode = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
13842
+ wkbHeader.byteOffset += 4;
13843
+ wkbHeader.geometryType = geometryCode & 7;
13844
+ const isoType = (geometryCode - wkbHeader.geometryType) / 1e3;
13845
+ switch (isoType) {
13846
+ case 0:
13847
+ break;
13848
+ case 1:
13849
+ wkbHeader.variant = "iso-wkb";
13850
+ wkbHeader.dimensions = 3;
13851
+ wkbHeader.coordinates = "xyz";
13852
+ break;
13853
+ case 2:
13854
+ wkbHeader.variant = "iso-wkb";
13855
+ wkbHeader.dimensions = 3;
13856
+ wkbHeader.coordinates = "xym";
13857
+ break;
13858
+ case 3:
13859
+ wkbHeader.variant = "iso-wkb";
13860
+ wkbHeader.dimensions = 4;
13861
+ wkbHeader.coordinates = "xyzm";
13862
+ break;
13863
+ default:
13864
+ throw new Error(`WKB: Unsupported iso-wkb type: ${isoType}`);
13980
13865
  }
13981
- };
13982
-
13983
- // ../worker-utils/src/lib/worker-utils/get-loadable-worker-url.ts
13984
- var workerURLCache = /* @__PURE__ */ new Map();
13985
- function getLoadableWorkerURL(props) {
13986
- assert(props.source && !props.url || !props.source && props.url);
13987
- let workerURL = workerURLCache.get(props.source || props.url);
13988
- if (!workerURL) {
13989
- if (props.url) {
13990
- workerURL = getLoadableWorkerURLFromURL(props.url);
13991
- workerURLCache.set(props.url, workerURL);
13992
- }
13993
- if (props.source) {
13994
- workerURL = getLoadableWorkerURLFromSource(props.source);
13995
- workerURLCache.set(props.source, workerURL);
13996
- }
13866
+ const ewkbZ = geometryCode & EWKB_FLAG_Z;
13867
+ const ewkbM = geometryCode & EWKB_FLAG_M;
13868
+ const ewkbSRID = geometryCode & EWKB_FLAG_SRID;
13869
+ if (ewkbZ && ewkbM) {
13870
+ wkbHeader.variant = "ewkb";
13871
+ wkbHeader.dimensions = 4;
13872
+ wkbHeader.coordinates = "xyzm";
13873
+ } else if (ewkbZ) {
13874
+ wkbHeader.variant = "ewkb";
13875
+ wkbHeader.dimensions = 3;
13876
+ wkbHeader.coordinates = "xyz";
13877
+ } else if (ewkbM) {
13878
+ wkbHeader.variant = "ewkb";
13879
+ wkbHeader.dimensions = 3;
13880
+ wkbHeader.coordinates = "xym";
13997
13881
  }
13998
- assert(workerURL);
13999
- return workerURL;
14000
- }
14001
- function getLoadableWorkerURLFromURL(url) {
14002
- if (!url.startsWith("http")) {
14003
- return url;
13882
+ if (ewkbSRID) {
13883
+ wkbHeader.variant = "ewkb";
13884
+ wkbHeader.srid = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
13885
+ wkbHeader.byteOffset += 4;
14004
13886
  }
14005
- const workerSource = buildScriptSource(url);
14006
- return getLoadableWorkerURLFromSource(workerSource);
14007
- }
14008
- function getLoadableWorkerURLFromSource(workerSource) {
14009
- const blob = new Blob([workerSource], { type: "application/javascript" });
14010
- return URL.createObjectURL(blob);
14011
- }
14012
- function buildScriptSource(workerUrl) {
14013
- return `try {
14014
- importScripts('${workerUrl}');
14015
- } catch (error) {
14016
- console.error(error);
14017
- throw error;
14018
- }`;
13887
+ return wkbHeader;
14019
13888
  }
14020
13889
 
14021
- // ../worker-utils/src/lib/worker-utils/get-transfer-list.ts
14022
- function getTransferList(object, recursive = true, transfers) {
14023
- const transfersSet = transfers || /* @__PURE__ */ new Set();
14024
- if (!object) {
14025
- } else if (isTransferable(object)) {
14026
- transfersSet.add(object);
14027
- } else if (isTransferable(object.buffer)) {
14028
- transfersSet.add(object.buffer);
14029
- } else if (ArrayBuffer.isView(object)) {
14030
- } else if (recursive && typeof object === "object") {
14031
- for (const key in object) {
14032
- getTransferList(object[key], recursive, transfersSet);
14033
- }
13890
+ // ../gis/src/lib/geometry-converters/wkb/convert-wkb-to-binary-geometry.ts
13891
+ function convertWKBToBinaryGeometry(arrayBuffer) {
13892
+ const dataView = new DataView(arrayBuffer);
13893
+ const wkbHeader = parseWKBHeader(dataView);
13894
+ const { geometryType, dimensions, littleEndian } = wkbHeader;
13895
+ const offset = wkbHeader.byteOffset;
13896
+ switch (geometryType) {
13897
+ case 1 /* Point */:
13898
+ const point = parsePoint(dataView, offset, dimensions, littleEndian);
13899
+ return point.geometry;
13900
+ case 2 /* LineString */:
13901
+ const line = parseLineString(dataView, offset, dimensions, littleEndian);
13902
+ return line.geometry;
13903
+ case 3 /* Polygon */:
13904
+ const polygon = parsePolygon(dataView, offset, dimensions, littleEndian);
13905
+ return polygon.geometry;
13906
+ case 4 /* MultiPoint */:
13907
+ const multiPoint = parseMultiPoint(dataView, offset, dimensions, littleEndian);
13908
+ multiPoint.type = "Point";
13909
+ return multiPoint;
13910
+ case 5 /* MultiLineString */:
13911
+ const multiLine = parseMultiLineString(dataView, offset, dimensions, littleEndian);
13912
+ multiLine.type = "LineString";
13913
+ return multiLine;
13914
+ case 6 /* MultiPolygon */:
13915
+ const multiPolygon = parseMultiPolygon(dataView, offset, dimensions, littleEndian);
13916
+ multiPolygon.type = "Polygon";
13917
+ return multiPolygon;
13918
+ default:
13919
+ throw new Error(`WKB: Unsupported geometry type: ${geometryType}`);
14034
13920
  }
14035
- return transfers === void 0 ? Array.from(transfersSet) : [];
14036
13921
  }
14037
- function isTransferable(object) {
14038
- if (!object) {
14039
- return false;
13922
+ function parsePoint(dataView, offset, dimension, littleEndian) {
13923
+ const positions = new Float64Array(dimension);
13924
+ for (let i = 0; i < dimension; i++) {
13925
+ positions[i] = dataView.getFloat64(offset, littleEndian);
13926
+ offset += 8;
14040
13927
  }
14041
- if (object instanceof ArrayBuffer) {
14042
- return true;
13928
+ return {
13929
+ geometry: { type: "Point", positions: { value: positions, size: dimension } },
13930
+ offset
13931
+ };
13932
+ }
13933
+ function parseLineString(dataView, offset, dimension, littleEndian) {
13934
+ const nPoints = dataView.getUint32(offset, littleEndian);
13935
+ offset += 4;
13936
+ const positions = new Float64Array(nPoints * dimension);
13937
+ for (let i = 0; i < nPoints * dimension; i++) {
13938
+ positions[i] = dataView.getFloat64(offset, littleEndian);
13939
+ offset += 8;
14043
13940
  }
14044
- if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
14045
- return true;
13941
+ const pathIndices = [0];
13942
+ if (nPoints > 0) {
13943
+ pathIndices.push(nPoints);
14046
13944
  }
14047
- if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
14048
- return true;
13945
+ return {
13946
+ geometry: {
13947
+ type: "LineString",
13948
+ positions: { value: positions, size: dimension },
13949
+ pathIndices: { value: new Uint32Array(pathIndices), size: 1 }
13950
+ },
13951
+ offset
13952
+ };
13953
+ }
13954
+ var cumulativeSum2 = (sum) => (value) => sum += value;
13955
+ function parsePolygon(dataView, offset, dimension, littleEndian) {
13956
+ const nRings = dataView.getUint32(offset, littleEndian);
13957
+ offset += 4;
13958
+ const rings = [];
13959
+ for (let i = 0; i < nRings; i++) {
13960
+ const parsed = parseLineString(dataView, offset, dimension, littleEndian);
13961
+ const { positions } = parsed.geometry;
13962
+ offset = parsed.offset;
13963
+ rings.push(positions.value);
14049
13964
  }
14050
- if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
14051
- return true;
13965
+ const concatenatedPositions = new Float64Array(concatTypedArrays(rings).buffer);
13966
+ const polygonIndices = [0];
13967
+ if (concatenatedPositions.length > 0) {
13968
+ polygonIndices.push(concatenatedPositions.length / dimension);
14052
13969
  }
14053
- return false;
13970
+ const primitivePolygonIndices = rings.map((l) => l.length / dimension).map(cumulativeSum2(0));
13971
+ primitivePolygonIndices.unshift(0);
13972
+ return {
13973
+ geometry: {
13974
+ type: "Polygon",
13975
+ positions: { value: concatenatedPositions, size: dimension },
13976
+ polygonIndices: {
13977
+ value: new Uint32Array(polygonIndices),
13978
+ size: 1
13979
+ },
13980
+ primitivePolygonIndices: { value: new Uint32Array(primitivePolygonIndices), size: 1 }
13981
+ },
13982
+ offset
13983
+ };
14054
13984
  }
14055
- function getTransferListForWriter(object) {
14056
- if (object === null) {
14057
- return {};
13985
+ function parseMultiPoint(dataView, offset, dimension, littleEndian) {
13986
+ const nPoints = dataView.getUint32(offset, littleEndian);
13987
+ offset += 4;
13988
+ const binaryPointGeometries = [];
13989
+ for (let i = 0; i < nPoints; i++) {
13990
+ const littleEndianPoint = dataView.getUint8(offset) === 1;
13991
+ offset++;
13992
+ if (dataView.getUint32(offset, littleEndianPoint) % 1e3 !== 1) {
13993
+ throw new Error("WKB: Inner geometries of MultiPoint not of type Point");
13994
+ }
13995
+ offset += 4;
13996
+ const parsed = parsePoint(dataView, offset, dimension, littleEndianPoint);
13997
+ offset = parsed.offset;
13998
+ binaryPointGeometries.push(parsed.geometry);
14058
13999
  }
14059
- const clone = Object.assign({}, object);
14060
- Object.keys(clone).forEach((key) => {
14061
- if (typeof object[key] === "object" && !ArrayBuffer.isView(object[key]) && !(object[key] instanceof Array)) {
14062
- clone[key] = getTransferListForWriter(object[key]);
14063
- } else if (typeof clone[key] === "function" || clone[key] instanceof RegExp) {
14064
- clone[key] = {};
14065
- } else {
14066
- clone[key] = object[key];
14000
+ return concatenateBinaryPointGeometries(binaryPointGeometries, dimension);
14001
+ }
14002
+ function parseMultiLineString(dataView, offset, dimension, littleEndian) {
14003
+ const nLines = dataView.getUint32(offset, littleEndian);
14004
+ offset += 4;
14005
+ const binaryLineGeometries = [];
14006
+ for (let i = 0; i < nLines; i++) {
14007
+ const littleEndianLine = dataView.getUint8(offset) === 1;
14008
+ offset++;
14009
+ if (dataView.getUint32(offset, littleEndianLine) % 1e3 !== 2) {
14010
+ throw new Error("WKB: Inner geometries of MultiLineString not of type LineString");
14067
14011
  }
14068
- });
14069
- return clone;
14012
+ offset += 4;
14013
+ const parsed = parseLineString(dataView, offset, dimension, littleEndianLine);
14014
+ offset = parsed.offset;
14015
+ binaryLineGeometries.push(parsed.geometry);
14016
+ }
14017
+ return concatenateBinaryLineGeometries(binaryLineGeometries, dimension);
14018
+ }
14019
+ function parseMultiPolygon(dataView, offset, dimension, littleEndian) {
14020
+ const nPolygons = dataView.getUint32(offset, littleEndian);
14021
+ offset += 4;
14022
+ const binaryPolygonGeometries = [];
14023
+ for (let i = 0; i < nPolygons; i++) {
14024
+ const littleEndianPolygon = dataView.getUint8(offset) === 1;
14025
+ offset++;
14026
+ if (dataView.getUint32(offset, littleEndianPolygon) % 1e3 !== 3) {
14027
+ throw new Error("WKB: Inner geometries of MultiPolygon not of type Polygon");
14028
+ }
14029
+ offset += 4;
14030
+ const parsed = parsePolygon(dataView, offset, dimension, littleEndianPolygon);
14031
+ offset = parsed.offset;
14032
+ binaryPolygonGeometries.push(parsed.geometry);
14033
+ }
14034
+ return concatenateBinaryPolygonGeometries(binaryPolygonGeometries, dimension);
14070
14035
  }
14071
14036
 
14072
- // ../worker-utils/src/lib/worker-farm/worker-thread.ts
14073
- var NOOP = () => {
14074
- };
14075
- var WorkerThread = class {
14076
- name;
14077
- source;
14078
- url;
14079
- terminated = false;
14080
- worker;
14081
- onMessage;
14082
- onError;
14083
- _loadableURL = "";
14084
- /** Checks if workers are supported on this platform */
14085
- static isSupported() {
14086
- return typeof Worker !== "undefined" && isBrowser || typeof NodeWorker !== "undefined" && !isBrowser;
14037
+ // ../gis/src/lib/geometry-converters/wkb/convert-wkb-to-geometry.ts
14038
+ function convertWKBToGeometry(arrayBuffer) {
14039
+ const binaryGeometry = convertWKBToBinaryGeometry(arrayBuffer);
14040
+ return convertBinaryGeometryToGeometry(binaryGeometry);
14041
+ }
14042
+
14043
+ // ../gis/src/lib/geometry-converters/wkb/convert-wkt-to-geometry.ts
14044
+ var numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/;
14045
+ var tuples = new RegExp("^" + numberRegexp.source + "(\\s" + numberRegexp.source + "){1,}");
14046
+ function convertWKTToGeometry(input, options) {
14047
+ const parts = input.split(";");
14048
+ let _ = parts.pop();
14049
+ const srid = (parts.shift() || "").split("=").pop();
14050
+ const state = { parts, _, i: 0 };
14051
+ const geometry = parseGeometry(state);
14052
+ return options?.wkt?.crs ? addCRS(geometry, srid) : geometry;
14053
+ }
14054
+ function parseGeometry(state) {
14055
+ return parsePoint2(state) || parseLineString2(state) || parsePolygon2(state) || parseMultiPoint2(state) || parseMultiLineString2(state) || parseMultiPolygon2(state) || parseGeometryCollection(state);
14056
+ }
14057
+ function addCRS(obj, srid) {
14058
+ if (obj && srid?.match(/\d+/)) {
14059
+ const crs = {
14060
+ type: "name",
14061
+ properties: {
14062
+ name: "urn:ogc:def:crs:EPSG::" + srid
14063
+ }
14064
+ };
14065
+ obj.crs = crs;
14066
+ }
14067
+ return obj;
14068
+ }
14069
+ function parsePoint2(state) {
14070
+ if (!$(/^(POINT(\sz)?)/i, state)) {
14071
+ return null;
14072
+ }
14073
+ white(state);
14074
+ if (!$(/^(\()/, state)) {
14075
+ return null;
14076
+ }
14077
+ const c = coords(state);
14078
+ if (!c) {
14079
+ return null;
14087
14080
  }
14088
- constructor(props) {
14089
- const { name, source, url } = props;
14090
- assert(source || url);
14091
- this.name = name;
14092
- this.source = source;
14093
- this.url = url;
14094
- this.onMessage = NOOP;
14095
- this.onError = (error) => console.log(error);
14096
- this.worker = isBrowser ? this._createBrowserWorker() : this._createNodeWorker();
14081
+ white(state);
14082
+ if (!$(/^(\))/, state)) {
14083
+ return null;
14097
14084
  }
14098
- /**
14099
- * Terminate this worker thread
14100
- * @note Can free up significant memory
14101
- */
14102
- destroy() {
14103
- this.onMessage = NOOP;
14104
- this.onError = NOOP;
14105
- this.worker.terminate();
14106
- this.terminated = true;
14085
+ return {
14086
+ type: "Point",
14087
+ coordinates: c[0]
14088
+ };
14089
+ }
14090
+ function parseMultiPoint2(state) {
14091
+ if (!$(/^(MULTIPOINT)/i, state)) {
14092
+ return null;
14107
14093
  }
14108
- get isRunning() {
14109
- return Boolean(this.onMessage);
14094
+ white(state);
14095
+ const newCoordsFormat = state._?.substring(state._?.indexOf("(") + 1, state._.length - 1).replace(/\(/g, "").replace(/\)/g, "");
14096
+ state._ = "MULTIPOINT (" + newCoordsFormat + ")";
14097
+ const c = multicoords(state);
14098
+ if (!c) {
14099
+ return null;
14110
14100
  }
14111
- /**
14112
- * Send a message to this worker thread
14113
- * @param data any data structure, ideally consisting mostly of transferrable objects
14114
- * @param transferList If not supplied, calculated automatically by traversing data
14115
- */
14116
- postMessage(data, transferList) {
14117
- transferList = transferList || getTransferList(data);
14118
- this.worker.postMessage(data, transferList);
14101
+ white(state);
14102
+ return {
14103
+ type: "MultiPoint",
14104
+ coordinates: c
14105
+ };
14106
+ }
14107
+ function parseLineString2(state) {
14108
+ if (!$(/^(LINESTRING(\sz)?)/i, state)) {
14109
+ return null;
14119
14110
  }
14120
- // PRIVATE
14121
- /**
14122
- * Generate a standard Error from an ErrorEvent
14123
- * @param event
14124
- */
14125
- _getErrorFromErrorEvent(event) {
14126
- let message = "Failed to load ";
14127
- message += `worker ${this.name} from ${this.url}. `;
14128
- if (event.message) {
14129
- message += `${event.message} in `;
14130
- }
14131
- if (event.lineno) {
14132
- message += `:${event.lineno}:${event.colno}`;
14133
- }
14134
- return new Error(message);
14111
+ white(state);
14112
+ if (!$(/^(\()/, state)) {
14113
+ return null;
14135
14114
  }
14136
- /**
14137
- * Creates a worker thread on the browser
14138
- */
14139
- _createBrowserWorker() {
14140
- this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url });
14141
- const worker = new Worker(this._loadableURL, { name: this.name });
14142
- worker.onmessage = (event) => {
14143
- if (!event.data) {
14144
- this.onError(new Error("No data received"));
14145
- } else {
14146
- this.onMessage(event.data);
14147
- }
14148
- };
14149
- worker.onerror = (error) => {
14150
- this.onError(this._getErrorFromErrorEvent(error));
14151
- this.terminated = true;
14152
- };
14153
- worker.onmessageerror = (event) => console.error(event);
14154
- return worker;
14115
+ const c = coords(state);
14116
+ if (!c) {
14117
+ return null;
14155
14118
  }
14156
- /**
14157
- * Creates a worker thread in node.js
14158
- * @todo https://nodejs.org/api/async_hooks.html#async-resource-worker-pool
14159
- */
14160
- _createNodeWorker() {
14161
- let worker;
14162
- if (this.url) {
14163
- const absolute = this.url.includes(":/") || this.url.startsWith("/");
14164
- const url = absolute ? this.url : `./${this.url}`;
14165
- worker = new NodeWorker(url, { eval: false });
14166
- } else if (this.source) {
14167
- worker = new NodeWorker(this.source, { eval: true });
14168
- } else {
14169
- throw new Error("no worker");
14170
- }
14171
- worker.on("message", (data) => {
14172
- this.onMessage(data);
14173
- });
14174
- worker.on("error", (error) => {
14175
- this.onError(error);
14176
- });
14177
- worker.on("exit", (code) => {
14178
- });
14179
- return worker;
14119
+ if (!$(/^(\))/, state)) {
14120
+ return null;
14180
14121
  }
14181
- };
14182
-
14183
- // ../worker-utils/src/lib/worker-farm/worker-pool.ts
14184
- var WorkerPool = class {
14185
- name = "unnamed";
14186
- source;
14187
- // | Function;
14188
- url;
14189
- maxConcurrency = 1;
14190
- maxMobileConcurrency = 1;
14191
- onDebug = () => {
14122
+ return {
14123
+ type: "LineString",
14124
+ coordinates: c
14192
14125
  };
14193
- reuseWorkers = true;
14194
- props = {};
14195
- jobQueue = [];
14196
- idleQueue = [];
14197
- count = 0;
14198
- isDestroyed = false;
14199
- /** Checks if workers are supported on this platform */
14200
- static isSupported() {
14201
- return WorkerThread.isSupported();
14126
+ }
14127
+ function parseMultiLineString2(state) {
14128
+ if (!$(/^(MULTILINESTRING)/i, state))
14129
+ return null;
14130
+ white(state);
14131
+ const c = multicoords(state);
14132
+ if (!c) {
14133
+ return null;
14202
14134
  }
14203
- /**
14204
- * @param processor - worker function
14205
- * @param maxConcurrency - max count of workers
14206
- */
14207
- constructor(props) {
14208
- this.source = props.source;
14209
- this.url = props.url;
14210
- this.setProps(props);
14135
+ white(state);
14136
+ return {
14137
+ // @ts-ignore
14138
+ type: "MultiLineString",
14139
+ // @ts-expect-error
14140
+ coordinates: c
14141
+ };
14142
+ }
14143
+ function parsePolygon2(state) {
14144
+ if (!$(/^(POLYGON(\sz)?)/i, state)) {
14145
+ return null;
14211
14146
  }
14212
- /**
14213
- * Terminates all workers in the pool
14214
- * @note Can free up significant memory
14215
- */
14216
- destroy() {
14217
- this.idleQueue.forEach((worker) => worker.destroy());
14218
- this.isDestroyed = true;
14147
+ white(state);
14148
+ const c = multicoords(state);
14149
+ if (!c) {
14150
+ return null;
14219
14151
  }
14220
- setProps(props) {
14221
- this.props = { ...this.props, ...props };
14222
- if (props.name !== void 0) {
14223
- this.name = props.name;
14224
- }
14225
- if (props.maxConcurrency !== void 0) {
14226
- this.maxConcurrency = props.maxConcurrency;
14227
- }
14228
- if (props.maxMobileConcurrency !== void 0) {
14229
- this.maxMobileConcurrency = props.maxMobileConcurrency;
14230
- }
14231
- if (props.reuseWorkers !== void 0) {
14232
- this.reuseWorkers = props.reuseWorkers;
14233
- }
14234
- if (props.onDebug !== void 0) {
14235
- this.onDebug = props.onDebug;
14236
- }
14152
+ return {
14153
+ // @ts-ignore
14154
+ type: "Polygon",
14155
+ // @ts-expect-error
14156
+ coordinates: c
14157
+ };
14158
+ }
14159
+ function parseMultiPolygon2(state) {
14160
+ if (!$(/^(MULTIPOLYGON)/i, state)) {
14161
+ return null;
14237
14162
  }
14238
- async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) {
14239
- const startPromise = new Promise((onStart) => {
14240
- this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart });
14241
- return this;
14242
- });
14243
- this._startQueuedJob();
14244
- return await startPromise;
14163
+ white(state);
14164
+ const c = multicoords(state);
14165
+ if (!c) {
14166
+ return null;
14245
14167
  }
14246
- // PRIVATE
14247
- /**
14248
- * Starts first queued job if worker is available or can be created
14249
- * Called when job is started and whenever a worker returns to the idleQueue
14250
- */
14251
- async _startQueuedJob() {
14252
- if (!this.jobQueue.length) {
14253
- return;
14254
- }
14255
- const workerThread = this._getAvailableWorker();
14256
- if (!workerThread) {
14257
- return;
14258
- }
14259
- const queuedJob = this.jobQueue.shift();
14260
- if (queuedJob) {
14261
- this.onDebug({
14262
- message: "Starting job",
14263
- name: queuedJob.name,
14264
- workerThread,
14265
- backlog: this.jobQueue.length
14266
- });
14267
- const job = new WorkerJob(queuedJob.name, workerThread);
14268
- workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload);
14269
- workerThread.onError = (error) => queuedJob.onError(job, error);
14270
- queuedJob.onStart(job);
14271
- try {
14272
- await job.result;
14273
- } catch (error) {
14274
- console.error(`Worker exception: ${error}`);
14275
- } finally {
14276
- this.returnWorkerToQueue(workerThread);
14277
- }
14278
- }
14168
+ return {
14169
+ type: "MultiPolygon",
14170
+ // @ts-expect-error
14171
+ coordinates: c
14172
+ };
14173
+ }
14174
+ function parseGeometryCollection(state) {
14175
+ const geometries = [];
14176
+ let geometry;
14177
+ if (!$(/^(GEOMETRYCOLLECTION)/i, state)) {
14178
+ return null;
14279
14179
  }
14280
- /**
14281
- * Returns a worker to the idle queue
14282
- * Destroys the worker if
14283
- * - pool is destroyed
14284
- * - if this pool doesn't reuse workers
14285
- * - if maxConcurrency has been lowered
14286
- * @param worker
14287
- */
14288
- returnWorkerToQueue(worker) {
14289
- const shouldDestroyWorker = (
14290
- // Workers on Node.js prevent the process from exiting.
14291
- // Until we figure out how to close them before exit, we always destroy them
14292
- !isBrowser || // If the pool is destroyed, there is no reason to keep the worker around
14293
- this.isDestroyed || // If the app has disabled worker reuse, any completed workers should be destroyed
14294
- !this.reuseWorkers || // If concurrency has been lowered, this worker might be surplus to requirements
14295
- this.count > this._getMaxConcurrency()
14296
- );
14297
- if (shouldDestroyWorker) {
14298
- worker.destroy();
14299
- this.count--;
14180
+ white(state);
14181
+ if (!$(/^(\()/, state)) {
14182
+ return null;
14183
+ }
14184
+ while (geometry = parseGeometry(state)) {
14185
+ geometries.push(geometry);
14186
+ white(state);
14187
+ $(/^(,)/, state);
14188
+ white(state);
14189
+ }
14190
+ if (!$(/^(\))/, state)) {
14191
+ return null;
14192
+ }
14193
+ return {
14194
+ type: "GeometryCollection",
14195
+ geometries
14196
+ };
14197
+ }
14198
+ function multicoords(state) {
14199
+ white(state);
14200
+ let depth = 0;
14201
+ const rings = [];
14202
+ const stack = [rings];
14203
+ let pointer = rings;
14204
+ let elem;
14205
+ while (elem = $(/^(\()/, state) || $(/^(\))/, state) || $(/^(,)/, state) || $(tuples, state)) {
14206
+ if (elem === "(") {
14207
+ stack.push(pointer);
14208
+ pointer = [];
14209
+ stack[stack.length - 1].push(pointer);
14210
+ depth++;
14211
+ } else if (elem === ")") {
14212
+ if (pointer.length === 0)
14213
+ return null;
14214
+ pointer = stack.pop();
14215
+ if (!pointer)
14216
+ return null;
14217
+ depth--;
14218
+ if (depth === 0)
14219
+ break;
14220
+ } else if (elem === ",") {
14221
+ pointer = [];
14222
+ stack[stack.length - 1].push(pointer);
14223
+ } else if (!elem.split(/\s/g).some(isNaN)) {
14224
+ Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat));
14300
14225
  } else {
14301
- this.idleQueue.push(worker);
14302
- }
14303
- if (!this.isDestroyed) {
14304
- this._startQueuedJob();
14226
+ return null;
14305
14227
  }
14228
+ white(state);
14306
14229
  }
14307
- /**
14308
- * Returns idle worker or creates new worker if maxConcurrency has not been reached
14309
- */
14310
- _getAvailableWorker() {
14311
- if (this.idleQueue.length > 0) {
14312
- return this.idleQueue.shift() || null;
14313
- }
14314
- if (this.count < this._getMaxConcurrency()) {
14315
- this.count++;
14316
- const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
14317
- return new WorkerThread({ name, source: this.source, url: this.url });
14318
- }
14230
+ if (depth !== 0)
14319
14231
  return null;
14232
+ return rings;
14233
+ }
14234
+ function coords(state) {
14235
+ const list = [];
14236
+ let item;
14237
+ let pt;
14238
+ while (pt = $(tuples, state) || $(/^(,)/, state)) {
14239
+ if (pt === ",") {
14240
+ list.push(item);
14241
+ item = [];
14242
+ } else if (!pt.split(/\s/g).some(isNaN)) {
14243
+ if (!item)
14244
+ item = [];
14245
+ Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat));
14246
+ }
14247
+ white(state);
14320
14248
  }
14321
- _getMaxConcurrency() {
14322
- return isMobile ? this.maxMobileConcurrency : this.maxConcurrency;
14249
+ if (item)
14250
+ list.push(item);
14251
+ else
14252
+ return null;
14253
+ return list.length ? list : null;
14254
+ }
14255
+ function $(regexp, state) {
14256
+ const match = state._?.substring(state.i).match(regexp);
14257
+ if (!match)
14258
+ return null;
14259
+ else {
14260
+ state.i += match[0].length;
14261
+ return match[0];
14323
14262
  }
14324
- };
14263
+ }
14264
+ function white(state) {
14265
+ $(/^\s*/, state);
14266
+ }
14325
14267
 
14326
- // ../worker-utils/src/lib/worker-farm/worker-farm.ts
14327
- var DEFAULT_PROPS = {
14328
- maxConcurrency: 3,
14329
- maxMobileConcurrency: 1,
14330
- reuseWorkers: true,
14331
- onDebug: () => {
14268
+ // ../gis/src/lib/geometry-converters/convert-geoarrow-to-geojson.ts
14269
+ function convertGeoArrowGeometryToGeoJSON(arrowCellValue, encoding) {
14270
+ encoding = encoding?.toLowerCase();
14271
+ if (!encoding || !arrowCellValue) {
14272
+ return null;
14332
14273
  }
14333
- };
14334
- var _WorkerFarm = class {
14335
- props;
14336
- workerPools = /* @__PURE__ */ new Map();
14337
- /** Checks if workers are supported on this platform */
14338
- static isSupported() {
14339
- return WorkerThread.isSupported();
14274
+ switch (encoding) {
14275
+ case "geoarrow.multipolygon":
14276
+ return arrowMultiPolygonToGeometry(arrowCellValue);
14277
+ case "geoarrow.polygon":
14278
+ return arrowPolygonToGeometry(arrowCellValue);
14279
+ case "geoarrow.multipoint":
14280
+ return arrowMultiPointToGeometry(arrowCellValue);
14281
+ case "geoarrow.point":
14282
+ return arrowPointToGeometry(arrowCellValue);
14283
+ case "geoarrow.multilinestring":
14284
+ return arrowMultiLineStringToGeometry(arrowCellValue);
14285
+ case "geoarrow.linestring":
14286
+ return arrowLineStringToGeometry(arrowCellValue);
14287
+ case "geoarrow.wkb":
14288
+ return arrowWKBToGeometry(arrowCellValue);
14289
+ case "geoarrow.wkt":
14290
+ return arrowWKTToGeometry(arrowCellValue);
14291
+ default: {
14292
+ throw Error(`GeoArrow encoding not supported ${encoding}`);
14293
+ }
14340
14294
  }
14341
- /** Get the singleton instance of the global worker farm */
14342
- static getWorkerFarm(props = {}) {
14343
- _WorkerFarm._workerFarm = _WorkerFarm._workerFarm || new _WorkerFarm({});
14344
- _WorkerFarm._workerFarm.setProps(props);
14345
- return _WorkerFarm._workerFarm;
14295
+ }
14296
+ function arrowWKBToGeometry(arrowCellValue) {
14297
+ const arrayBuffer = arrowCellValue.buffer.slice(
14298
+ arrowCellValue.byteOffset,
14299
+ arrowCellValue.byteOffset + arrowCellValue.byteLength
14300
+ );
14301
+ return convertWKBToGeometry(arrayBuffer);
14302
+ }
14303
+ function arrowWKTToGeometry(arrowCellValue) {
14304
+ const string = arrowCellValue;
14305
+ return convertWKTToGeometry(string);
14306
+ }
14307
+ function arrowMultiPolygonToGeometry(arrowMultiPolygon) {
14308
+ const multiPolygon = [];
14309
+ for (let m = 0; m < arrowMultiPolygon.length; m++) {
14310
+ const arrowPolygon = arrowMultiPolygon.get(m);
14311
+ const polygon = [];
14312
+ for (let i = 0; arrowPolygon && i < arrowPolygon?.length; i++) {
14313
+ const arrowRing = arrowPolygon?.get(i);
14314
+ const ring = [];
14315
+ for (let j = 0; arrowRing && j < arrowRing.length; j++) {
14316
+ const arrowCoord = arrowRing.get(j);
14317
+ const coord = Array.from(arrowCoord);
14318
+ ring.push(coord);
14319
+ }
14320
+ polygon.push(ring);
14321
+ }
14322
+ multiPolygon.push(polygon);
14346
14323
  }
14347
- /** get global instance with WorkerFarm.getWorkerFarm() */
14348
- constructor(props) {
14349
- this.props = { ...DEFAULT_PROPS };
14350
- this.setProps(props);
14351
- this.workerPools = /* @__PURE__ */ new Map();
14324
+ const geometry = {
14325
+ type: "MultiPolygon",
14326
+ coordinates: multiPolygon
14327
+ };
14328
+ return geometry;
14329
+ }
14330
+ function arrowPolygonToGeometry(arrowPolygon) {
14331
+ const polygon = [];
14332
+ for (let i = 0; arrowPolygon && i < arrowPolygon.length; i++) {
14333
+ const arrowRing = arrowPolygon.get(i);
14334
+ const ring = [];
14335
+ for (let j = 0; arrowRing && j < arrowRing.length; j++) {
14336
+ const arrowCoord = arrowRing.get(j);
14337
+ const coords2 = Array.from(arrowCoord);
14338
+ ring.push(coords2);
14339
+ }
14340
+ polygon.push(ring);
14352
14341
  }
14353
- /**
14354
- * Terminate all workers in the farm
14355
- * @note Can free up significant memory
14356
- */
14357
- destroy() {
14358
- for (const workerPool of this.workerPools.values()) {
14359
- workerPool.destroy();
14342
+ const geometry = {
14343
+ type: "Polygon",
14344
+ coordinates: polygon
14345
+ };
14346
+ return geometry;
14347
+ }
14348
+ function arrowMultiPointToGeometry(arrowMultiPoint) {
14349
+ const multiPoint = [];
14350
+ for (let i = 0; arrowMultiPoint && i < arrowMultiPoint.length; i++) {
14351
+ const arrowPoint = arrowMultiPoint.get(i);
14352
+ if (arrowPoint) {
14353
+ const coord = Array.from(arrowPoint);
14354
+ multiPoint.push(coord);
14360
14355
  }
14361
- this.workerPools = /* @__PURE__ */ new Map();
14362
14356
  }
14363
- /**
14364
- * Set props used when initializing worker pools
14365
- * @param props
14366
- */
14367
- setProps(props) {
14368
- this.props = { ...this.props, ...props };
14369
- for (const workerPool of this.workerPools.values()) {
14370
- workerPool.setProps(this._getWorkerPoolProps());
14357
+ return {
14358
+ type: "MultiPoint",
14359
+ coordinates: multiPoint
14360
+ };
14361
+ }
14362
+ function arrowPointToGeometry(arrowPoint) {
14363
+ const point = Array.from(arrowPoint);
14364
+ return {
14365
+ type: "Point",
14366
+ coordinates: point
14367
+ };
14368
+ }
14369
+ function arrowMultiLineStringToGeometry(arrowMultiLineString) {
14370
+ const multiLineString = [];
14371
+ for (let i = 0; arrowMultiLineString && i < arrowMultiLineString.length; i++) {
14372
+ const arrowLineString = arrowMultiLineString.get(i);
14373
+ const lineString = [];
14374
+ for (let j = 0; arrowLineString && j < arrowLineString.length; j++) {
14375
+ const arrowCoord = arrowLineString.get(j);
14376
+ if (arrowCoord) {
14377
+ const coords2 = Array.from(arrowCoord);
14378
+ lineString.push(coords2);
14379
+ }
14371
14380
  }
14381
+ multiLineString.push(lineString);
14372
14382
  }
14373
- /**
14374
- * Returns a worker pool for the specified worker
14375
- * @param options - only used first time for a specific worker name
14376
- * @param options.name - the name of the worker - used to identify worker pool
14377
- * @param options.url -
14378
- * @param options.source -
14379
- * @example
14380
- * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
14381
- */
14382
- getWorkerPool(options) {
14383
- const { name, source, url } = options;
14384
- let workerPool = this.workerPools.get(name);
14385
- if (!workerPool) {
14386
- workerPool = new WorkerPool({
14387
- name,
14388
- source,
14389
- url
14390
- });
14391
- workerPool.setProps(this._getWorkerPoolProps());
14392
- this.workerPools.set(name, workerPool);
14383
+ return {
14384
+ type: "MultiLineString",
14385
+ coordinates: multiLineString
14386
+ };
14387
+ }
14388
+ function arrowLineStringToGeometry(arrowLineString) {
14389
+ const lineString = [];
14390
+ for (let i = 0; arrowLineString && i < arrowLineString.length; i++) {
14391
+ const arrowCoord = arrowLineString.get(i);
14392
+ if (arrowCoord) {
14393
+ const coords2 = Array.from(arrowCoord);
14394
+ lineString.push(coords2);
14393
14395
  }
14394
- return workerPool;
14395
- }
14396
- _getWorkerPoolProps() {
14397
- return {
14398
- maxConcurrency: this.props.maxConcurrency,
14399
- maxMobileConcurrency: this.props.maxMobileConcurrency,
14400
- reuseWorkers: this.props.reuseWorkers,
14401
- onDebug: this.props.onDebug
14402
- };
14403
14396
  }
14404
- };
14405
- var WorkerFarm = _WorkerFarm;
14406
- // singleton
14407
- __publicField(WorkerFarm, "_workerFarm");
14397
+ return {
14398
+ type: "LineString",
14399
+ coordinates: lineString
14400
+ };
14401
+ }
14408
14402
 
14409
- // ../worker-utils/src/lib/worker-api/get-worker-url.ts
14410
- function getWorkerName(worker) {
14411
- const warning = worker.version !== VERSION3 ? ` (worker-utils@${VERSION3})` : "";
14412
- return `${worker.name}@${worker.version}${warning}`;
14403
+ // ../gis/src/lib/table-converters/convert-geoarrow-table.ts
14404
+ function convertGeoArrowToTable(arrowTable, shape) {
14405
+ switch (shape) {
14406
+ case "arrow-table":
14407
+ return convertArrowToArrowTable2(arrowTable);
14408
+ case "array-row-table":
14409
+ return convertArrowToArrayRowTable2(arrowTable);
14410
+ case "object-row-table":
14411
+ return convertArrowToObjectRowTable2(arrowTable);
14412
+ case "columnar-table":
14413
+ return convertArrowToColumnarTable2(arrowTable);
14414
+ case "geojson-table":
14415
+ return convertArrowToGeoJSONTable2(arrowTable);
14416
+ default:
14417
+ throw new Error(shape);
14418
+ }
14413
14419
  }
14414
- function getWorkerURL(worker, options = {}) {
14415
- const workerOptions = options[worker.id] || {};
14416
- const workerFile = isBrowser ? `${worker.id}-worker.js` : `${worker.id}-worker-node.js`;
14417
- let url = workerOptions.workerUrl;
14418
- if (!url && worker.id === "compression") {
14419
- url = options.workerUrl;
14420
+ function convertArrowToArrowTable2(arrowTable) {
14421
+ return {
14422
+ shape: "arrow-table",
14423
+ schema: convertArrowToSchema(arrowTable.schema),
14424
+ data: arrowTable
14425
+ };
14426
+ }
14427
+ function convertArrowToArrayRowTable2(arrowTable) {
14428
+ const columnarTable = convertArrowToColumnarTable2(arrowTable);
14429
+ return convertTable(columnarTable, "array-row-table");
14430
+ }
14431
+ function convertArrowToObjectRowTable2(arrowTable) {
14432
+ const columnarTable = convertArrowToColumnarTable2(arrowTable);
14433
+ return convertTable(columnarTable, "object-row-table");
14434
+ }
14435
+ function convertArrowToColumnarTable2(arrowTable) {
14436
+ const columns = {};
14437
+ for (const field of arrowTable.schema.fields) {
14438
+ const arrowColumn = arrowTable.getChild(field.name);
14439
+ const values = arrowColumn?.toArray();
14440
+ columns[field.name] = values;
14420
14441
  }
14421
- if (options._workerType === "test") {
14422
- if (isBrowser) {
14423
- url = `modules/${worker.module}/dist/${workerFile}`;
14424
- } else {
14425
- url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`;
14442
+ const schema = convertArrowToSchema(arrowTable.schema);
14443
+ return {
14444
+ shape: "columnar-table",
14445
+ schema,
14446
+ data: columns
14447
+ };
14448
+ }
14449
+ function convertArrowToGeoJSONTable2(arrowTable) {
14450
+ const schema = convertArrowToSchema(arrowTable.schema);
14451
+ const geometryColumns = getGeometryColumnsFromSchema(schema);
14452
+ const encoding = geometryColumns.geometry.encoding;
14453
+ const features = [];
14454
+ const propertyColumnNames = arrowTable.schema.fields.map((field) => field.name).filter((name) => !(name in geometryColumns));
14455
+ const propertiesTable = arrowTable.select(propertyColumnNames);
14456
+ const arrowGeometryColumn = arrowTable.getChild("geometry");
14457
+ for (let row = 0; row < arrowTable.numRows; row++) {
14458
+ const arrowGeometry = arrowGeometryColumn?.get(row);
14459
+ const feature = convertGeoArrowGeometryToGeoJSON(arrowGeometry, encoding);
14460
+ if (feature) {
14461
+ const properties = propertiesTable.get(row)?.toJSON() || {};
14462
+ features.push({ type: "Feature", geometry: feature, properties });
14426
14463
  }
14427
14464
  }
14428
- if (!url) {
14429
- let version = worker.version;
14430
- if (version === "latest") {
14431
- version = NPM_TAG;
14432
- }
14433
- const versionTag = version ? `@${version}` : "";
14434
- url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
14465
+ return {
14466
+ shape: "geojson-table",
14467
+ type: "FeatureCollection",
14468
+ schema,
14469
+ features
14470
+ };
14471
+ }
14472
+
14473
+ // src/lib/parsers/parse-geoarrow.ts
14474
+ function parseGeoArrowSync(arrayBuffer, options) {
14475
+ const table = parseArrowSync(arrayBuffer, { shape: "arrow-table" });
14476
+ switch (options?.shape) {
14477
+ case "geojson-table":
14478
+ return convertGeoArrowToTable(table.data, "geojson-table");
14479
+ default:
14480
+ return table;
14435
14481
  }
14436
- assert(url);
14437
- return url;
14482
+ }
14483
+ function parseGeoArrowInBatches(asyncIterator) {
14484
+ return parseArrowInBatches(asyncIterator);
14438
14485
  }
14439
14486
 
14440
- // ../worker-utils/src/lib/worker-api/process-on-worker.ts
14441
- async function processOnWorker(worker, data, options = {}, context = {}) {
14442
- const name = getWorkerName(worker);
14443
- const workerFarm = WorkerFarm.getWorkerFarm(options);
14444
- const { source } = options;
14445
- const workerPoolProps = { name, source };
14446
- if (!source) {
14447
- workerPoolProps.url = getWorkerURL(worker, options);
14487
+ // src/geoarrow-loader.ts
14488
+ var GeoArrowLoader = {
14489
+ ...GeoArrowWorkerLoader,
14490
+ parse: async (arraybuffer, options) => parseGeoArrowSync(arraybuffer, options?.arrow),
14491
+ parseSync: (arraybuffer, options) => parseGeoArrowSync(arraybuffer, options?.arrow),
14492
+ parseInBatches: parseGeoArrowInBatches
14493
+ };
14494
+
14495
+ // src/workers/hard-clone.ts
14496
+ function hardClone(data, force = false) {
14497
+ if ("data" in data) {
14498
+ return new Vector(data.data.map((data2) => hardClone(data2, force)));
14448
14499
  }
14449
- const workerPool = workerFarm.getWorkerPool(workerPoolProps);
14450
- const jobName = options.jobName || worker.name;
14451
- const job = await workerPool.startJob(
14452
- jobName,
14453
- // eslint-disable-next-line
14454
- onMessage.bind(null, context)
14500
+ const clonedChildren = [];
14501
+ for (const childData of data.children) {
14502
+ clonedChildren.push(hardClone(childData, force));
14503
+ }
14504
+ let clonedDictionary;
14505
+ if (data.dictionary !== void 0) {
14506
+ clonedDictionary = hardClone(data.dictionary, force);
14507
+ }
14508
+ const clonedBuffers = {
14509
+ [BufferType.OFFSET]: cloneBuffer(data.buffers[BufferType.OFFSET], force),
14510
+ [BufferType.DATA]: cloneBuffer(data.buffers[BufferType.DATA], force),
14511
+ [BufferType.VALIDITY]: cloneBuffer(data.buffers[BufferType.VALIDITY], force),
14512
+ [BufferType.TYPE]: cloneBuffer(data.buffers[BufferType.TYPE], force)
14513
+ };
14514
+ return new Data(
14515
+ data.type,
14516
+ data.offset,
14517
+ data.length,
14518
+ // @ts-expect-error _nullCount is protected. We're using it here to mimic
14519
+ // `Data.clone`
14520
+ data._nullCount,
14521
+ clonedBuffers,
14522
+ clonedChildren,
14523
+ clonedDictionary
14455
14524
  );
14456
- const transferableOptions = getTransferListForWriter(options);
14457
- job.postMessage("process", { input: data, options: transferableOptions });
14458
- const result = await job.result;
14459
- return result.result;
14460
14525
  }
14461
- async function onMessage(context, job, type, payload) {
14462
- switch (type) {
14463
- case "done":
14464
- job.done(payload);
14465
- break;
14466
- case "error":
14467
- job.error(new Error(payload.error));
14468
- break;
14469
- case "process":
14470
- const { id, input, options } = payload;
14471
- try {
14472
- if (!context.process) {
14473
- job.postMessage("error", { id, error: "Worker not set up to process on main thread" });
14474
- return;
14475
- }
14476
- const result = await context.process(input, options);
14477
- job.postMessage("done", { id, result });
14478
- } catch (error) {
14479
- const message = error instanceof Error ? error.message : "unknown error";
14480
- job.postMessage("error", { id, error: message });
14481
- }
14482
- break;
14483
- default:
14484
- console.warn(`process-on-worker: unknown message ${type}`);
14526
+ function isTypedArraySliced(arr) {
14527
+ return !(arr.byteOffset === 0 && arr.byteLength === arr.buffer.byteLength);
14528
+ }
14529
+ function cloneBuffer(arr, force) {
14530
+ if (arr === void 0) {
14531
+ return arr;
14485
14532
  }
14533
+ if (!force && !isTypedArraySliced(arr)) {
14534
+ return arr;
14535
+ }
14536
+ return arr.slice();
14486
14537
  }
14487
14538
 
14488
14539
  // src/triangulate-on-worker.ts