@loaders.gl/arrow 4.0.3 → 4.1.0-alpha.1

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 (114) hide show
  1. package/dist/arrow-loader.d.ts +6 -3
  2. package/dist/arrow-loader.d.ts.map +1 -1
  3. package/dist/arrow-loader.js +9 -1
  4. package/dist/arrow-loader.js.map +1 -1
  5. package/dist/arrow-worker.js +272 -537
  6. package/dist/dist.dev.js +2399 -269
  7. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.d.ts +33 -1
  8. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.d.ts.map +1 -1
  9. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.js +146 -17
  10. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.js.map +1 -1
  11. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.d.ts +13 -0
  12. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.d.ts.map +1 -0
  13. package/dist/geoarrow/{convert-geoarrow-to-geojson.js → convert-geoarrow-to-geojson-geometry.js} +36 -25
  14. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.js.map +1 -0
  15. package/dist/geoarrow-loader.d.ts +19 -0
  16. package/dist/geoarrow-loader.d.ts.map +1 -0
  17. package/dist/geoarrow-loader.js +23 -0
  18. package/dist/geoarrow-loader.js.map +1 -0
  19. package/dist/geoarrow-writer.d.ts +9 -0
  20. package/dist/geoarrow-writer.d.ts.map +1 -0
  21. package/dist/geoarrow-writer.js +19 -0
  22. package/dist/geoarrow-writer.js.map +1 -0
  23. package/dist/index.cjs +481 -255
  24. package/dist/index.d.ts +9 -12
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +7 -13
  27. package/dist/index.js.map +1 -1
  28. package/dist/lib/arrow-table-batch.d.ts.map +1 -1
  29. package/dist/lib/arrow-table-batch.js.map +1 -1
  30. package/dist/lib/encode-arrow.d.ts.map +1 -1
  31. package/dist/lib/encode-arrow.js.map +1 -1
  32. package/dist/lib/encode-geoarrow.d.ts +15 -0
  33. package/dist/lib/encode-geoarrow.d.ts.map +1 -0
  34. package/dist/lib/encode-geoarrow.js +22 -0
  35. package/dist/lib/encode-geoarrow.js.map +1 -0
  36. package/dist/{lib → parsers}/parse-arrow-in-batches.d.ts +1 -1
  37. package/dist/parsers/parse-arrow-in-batches.d.ts.map +1 -0
  38. package/dist/parsers/parse-arrow-in-batches.js.map +1 -0
  39. package/dist/parsers/parse-arrow-sync.d.ts +6 -0
  40. package/dist/parsers/parse-arrow-sync.d.ts.map +1 -0
  41. package/dist/parsers/parse-arrow-sync.js +28 -0
  42. package/dist/parsers/parse-arrow-sync.js.map +1 -0
  43. package/dist/parsers/parse-geoarrow-in-batches.d.ts +6 -0
  44. package/dist/parsers/parse-geoarrow-in-batches.d.ts.map +1 -0
  45. package/dist/parsers/parse-geoarrow-in-batches.js +5 -0
  46. package/dist/parsers/parse-geoarrow-in-batches.js.map +1 -0
  47. package/dist/parsers/parse-geoarrow-sync.d.ts +6 -0
  48. package/dist/parsers/parse-geoarrow-sync.d.ts.map +1 -0
  49. package/dist/parsers/parse-geoarrow-sync.js +14 -0
  50. package/dist/parsers/parse-geoarrow-sync.js.map +1 -0
  51. package/dist/tables/convert-arrow-to-columnar-table.d.ts +8 -0
  52. package/dist/tables/convert-arrow-to-columnar-table.d.ts.map +1 -0
  53. package/dist/tables/convert-arrow-to-columnar-table.js +15 -0
  54. package/dist/tables/convert-arrow-to-columnar-table.js.map +1 -0
  55. package/dist/tables/convert-arrow-to-geojson-table.d.ts +16 -0
  56. package/dist/tables/convert-arrow-to-geojson-table.d.ts.map +1 -0
  57. package/dist/tables/convert-arrow-to-geojson-table.js +39 -0
  58. package/dist/tables/convert-arrow-to-geojson-table.js.map +1 -0
  59. package/dist/tables/convert-columnar-to-row-table.d.ts +7 -0
  60. package/dist/tables/convert-columnar-to-row-table.d.ts.map +1 -0
  61. package/dist/tables/convert-columnar-to-row-table.js +19 -0
  62. package/dist/tables/convert-columnar-to-row-table.js.map +1 -0
  63. package/dist/triangulate-on-worker.d.ts +36 -0
  64. package/dist/triangulate-on-worker.d.ts.map +1 -0
  65. package/dist/triangulate-on-worker.js +14 -0
  66. package/dist/triangulate-on-worker.js.map +1 -0
  67. package/dist/triangulation-worker.js +887 -0
  68. package/dist/workers/arrow-worker.js +1 -1
  69. package/dist/workers/arrow-worker.js.map +1 -1
  70. package/dist/workers/triangulation-worker-node.d.ts +2 -0
  71. package/dist/workers/triangulation-worker-node.d.ts.map +1 -0
  72. package/dist/workers/triangulation-worker-node.js +2 -0
  73. package/dist/workers/triangulation-worker-node.js.map +1 -0
  74. package/dist/workers/triangulation-worker.d.ts +2 -0
  75. package/dist/workers/triangulation-worker.d.ts.map +1 -0
  76. package/dist/workers/triangulation-worker.js +26 -0
  77. package/dist/workers/triangulation-worker.js.map +1 -0
  78. package/package.json +20 -12
  79. package/src/arrow-loader.ts +25 -3
  80. package/src/geoarrow/convert-geoarrow-to-binary-geometry.ts +247 -23
  81. package/src/geoarrow/{convert-geoarrow-to-geojson.ts → convert-geoarrow-to-geojson-geometry.ts} +58 -44
  82. package/src/geoarrow-loader.ts +51 -0
  83. package/src/geoarrow-writer.ts +41 -0
  84. package/src/index.ts +31 -37
  85. package/src/lib/arrow-table-batch.ts +3 -0
  86. package/src/lib/encode-arrow.ts +3 -0
  87. package/src/lib/encode-geoarrow.ts +45 -0
  88. package/src/{lib → parsers}/parse-arrow-in-batches.ts +4 -2
  89. package/src/parsers/parse-arrow-sync.ts +43 -0
  90. package/src/parsers/parse-geoarrow-in-batches.ts +15 -0
  91. package/src/parsers/parse-geoarrow-sync.ts +22 -0
  92. package/src/tables/convert-arrow-to-columnar-table.ts +30 -0
  93. package/src/tables/convert-arrow-to-geojson-table.ts +65 -0
  94. package/src/tables/convert-columnar-to-row-table.ts +30 -0
  95. package/src/triangulate-on-worker.ts +47 -0
  96. package/src/workers/arrow-worker.ts +1 -1
  97. package/src/workers/triangulation-worker-node.ts +4 -0
  98. package/src/workers/triangulation-worker.ts +39 -0
  99. package/dist/geoarrow/convert-geoarrow-to-geojson.d.ts +0 -19
  100. package/dist/geoarrow/convert-geoarrow-to-geojson.d.ts.map +0 -1
  101. package/dist/geoarrow/convert-geoarrow-to-geojson.js.map +0 -1
  102. package/dist/lib/parse-arrow-in-batches.d.ts.map +0 -1
  103. package/dist/lib/parse-arrow-in-batches.js.map +0 -1
  104. package/dist/lib/parse-arrow-sync.d.ts +0 -5
  105. package/dist/lib/parse-arrow-sync.d.ts.map +0 -1
  106. package/dist/lib/parse-arrow-sync.js +0 -21
  107. package/dist/lib/parse-arrow-sync.js.map +0 -1
  108. package/dist/tables/convert-arrow-to-table.d.ts +0 -21
  109. package/dist/tables/convert-arrow-to-table.d.ts.map +0 -1
  110. package/dist/tables/convert-arrow-to-table.js +0 -37
  111. package/dist/tables/convert-arrow-to-table.js.map +0 -1
  112. package/src/lib/parse-arrow-sync.ts +0 -35
  113. package/src/tables/convert-arrow-to-table.ts +0 -68
  114. /package/dist/{lib → parsers}/parse-arrow-in-batches.js +0 -0
@@ -1,4 +1,4 @@
1
1
  import { createLoaderWorker } from '@loaders.gl/loader-utils';
2
- import { ArrowLoader } from "../index.js";
2
+ import { ArrowLoader } from "../arrow-loader.js";
3
3
  createLoaderWorker(ArrowLoader);
4
4
  //# sourceMappingURL=arrow-worker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"arrow-worker.js","names":["createLoaderWorker","ArrowLoader"],"sources":["../../src/workers/arrow-worker.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Copyright (c) vis.gl contributors\n\nimport {createLoaderWorker} from '@loaders.gl/loader-utils';\nimport {ArrowLoader} from '../index';\n\ncreateLoaderWorker(ArrowLoader);\n"],"mappings":"AAGA,SAAQA,kBAAkB,QAAO,0BAA0B;AAAC,SACpDC,WAAW;AAEnBD,kBAAkB,CAACC,WAAW,CAAC"}
1
+ {"version":3,"file":"arrow-worker.js","names":["createLoaderWorker","ArrowLoader"],"sources":["../../src/workers/arrow-worker.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Copyright (c) vis.gl contributors\n\nimport {createLoaderWorker} from '@loaders.gl/loader-utils';\nimport {ArrowLoader} from '../arrow-loader';\n\ncreateLoaderWorker(ArrowLoader);\n"],"mappings":"AAGA,SAAQA,kBAAkB,QAAO,0BAA0B;AAAC,SACpDC,WAAW;AAEnBD,kBAAkB,CAACC,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ import './triangulation-worker';
2
+ //# sourceMappingURL=triangulation-worker-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triangulation-worker-node.d.ts","sourceRoot":"","sources":["../../src/workers/triangulation-worker-node.ts"],"names":[],"mappings":"AAGA,OAAO,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import "./triangulation-worker.js";
2
+ //# sourceMappingURL=triangulation-worker-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triangulation-worker-node.js","names":[],"sources":["../../src/workers/triangulation-worker-node.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Copyright (c) vis.gl contributors\n\nimport './triangulation-worker';\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=triangulation-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triangulation-worker.d.ts","sourceRoot":"","sources":["../../src/workers/triangulation-worker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { createWorker } from '@loaders.gl/worker-utils';
2
+ import { getTriangleIndices } from "../geoarrow/convert-geoarrow-to-binary-geometry.js";
3
+ createWorker(async function (data) {
4
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
5
+ const input = data;
6
+ const operation = input === null || input === void 0 ? void 0 : input.operation;
7
+ switch (operation) {
8
+ case 'test':
9
+ return input;
10
+ case 'triangulate':
11
+ return triangulateBatch(data);
12
+ default:
13
+ throw new Error(`TriangulationWorker: Unsupported operation ${operation}. Expected 'triangulate'`);
14
+ }
15
+ });
16
+ function triangulateBatch(data) {
17
+ console.error('TriangulationWorker: tessellating batch', data);
18
+ const triangleIndices = getTriangleIndices(data.polygonIndices, data.primitivePolygonIndices, data.flatCoordinateArray, data.nDim);
19
+ return {
20
+ ...data,
21
+ ...(triangleIndices ? {
22
+ triangleIndices
23
+ } : {})
24
+ };
25
+ }
26
+ //# sourceMappingURL=triangulation-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triangulation-worker.js","names":["createWorker","getTriangleIndices","data","options","arguments","length","undefined","input","operation","triangulateBatch","Error","console","error","triangleIndices","polygonIndices","primitivePolygonIndices","flatCoordinateArray","nDim"],"sources":["../../src/workers/triangulation-worker.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Copyright (c) vis.gl contributors\n\nimport {createWorker} from '@loaders.gl/worker-utils';\nimport {getTriangleIndices} from '../geoarrow/convert-geoarrow-to-binary-geometry';\nimport type {\n TriangulationWorkerInput,\n TriangulateInput,\n TriangulateResult\n} from '../triangulate-on-worker';\n\ncreateWorker(async (data, options = {}) => {\n const input = data as TriangulationWorkerInput;\n const operation = input?.operation;\n switch (operation) {\n case 'test':\n return input;\n case 'triangulate':\n return triangulateBatch(data);\n default:\n throw new Error(\n `TriangulationWorker: Unsupported operation ${operation}. Expected 'triangulate'`\n );\n }\n});\n\nfunction triangulateBatch(data: TriangulateInput): TriangulateResult {\n // Parse any WKT/WKB geometries\n // Build binary geometries\n // Call earcut and triangulate\n console.error('TriangulationWorker: tessellating batch', data);\n const triangleIndices = getTriangleIndices(\n data.polygonIndices,\n data.primitivePolygonIndices,\n data.flatCoordinateArray,\n data.nDim\n );\n return {...data, ...(triangleIndices ? {triangleIndices} : {})};\n}\n"],"mappings":"AAGA,SAAQA,YAAY,QAAO,0BAA0B;AAAC,SAC9CC,kBAAkB;AAO1BD,YAAY,CAAC,gBAAOE,IAAI,EAAmB;EAAA,IAAjBC,OAAO,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EACpC,MAAMG,KAAK,GAAGL,IAAgC;EAC9C,MAAMM,SAAS,GAAGD,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEC,SAAS;EAClC,QAAQA,SAAS;IACf,KAAK,MAAM;MACT,OAAOD,KAAK;IACd,KAAK,aAAa;MAChB,OAAOE,gBAAgB,CAACP,IAAI,CAAC;IAC/B;MACE,MAAM,IAAIQ,KAAK,CACZ,8CAA6CF,SAAU,0BAC1D,CAAC;EACL;AACF,CAAC,CAAC;AAEF,SAASC,gBAAgBA,CAACP,IAAsB,EAAqB;EAInES,OAAO,CAACC,KAAK,CAAC,yCAAyC,EAAEV,IAAI,CAAC;EAC9D,MAAMW,eAAe,GAAGZ,kBAAkB,CACxCC,IAAI,CAACY,cAAc,EACnBZ,IAAI,CAACa,uBAAuB,EAC5Bb,IAAI,CAACc,mBAAmB,EACxBd,IAAI,CAACe,IACP,CAAC;EACD,OAAO;IAAC,GAAGf,IAAI;IAAE,IAAIW,eAAe,GAAG;MAACA;IAAe,CAAC,GAAG,CAAC,CAAC;EAAC,CAAC;AACjE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/arrow",
3
- "version": "4.0.3",
3
+ "version": "4.1.0-alpha.1",
4
4
  "description": "Simple columnar table loader for the Apache Arrow format",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,12 +12,17 @@
12
12
  "url": "https://github.com/visgl/loaders.gl"
13
13
  },
14
14
  "keywords": [
15
- "webgl",
16
15
  "loader",
17
- "3d",
18
- "mesh",
19
- "point cloud",
20
- "PLY"
16
+ "parser",
17
+ "writer",
18
+ "encoder",
19
+ "geoarrow",
20
+ "apache-arrow",
21
+ "arrow",
22
+ "binary columnar",
23
+ "cloud native",
24
+ "webgl",
25
+ "webgpu"
21
26
  ],
22
27
  "types": "dist/index.d.ts",
23
28
  "main": "dist/index.cjs",
@@ -39,17 +44,20 @@
39
44
  "fs": false
40
45
  },
41
46
  "scripts": {
42
- "pre-build": "npm run build-worker && npm run build-bundle && npm run build-bundle -- --env=dev",
47
+ "pre-build": "npm run build-worker && npm run build-bundle && npm run build-bundle -- --env=dev && npm run build-triangulation-worker",
43
48
  "build-bundle": "ocular-bundle ./src/index.ts",
44
- "build-worker": "esbuild src/workers/arrow-worker.ts --bundle --outfile=dist/arrow-worker.js --platform=browser --external:{stream} --define:__VERSION__=\\\"$npm_package_version\\\"",
49
+ "build-triangulation-worker": "esbuild src/workers/triangulation-worker.ts --bundle --outfile=dist/triangulation-worker.js --platform=browser --external:{stream} --define:__VERSION__=\\\"$npm_package_version\\\"",
45
50
  "pre-build2": "cp fixed-package.json ../../node_modules/apache-arrow/package.json && npm run build-bundle && npm run build-worker",
51
+ "build-worker": "esbuild src/workers/arrow-worker.ts --bundle --outfile=dist/arrow-worker.js --platform=browser --external:{stream} --define:__VERSION__=\\\"$npm_package_version\\\"",
46
52
  "build-worker2": "esbuild src/workers/arrow-worker.ts --bundle --outfile=dist/arrow-worker.js --platform=browser --external:{stream}"
47
53
  },
48
54
  "dependencies": {
49
- "@loaders.gl/gis": "4.0.3",
50
- "@loaders.gl/loader-utils": "4.0.3",
51
- "@loaders.gl/schema": "4.0.3",
55
+ "@loaders.gl/gis": "4.1.0-alpha.1",
56
+ "@loaders.gl/loader-utils": "4.1.0-alpha.1",
57
+ "@loaders.gl/schema": "4.1.0-alpha.1",
58
+ "@loaders.gl/wkt": "4.1.0-alpha.1",
59
+ "@math.gl/polygon": "4.0.0",
52
60
  "apache-arrow": "^13.0.0"
53
61
  },
54
- "gitHead": "03c871839b36c997249dabae1844df53a35d3760"
62
+ "gitHead": "6a4d3da93d45115ad99861474a43c3f4a0b280a7"
55
63
  }
@@ -1,8 +1,16 @@
1
1
  // loaders.gl, MIT license
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
- import type {Loader, LoaderOptions} from '@loaders.gl/loader-utils';
4
+ import type {Loader, LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';
5
+ import type {
6
+ ArrayRowTable,
7
+ ArrowTableBatch,
8
+ ColumnarTable,
9
+ ObjectRowTable
10
+ } from '@loaders.gl/schema';
5
11
  import type {ArrowTable} from './lib/arrow-table';
12
+ import {parseArrowSync} from './parsers/parse-arrow-sync';
13
+ import {parseArrowInBatches} from './parsers/parse-arrow-in-batches';
6
14
 
7
15
  // __VERSION__ is injected by babel-plugin-version-inline
8
16
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
@@ -10,12 +18,12 @@ const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
10
18
 
11
19
  export type ArrowLoaderOptions = LoaderOptions & {
12
20
  arrow?: {
13
- shape: 'arrow-table' | 'columnar-table' | 'row-table' | 'array-row-table' | 'object-row-table';
21
+ shape: 'arrow-table' | 'columnar-table' | 'array-row-table' | 'object-row-table';
14
22
  };
15
23
  };
16
24
 
17
25
  /** ArrowJS table loader */
18
- export const ArrowLoader: Loader<ArrowTable, never, ArrowLoaderOptions> = {
26
+ export const ArrowWorkerLoader: Loader<ArrowTable, never, ArrowLoaderOptions> = {
19
27
  name: 'Apache Arrow',
20
28
  id: 'arrow',
21
29
  module: 'arrow',
@@ -36,3 +44,17 @@ export const ArrowLoader: Loader<ArrowTable, never, ArrowLoaderOptions> = {
36
44
  }
37
45
  }
38
46
  };
47
+
48
+ /** ArrowJS table loader */
49
+ export const ArrowLoader: LoaderWithParser<
50
+ ArrowTable | ColumnarTable | ObjectRowTable | ArrayRowTable,
51
+ ArrowTableBatch,
52
+ ArrowLoaderOptions
53
+ > = {
54
+ ...ArrowWorkerLoader,
55
+ parse: async (arraybuffer: ArrayBuffer, options?: ArrowLoaderOptions) =>
56
+ parseArrowSync(arraybuffer, options?.arrow),
57
+ parseSync: (arraybuffer: ArrayBuffer, options?: ArrowLoaderOptions) =>
58
+ parseArrowSync(arraybuffer, options?.arrow),
59
+ parseInBatches: parseArrowInBatches
60
+ };
@@ -2,28 +2,58 @@
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
4
  import * as arrow from 'apache-arrow';
5
+ import {earcut} from '@math.gl/polygon';
5
6
  import {BinaryFeatureCollection as BinaryFeatures} from '@loaders.gl/schema';
6
7
  import {GeoArrowEncoding} from '@loaders.gl/gis';
7
8
  import {updateBoundsFromGeoArrowSamples} from './get-arrow-bounds';
9
+ import {TypedArray} from '@loaders.gl/loader-utils';
10
+
11
+ /**
12
+ * Binary geometry type
13
+ */
14
+ enum BinaryGeometryType {
15
+ points = 'points',
16
+ lines = 'lines',
17
+ polygons = 'polygons'
18
+ }
8
19
 
9
20
  /**
10
21
  * Binary data from geoarrow column and can be used by e.g. deck.gl GeojsonLayer
11
22
  */
12
23
  export type BinaryDataFromGeoArrow = {
24
+ /** Binary format geometries, an array of BinaryFeatureCollection */
13
25
  binaryGeometries: BinaryFeatures[];
26
+ /** Boundary of the binary geometries */
14
27
  bounds: [number, number, number, number];
28
+ /** Feature types of the binary geometries */
15
29
  featureTypes: {polygon: boolean; point: boolean; line: boolean};
30
+ /** (Optional) mean centers of the binary geometries for e.g. polygon filtering */
31
+ meanCenters?: number[][];
16
32
  };
17
33
 
34
+ /**
35
+ * Binary geometry content returned from getBinaryGeometriesFromChunk
36
+ */
18
37
  type BinaryGeometryContent = {
38
+ // Array of Point feature indexes by vertex
19
39
  featureIds: Uint32Array;
40
+ /** Flat coordinate array of e.g. x, y or x,y,z */
20
41
  flatCoordinateArray: Float64Array;
42
+ /** Dimention of each position */
21
43
  nDim: number;
44
+ /** Array of geometry offsets: the start index of primitive geometry */
22
45
  geomOffset: Int32Array;
46
+ /** Array of geometry indicies: the start index of each geometry */
23
47
  geometryIndicies: Uint16Array;
48
+ /** (Optional) indices of triangels returned from polygon tessellation (Polygon only) */
49
+ triangles?: Uint32Array;
50
+ /** (Optional) array of mean center of each geometry */
51
+ meanCenters?: Float64Array;
24
52
  };
25
53
 
26
- // binary geometry template, see deck.gl BinaryGeometry
54
+ /**
55
+ * binary geometry template, see deck.gl BinaryGeometry
56
+ */
27
57
  export const BINARY_GEOMETRY_TEMPLATE = {
28
58
  globalFeatureIds: {value: new Uint32Array(0), size: 1},
29
59
  positions: {value: new Float32Array(0), size: 2},
@@ -32,16 +62,27 @@ export const BINARY_GEOMETRY_TEMPLATE = {
32
62
  featureIds: {value: new Uint32Array(0), size: 1}
33
63
  };
34
64
 
65
+ export type BinaryGeometriesFromArrowOptions = {
66
+ /** option to specify which chunk to get binary geometries from, for progressive rendering */
67
+ chunkIndex?: number;
68
+ /** option to get mean centers from geometries, for polygon filtering */
69
+ calculateMeanCenters?: boolean;
70
+ /** option to compute the triangle indices by tesselating polygons */
71
+ triangulate?: boolean;
72
+ };
73
+
35
74
  /**
36
75
  * get binary geometries from geoarrow column
37
76
  *
38
77
  * @param geoColumn the geoarrow column, e.g. arrowTable.getChildAt(geoColumnIndex)
39
78
  * @param geoEncoding the geo encoding of the geoarrow column, e.g. getGeoArrowEncoding(arrowTable.schema, geoColumnName)
79
+ * @param options options for getting binary geometries {meanCenter: boolean}
40
80
  * @returns BinaryDataFromGeoArrow
41
81
  */
42
82
  export function getBinaryGeometriesFromArrow(
43
83
  geoColumn: arrow.Vector,
44
- geoEncoding: GeoArrowEncoding
84
+ geoEncoding: GeoArrowEncoding,
85
+ options?: BinaryGeometriesFromArrowOptions
45
86
  ): BinaryDataFromGeoArrow {
46
87
  const featureTypes = {
47
88
  polygon: geoEncoding === 'geoarrow.multipolygon' || geoEncoding === 'geoarrow.polygon',
@@ -49,16 +90,14 @@ export function getBinaryGeometriesFromArrow(
49
90
  line: geoEncoding === 'geoarrow.multilinestring' || geoEncoding === 'geoarrow.linestring'
50
91
  };
51
92
 
52
- const chunks = geoColumn.data;
93
+ const chunks = options?.chunkIndex ? [geoColumn.data[options?.chunkIndex]] : geoColumn.data;
53
94
  let bounds: [number, number, number, number] = [Infinity, Infinity, -Infinity, -Infinity];
54
95
  let globalFeatureIdOffset = 0;
55
96
  const binaryGeometries: BinaryFeatures[] = [];
56
97
 
57
98
  chunks.forEach((chunk) => {
58
- const {featureIds, flatCoordinateArray, nDim, geomOffset} = getBinaryGeometriesFromChunk(
59
- chunk,
60
- geoEncoding
61
- );
99
+ const {featureIds, flatCoordinateArray, nDim, geomOffset, triangles} =
100
+ getBinaryGeometriesFromChunk(chunk, geoEncoding, options);
62
101
 
63
102
  const globalFeatureIds = new Uint32Array(featureIds.length);
64
103
  for (let i = 0; i < featureIds.length; i++) {
@@ -79,7 +118,6 @@ export function getBinaryGeometriesFromArrow(
79
118
 
80
119
  // TODO: check if chunks are sequentially accessed
81
120
  globalFeatureIdOffset += chunk.length;
82
-
83
121
  // NOTE: deck.gl defines the BinaryFeatures structure must have points, lines, polygons even if they are empty
84
122
  binaryGeometries.push({
85
123
  shape: 'binary-feature-collection',
@@ -99,33 +137,128 @@ export function getBinaryGeometriesFromArrow(
99
137
  ...BINARY_GEOMETRY_TEMPLATE,
100
138
  ...(featureTypes.polygon ? binaryContent : {}),
101
139
  polygonIndices: {
102
- // TODO why deck.gl's tessellatePolygon performance is not good when using geometryIndicies
103
- // even when there is no hole in any polygon
140
+ // use geomOffset as polygonIndices same as primitivePolygonIndices since we are using earcut to get triangule indices
104
141
  value: featureTypes.polygon ? geomOffset : new Uint16Array(0),
105
142
  size: 1
106
143
  },
107
144
  primitivePolygonIndices: {
108
145
  value: featureTypes.polygon ? geomOffset : new Uint16Array(0),
109
146
  size: 1
110
- }
147
+ },
148
+ ...(triangles ? {triangles: {value: triangles, size: 1}} : {})
111
149
  }
112
150
  });
113
151
 
114
152
  bounds = updateBoundsFromGeoArrowSamples(flatCoordinateArray, nDim, bounds);
115
153
  });
116
154
 
117
- return {binaryGeometries, bounds, featureTypes};
155
+ return {
156
+ binaryGeometries,
157
+ bounds,
158
+ featureTypes,
159
+ ...(options?.calculateMeanCenters
160
+ ? {meanCenters: getMeanCentersFromBinaryGeometries(binaryGeometries)}
161
+ : {})
162
+ };
163
+ }
164
+
165
+ /**
166
+ * Get mean centers from binary geometries
167
+ * @param binaryGeometries binary geometries from geoarrow column, an array of BinaryFeatureCollection
168
+ * @returns mean centers of the binary geometries
169
+ */
170
+ export function getMeanCentersFromBinaryGeometries(binaryGeometries: BinaryFeatures[]): number[][] {
171
+ const globalMeanCenters: number[][] = [];
172
+ binaryGeometries.forEach((binaryGeometry: BinaryFeatures) => {
173
+ let binaryGeometryType: keyof typeof BinaryGeometryType | null = null;
174
+ if (binaryGeometry.points && binaryGeometry.points.positions.value.length > 0) {
175
+ binaryGeometryType = BinaryGeometryType.points;
176
+ } else if (binaryGeometry.lines && binaryGeometry.lines.positions.value.length > 0) {
177
+ binaryGeometryType = BinaryGeometryType.lines;
178
+ } else if (binaryGeometry.polygons && binaryGeometry.polygons.positions.value.length > 0) {
179
+ binaryGeometryType = BinaryGeometryType.polygons;
180
+ }
181
+
182
+ const binaryContent = binaryGeometryType ? binaryGeometry[binaryGeometryType] : null;
183
+ if (binaryContent && binaryGeometryType !== null) {
184
+ const featureIds = binaryContent.featureIds.value;
185
+ const flatCoordinateArray = binaryContent.positions.value;
186
+ const nDim = binaryContent.positions.size;
187
+ const primitivePolygonIndices =
188
+ binaryContent.type === 'Polygon' ? binaryContent.primitivePolygonIndices?.value : undefined;
189
+
190
+ const meanCenters = getMeanCentersFromGeometry(
191
+ featureIds,
192
+ flatCoordinateArray,
193
+ nDim,
194
+ binaryGeometryType,
195
+ primitivePolygonIndices
196
+ );
197
+ meanCenters.forEach((center) => {
198
+ globalMeanCenters.push(center);
199
+ });
200
+ }
201
+ });
202
+ return globalMeanCenters;
203
+ }
204
+
205
+ /**
206
+ * Get mean centers from raw coordinates and feature ids
207
+ * @param featureIds Array of feature ids indexes by vertex
208
+ * @param flatCoordinateArray Array of vertex, e.g. x, y or x, y, z, positions
209
+ * @param nDim number of dimensions per position
210
+ * @returns - mean centers of each polygon
211
+ */
212
+ function getMeanCentersFromGeometry(
213
+ featureIds: TypedArray,
214
+ flatCoordinateArray: TypedArray,
215
+ nDim: number,
216
+ geometryType: keyof typeof BinaryGeometryType,
217
+ primitivePolygonIndices?: TypedArray
218
+ ) {
219
+ const meanCenters: number[][] = [];
220
+ const vertexCount = flatCoordinateArray.length;
221
+ let vertexIndex = 0;
222
+ let coordIdx = 0;
223
+ let primitiveIdx = 0;
224
+ while (vertexIndex < vertexCount) {
225
+ const featureId = featureIds[vertexIndex / nDim];
226
+ const center = [0, 0];
227
+ let vertexCountInFeature = 0;
228
+ while (vertexIndex < vertexCount && featureIds[coordIdx] === featureId) {
229
+ if (
230
+ geometryType === BinaryGeometryType.polygons &&
231
+ primitivePolygonIndices?.[primitiveIdx] === coordIdx
232
+ ) {
233
+ // skip the first point since it is the same as the last point in each ring for polygons
234
+ vertexIndex += nDim;
235
+ primitiveIdx++;
236
+ } else {
237
+ center[0] += flatCoordinateArray[vertexIndex];
238
+ center[1] += flatCoordinateArray[vertexIndex + 1];
239
+ vertexIndex += nDim;
240
+ vertexCountInFeature++;
241
+ }
242
+ coordIdx += 1;
243
+ }
244
+ center[0] /= vertexCountInFeature;
245
+ center[1] /= vertexCountInFeature;
246
+ meanCenters.push(center);
247
+ }
248
+ return meanCenters;
118
249
  }
119
250
 
120
251
  /**
121
252
  * get binary geometries from geoarrow column
122
253
  * @param chunk one chunk/batch of geoarrow column
123
254
  * @param geoEncoding geo encoding of the geoarrow column
255
+ * @param options options for getting binary geometries
124
256
  * @returns BinaryGeometryContent
125
257
  */
126
258
  function getBinaryGeometriesFromChunk(
127
259
  chunk: arrow.Data,
128
- geoEncoding: GeoArrowEncoding
260
+ geoEncoding: GeoArrowEncoding,
261
+ options?: BinaryGeometriesFromArrowOptions
129
262
  ): BinaryGeometryContent {
130
263
  switch (geoEncoding) {
131
264
  case 'geoarrow.point':
@@ -136,19 +269,81 @@ function getBinaryGeometriesFromChunk(
136
269
  return getBinaryLinesFromChunk(chunk, geoEncoding);
137
270
  case 'geoarrow.polygon':
138
271
  case 'geoarrow.multipolygon':
139
- return getBinaryPolygonsFromChunk(chunk, geoEncoding);
272
+ return getBinaryPolygonsFromChunk(chunk, geoEncoding, options);
140
273
  default:
141
274
  throw Error('invalid geoarrow encoding');
142
275
  }
143
276
  }
144
277
 
278
+ /**
279
+ * get triangle indices. Allows deck.gl to skip performing costly triangulation on main thread.
280
+ * @param polygonIndices Indices within positions of the start of each simple Polygon
281
+ * @param primitivePolygonIndices Indices within positions of the start of each primitive Polygon/ring
282
+ * @param flatCoordinateArray Array of x, y or x, y, z positions
283
+ * @param nDim - number of dimensions per position
284
+ * @returns
285
+ */
286
+ export function getTriangleIndices(
287
+ polygonIndices: Uint16Array,
288
+ primitivePolygonIndices: Int32Array,
289
+ flatCoordinateArray: Float64Array,
290
+ nDim: number
291
+ ): Uint32Array | null {
292
+ try {
293
+ let primitiveIndex = 0;
294
+ const triangles: number[] = [];
295
+ // loop polygonIndices to get triangles
296
+ for (let i = 0; i < polygonIndices.length - 1; i++) {
297
+ const startIdx = polygonIndices[i];
298
+ const endIdx = polygonIndices[i + 1];
299
+ // get subarray of flatCoordinateArray
300
+ const slicedFlatCoords = flatCoordinateArray.subarray(startIdx * nDim, endIdx * nDim);
301
+ // get holeIndices for earcut
302
+ const holeIndices: number[] = [];
303
+ while (primitivePolygonIndices[primitiveIndex] < endIdx) {
304
+ if (primitivePolygonIndices[primitiveIndex] > startIdx) {
305
+ holeIndices.push(primitivePolygonIndices[primitiveIndex] - startIdx);
306
+ }
307
+ primitiveIndex++;
308
+ }
309
+ const triangleIndices = earcut(
310
+ slicedFlatCoords,
311
+ holeIndices.length > 0 ? holeIndices : undefined,
312
+ nDim
313
+ );
314
+ if (triangleIndices.length === 0) {
315
+ throw Error('can not tesselate invalid polygon');
316
+ }
317
+ for (let j = 0; j < triangleIndices.length; j++) {
318
+ triangles.push(triangleIndices[j] + startIdx);
319
+ }
320
+ }
321
+ // convert traingles to Uint32Array
322
+ const trianglesUint32 = new Uint32Array(triangles.length);
323
+ for (let i = 0; i < triangles.length; i++) {
324
+ trianglesUint32[i] = triangles[i];
325
+ }
326
+ return trianglesUint32;
327
+ } catch (error) {
328
+ // TODO - add logging
329
+ // there is an expection when tesselating invalid polygon, e.g. polygon with self-intersection
330
+ // return null to skip tesselating
331
+ return null;
332
+ }
333
+ }
334
+
145
335
  /**
146
336
  * get binary polygons from geoarrow polygon column
147
337
  * @param chunk one chunk of geoarrow polygon column
148
338
  * @param geoEncoding the geo encoding of the geoarrow polygon column
339
+ * @param options options for getting binary geometries
149
340
  * @returns BinaryGeometryContent
150
341
  */
151
- function getBinaryPolygonsFromChunk(chunk: arrow.Data, geoEncoding: string): BinaryGeometryContent {
342
+ function getBinaryPolygonsFromChunk(
343
+ chunk: arrow.Data,
344
+ geoEncoding: string,
345
+ options?: BinaryGeometriesFromArrowOptions
346
+ ): BinaryGeometryContent {
152
347
  const isMultiPolygon = geoEncoding === 'geoarrow.multipolygon';
153
348
 
154
349
  const polygonData = isMultiPolygon ? chunk.children[0] : chunk;
@@ -178,12 +373,17 @@ function getBinaryPolygonsFromChunk(chunk: arrow.Data, geoEncoding: string): Bin
178
373
  }
179
374
  }
180
375
 
376
+ const triangles = options?.triangulate
377
+ ? getTriangleIndices(geometryIndicies, geomOffset, flatCoordinateArray, nDim)
378
+ : null;
379
+
181
380
  return {
182
381
  featureIds,
183
382
  flatCoordinateArray,
184
383
  nDim,
185
384
  geomOffset,
186
- geometryIndicies
385
+ geometryIndicies,
386
+ ...(options?.triangulate && triangles ? {triangles} : {})
187
387
  };
188
388
  }
189
389
 
@@ -209,11 +409,23 @@ function getBinaryLinesFromChunk(chunk: arrow.Data, geoEncoding: string): Binary
209
409
 
210
410
  const numOfVertices = flatCoordinateArray.length / nDim;
211
411
  const featureIds = new Uint32Array(numOfVertices);
212
- for (let i = 0; i < chunk.length; i++) {
213
- const startIdx = geomOffset[i];
214
- const endIdx = geomOffset[i + 1];
215
- for (let j = startIdx; j < endIdx; j++) {
216
- featureIds[j] = i;
412
+
413
+ if (isMultiLineString) {
414
+ const partData = chunk.valueOffsets;
415
+ for (let i = 0; i < partData.length - 1; i++) {
416
+ const startIdx = geomOffset[partData[i]];
417
+ const endIdx = geomOffset[partData[i + 1]];
418
+ for (let j = startIdx; j < endIdx; j++) {
419
+ featureIds[j] = i;
420
+ }
421
+ }
422
+ } else {
423
+ for (let i = 0; i < chunk.length; i++) {
424
+ const startIdx = geomOffset[i];
425
+ const endIdx = geomOffset[i + 1];
426
+ for (let j = startIdx; j < endIdx; j++) {
427
+ featureIds[j] = i;
428
+ }
217
429
  }
218
430
  }
219
431
 
@@ -248,8 +460,20 @@ function getBinaryPointsFromChunk(chunk: arrow.Data, geoEncoding: string): Binar
248
460
 
249
461
  const numOfVertices = flatCoordinateArray.length / nDim;
250
462
  const featureIds = new Uint32Array(numOfVertices);
251
- for (let i = 0; i < chunk.length; i++) {
252
- featureIds[i] = i;
463
+
464
+ if (isMultiPoint) {
465
+ const partData = chunk.valueOffsets;
466
+ for (let i = 0; i < partData.length - 1; i++) {
467
+ const startIdx = partData[i];
468
+ const endIdx = partData[i + 1];
469
+ for (let j = startIdx; j < endIdx; j++) {
470
+ featureIds[j] = i;
471
+ }
472
+ }
473
+ } else {
474
+ for (let i = 0; i < chunk.length; i++) {
475
+ featureIds[i] = i;
476
+ }
253
477
  }
254
478
 
255
479
  return {