@loaders.gl/arrow 4.0.4 → 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 (51) hide show
  1. package/dist/arrow-worker.js +237 -2
  2. package/dist/dist.dev.js +1398 -610
  3. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.d.ts +4 -2
  4. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.d.ts.map +1 -1
  5. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.js +51 -32
  6. package/dist/geoarrow/convert-geoarrow-to-binary-geometry.js.map +1 -1
  7. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.d.ts +13 -0
  8. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.d.ts.map +1 -0
  9. package/dist/geoarrow/{convert-geoarrow-to-geojson.js → convert-geoarrow-to-geojson-geometry.js} +34 -27
  10. package/dist/geoarrow/convert-geoarrow-to-geojson-geometry.js.map +1 -0
  11. package/dist/geoarrow-loader.d.ts.map +1 -1
  12. package/dist/geoarrow-loader.js +0 -1
  13. package/dist/geoarrow-loader.js.map +1 -1
  14. package/dist/index.cjs +361 -332
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/parsers/parse-arrow-sync.d.ts.map +1 -1
  20. package/dist/parsers/parse-arrow-sync.js +2 -0
  21. package/dist/parsers/parse-arrow-sync.js.map +1 -1
  22. package/dist/tables/convert-arrow-to-columnar-table.d.ts.map +1 -1
  23. package/dist/tables/convert-arrow-to-columnar-table.js +1 -0
  24. package/dist/tables/convert-arrow-to-columnar-table.js.map +1 -1
  25. package/dist/tables/convert-arrow-to-geojson-table.d.ts +1 -1
  26. package/dist/tables/convert-arrow-to-geojson-table.d.ts.map +1 -1
  27. package/dist/tables/convert-arrow-to-geojson-table.js +14 -8
  28. package/dist/tables/convert-arrow-to-geojson-table.js.map +1 -1
  29. package/dist/tables/convert-columnar-to-row-table.d.ts.map +1 -1
  30. package/dist/tables/convert-columnar-to-row-table.js +1 -0
  31. package/dist/tables/convert-columnar-to-row-table.js.map +1 -1
  32. package/dist/triangulate-on-worker.d.ts +1 -1
  33. package/dist/triangulate-on-worker.d.ts.map +1 -1
  34. package/dist/triangulate-on-worker.js.map +1 -1
  35. package/dist/triangulation-worker.js +31 -24
  36. package/dist/workers/triangulation-worker.js +3 -1
  37. package/dist/workers/triangulation-worker.js.map +1 -1
  38. package/package.json +16 -10
  39. package/src/geoarrow/convert-geoarrow-to-binary-geometry.ts +81 -46
  40. package/src/geoarrow/{convert-geoarrow-to-geojson.ts → convert-geoarrow-to-geojson-geometry.ts} +56 -46
  41. package/src/geoarrow-loader.ts +0 -4
  42. package/src/index.ts +1 -1
  43. package/src/parsers/parse-arrow-sync.ts +6 -1
  44. package/src/tables/convert-arrow-to-columnar-table.ts +1 -0
  45. package/src/tables/convert-arrow-to-geojson-table.ts +18 -7
  46. package/src/tables/convert-columnar-to-row-table.ts +1 -0
  47. package/src/triangulate-on-worker.ts +1 -1
  48. package/src/workers/triangulation-worker.ts +1 -1
  49. package/dist/geoarrow/convert-geoarrow-to-geojson.d.ts +0 -20
  50. package/dist/geoarrow/convert-geoarrow-to-geojson.d.ts.map +0 -1
  51. package/dist/geoarrow/convert-geoarrow-to-geojson.js.map +0 -1
@@ -8,6 +8,15 @@ import {GeoArrowEncoding} from '@loaders.gl/gis';
8
8
  import {updateBoundsFromGeoArrowSamples} from './get-arrow-bounds';
9
9
  import {TypedArray} from '@loaders.gl/loader-utils';
10
10
 
11
+ /**
12
+ * Binary geometry type
13
+ */
14
+ enum BinaryGeometryType {
15
+ points = 'points',
16
+ lines = 'lines',
17
+ polygons = 'polygons'
18
+ }
19
+
11
20
  /**
12
21
  * Binary data from geoarrow column and can be used by e.g. deck.gl GeojsonLayer
13
22
  */
@@ -57,7 +66,9 @@ export type BinaryGeometriesFromArrowOptions = {
57
66
  /** option to specify which chunk to get binary geometries from, for progressive rendering */
58
67
  chunkIndex?: number;
59
68
  /** option to get mean centers from geometries, for polygon filtering */
60
- meanCenter?: boolean;
69
+ calculateMeanCenters?: boolean;
70
+ /** option to compute the triangle indices by tesselating polygons */
71
+ triangulate?: boolean;
61
72
  };
62
73
 
63
74
  /**
@@ -86,7 +97,7 @@ export function getBinaryGeometriesFromArrow(
86
97
 
87
98
  chunks.forEach((chunk) => {
88
99
  const {featureIds, flatCoordinateArray, nDim, geomOffset, triangles} =
89
- getBinaryGeometriesFromChunk(chunk, geoEncoding);
100
+ getBinaryGeometriesFromChunk(chunk, geoEncoding, options);
90
101
 
91
102
  const globalFeatureIds = new Uint32Array(featureIds.length);
92
103
  for (let i = 0; i < featureIds.length; i++) {
@@ -145,7 +156,7 @@ export function getBinaryGeometriesFromArrow(
145
156
  binaryGeometries,
146
157
  bounds,
147
158
  featureTypes,
148
- ...(options?.meanCenter
159
+ ...(options?.calculateMeanCenters
149
160
  ? {meanCenters: getMeanCentersFromBinaryGeometries(binaryGeometries)}
150
161
  : {})
151
162
  };
@@ -159,13 +170,13 @@ export function getBinaryGeometriesFromArrow(
159
170
  export function getMeanCentersFromBinaryGeometries(binaryGeometries: BinaryFeatures[]): number[][] {
160
171
  const globalMeanCenters: number[][] = [];
161
172
  binaryGeometries.forEach((binaryGeometry: BinaryFeatures) => {
162
- let binaryGeometryType: string | null = null;
173
+ let binaryGeometryType: keyof typeof BinaryGeometryType | null = null;
163
174
  if (binaryGeometry.points && binaryGeometry.points.positions.value.length > 0) {
164
- binaryGeometryType = 'points';
175
+ binaryGeometryType = BinaryGeometryType.points;
165
176
  } else if (binaryGeometry.lines && binaryGeometry.lines.positions.value.length > 0) {
166
- binaryGeometryType = 'lines';
177
+ binaryGeometryType = BinaryGeometryType.lines;
167
178
  } else if (binaryGeometry.polygons && binaryGeometry.polygons.positions.value.length > 0) {
168
- binaryGeometryType = 'polygons';
179
+ binaryGeometryType = BinaryGeometryType.polygons;
169
180
  }
170
181
 
171
182
  const binaryContent = binaryGeometryType ? binaryGeometry[binaryGeometryType] : null;
@@ -173,7 +184,8 @@ export function getMeanCentersFromBinaryGeometries(binaryGeometries: BinaryFeatu
173
184
  const featureIds = binaryContent.featureIds.value;
174
185
  const flatCoordinateArray = binaryContent.positions.value;
175
186
  const nDim = binaryContent.positions.size;
176
- const primitivePolygonIndices = binaryContent.primitivePolygonIndices?.value;
187
+ const primitivePolygonIndices =
188
+ binaryContent.type === 'Polygon' ? binaryContent.primitivePolygonIndices?.value : undefined;
177
189
 
178
190
  const meanCenters = getMeanCentersFromGeometry(
179
191
  featureIds,
@@ -201,30 +213,33 @@ function getMeanCentersFromGeometry(
201
213
  featureIds: TypedArray,
202
214
  flatCoordinateArray: TypedArray,
203
215
  nDim: number,
204
- geometryType: string,
216
+ geometryType: keyof typeof BinaryGeometryType,
205
217
  primitivePolygonIndices?: TypedArray
206
218
  ) {
207
219
  const meanCenters: number[][] = [];
208
220
  const vertexCount = flatCoordinateArray.length;
209
221
  let vertexIndex = 0;
222
+ let coordIdx = 0;
223
+ let primitiveIdx = 0;
210
224
  while (vertexIndex < vertexCount) {
211
225
  const featureId = featureIds[vertexIndex / nDim];
212
226
  const center = [0, 0];
213
227
  let vertexCountInFeature = 0;
214
- while (vertexIndex < vertexCount && featureIds[vertexIndex / nDim] === featureId) {
228
+ while (vertexIndex < vertexCount && featureIds[coordIdx] === featureId) {
215
229
  if (
216
- geometryType === 'polygons' &&
217
- primitivePolygonIndices &&
218
- primitivePolygonIndices.indexOf(vertexIndex / nDim) >= 0
230
+ geometryType === BinaryGeometryType.polygons &&
231
+ primitivePolygonIndices?.[primitiveIdx] === coordIdx
219
232
  ) {
220
233
  // skip the first point since it is the same as the last point in each ring for polygons
221
234
  vertexIndex += nDim;
235
+ primitiveIdx++;
222
236
  } else {
223
237
  center[0] += flatCoordinateArray[vertexIndex];
224
238
  center[1] += flatCoordinateArray[vertexIndex + 1];
225
239
  vertexIndex += nDim;
226
240
  vertexCountInFeature++;
227
241
  }
242
+ coordIdx += 1;
228
243
  }
229
244
  center[0] /= vertexCountInFeature;
230
245
  center[1] /= vertexCountInFeature;
@@ -237,11 +252,13 @@ function getMeanCentersFromGeometry(
237
252
  * get binary geometries from geoarrow column
238
253
  * @param chunk one chunk/batch of geoarrow column
239
254
  * @param geoEncoding geo encoding of the geoarrow column
255
+ * @param options options for getting binary geometries
240
256
  * @returns BinaryGeometryContent
241
257
  */
242
258
  function getBinaryGeometriesFromChunk(
243
259
  chunk: arrow.Data,
244
- geoEncoding: GeoArrowEncoding
260
+ geoEncoding: GeoArrowEncoding,
261
+ options?: BinaryGeometriesFromArrowOptions
245
262
  ): BinaryGeometryContent {
246
263
  switch (geoEncoding) {
247
264
  case 'geoarrow.point':
@@ -252,7 +269,7 @@ function getBinaryGeometriesFromChunk(
252
269
  return getBinaryLinesFromChunk(chunk, geoEncoding);
253
270
  case 'geoarrow.polygon':
254
271
  case 'geoarrow.multipolygon':
255
- return getBinaryPolygonsFromChunk(chunk, geoEncoding);
272
+ return getBinaryPolygonsFromChunk(chunk, geoEncoding, options);
256
273
  default:
257
274
  throw Error('invalid geoarrow encoding');
258
275
  }
@@ -271,47 +288,62 @@ export function getTriangleIndices(
271
288
  primitivePolygonIndices: Int32Array,
272
289
  flatCoordinateArray: Float64Array,
273
290
  nDim: number
274
- ): Uint32Array {
275
- let primitiveIndex = 0;
276
- const triangles: number[] = [];
277
- // loop polygonIndices to get triangles
278
- for (let i = 0; i < polygonIndices.length - 1; i++) {
279
- const startIdx = polygonIndices[i];
280
- const endIdx = polygonIndices[i + 1];
281
- // get subarray of flatCoordinateArray
282
- const slicedFlatCoords = flatCoordinateArray.subarray(startIdx * nDim, endIdx * nDim);
283
- // get holeIndices for earcut
284
- const holeIndices: number[] = [];
285
- while (primitivePolygonIndices[primitiveIndex] < endIdx) {
286
- if (primitivePolygonIndices[primitiveIndex] > startIdx) {
287
- holeIndices.push(primitivePolygonIndices[primitiveIndex] - startIdx);
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);
288
319
  }
289
- primitiveIndex++;
290
320
  }
291
- const triangleIndices = earcut(
292
- slicedFlatCoords,
293
- holeIndices.length > 0 ? holeIndices : undefined,
294
- nDim
295
- );
296
- for (let j = 0; j < triangleIndices.length; j++) {
297
- triangles.push(triangleIndices[j] + startIdx);
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];
298
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;
299
332
  }
300
- // convert traingles to Uint32Array
301
- const trianglesUint32 = new Uint32Array(triangles.length);
302
- for (let i = 0; i < triangles.length; i++) {
303
- trianglesUint32[i] = triangles[i];
304
- }
305
- return trianglesUint32;
306
333
  }
307
334
 
308
335
  /**
309
336
  * get binary polygons from geoarrow polygon column
310
337
  * @param chunk one chunk of geoarrow polygon column
311
338
  * @param geoEncoding the geo encoding of the geoarrow polygon column
339
+ * @param options options for getting binary geometries
312
340
  * @returns BinaryGeometryContent
313
341
  */
314
- function getBinaryPolygonsFromChunk(chunk: arrow.Data, geoEncoding: string): BinaryGeometryContent {
342
+ function getBinaryPolygonsFromChunk(
343
+ chunk: arrow.Data,
344
+ geoEncoding: string,
345
+ options?: BinaryGeometriesFromArrowOptions
346
+ ): BinaryGeometryContent {
315
347
  const isMultiPolygon = geoEncoding === 'geoarrow.multipolygon';
316
348
 
317
349
  const polygonData = isMultiPolygon ? chunk.children[0] : chunk;
@@ -341,14 +373,17 @@ function getBinaryPolygonsFromChunk(chunk: arrow.Data, geoEncoding: string): Bin
341
373
  }
342
374
  }
343
375
 
344
- const triangles = getTriangleIndices(geometryIndicies, geomOffset, flatCoordinateArray, nDim);
376
+ const triangles = options?.triangulate
377
+ ? getTriangleIndices(geometryIndicies, geomOffset, flatCoordinateArray, nDim)
378
+ : null;
379
+
345
380
  return {
346
381
  featureIds,
347
382
  flatCoordinateArray,
348
383
  nDim,
349
384
  geomOffset,
350
385
  geometryIndicies,
351
- triangles
386
+ ...(options?.triangulate && triangles ? {triangles} : {})
352
387
  };
353
388
  }
354
389
 
@@ -1,81 +1,95 @@
1
1
  // loaders.gl, MIT license
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
- import * as arrow from 'apache-arrow';
4
+ // import * as arrow from 'apache-arrow';
5
5
  import {
6
- Feature,
7
6
  MultiPolygon,
8
7
  Position,
9
8
  Polygon,
10
9
  MultiPoint,
11
10
  Point,
12
11
  MultiLineString,
13
- LineString
12
+ LineString,
13
+ Geometry,
14
+ BinaryGeometry
14
15
  } from '@loaders.gl/schema';
15
- import type {GeoArrowEncoding} from '@loaders.gl/gis';
16
-
17
- type RawArrowFeature = {
18
- data: arrow.Vector;
19
- encoding?: GeoArrowEncoding;
20
- };
16
+ import {binaryToGeometry, type GeoArrowEncoding} from '@loaders.gl/gis';
17
+ import {WKBLoader, WKTLoader} from '@loaders.gl/wkt';
21
18
 
22
19
  /**
23
20
  * parse geometry from arrow data that is returned from processArrowData()
24
- * NOTE: this function could be duplicated with the binaryToFeature() in deck.gl,
25
- * it is currently only used for picking because currently deck.gl returns only the index of the feature
26
- * So the following functions could be deprecated once deck.gl returns the feature directly for binary geojson layer
21
+ * NOTE: this function could be deduplicated with the binaryToFeature() in deck.gl,
22
+ * it is currently used for deck.gl picking because currently deck.gl returns only the index of the feature
27
23
  *
28
- * @param rawData the raw geometry data returned from processArrowData, which is an object with two properties: encoding and data
29
- * @see processArrowData
24
+ * @param data data extraced from arrow vector representing a geometry
25
+ * @param encoding the geoarrow encoding of the geometry column
30
26
  * @returns Feature or null
31
27
  */
32
- export function parseGeometryFromArrow(rawData: RawArrowFeature): Feature | null {
33
- const encoding = rawData.encoding?.toLowerCase() as typeof rawData.encoding;
34
- const data = rawData.data;
35
- if (!encoding || !data) {
28
+ export function parseGeometryFromArrow(
29
+ arrowCellValue: any,
30
+ encoding?: GeoArrowEncoding
31
+ ): Geometry | null {
32
+ // sanity
33
+ encoding = encoding?.toLowerCase() as GeoArrowEncoding;
34
+ if (!encoding || !arrowCellValue) {
36
35
  return null;
37
36
  }
38
37
 
39
- let geometry;
38
+ let geometry: Geometry;
40
39
 
41
40
  switch (encoding) {
42
41
  case 'geoarrow.multipolygon':
43
- geometry = arrowMultiPolygonToFeature(data);
42
+ geometry = arrowMultiPolygonToFeature(arrowCellValue);
44
43
  break;
45
44
  case 'geoarrow.polygon':
46
- geometry = arrowPolygonToFeature(data);
45
+ geometry = arrowPolygonToFeature(arrowCellValue);
47
46
  break;
48
47
  case 'geoarrow.multipoint':
49
- geometry = arrowMultiPointToFeature(data);
48
+ geometry = arrowMultiPointToFeature(arrowCellValue);
50
49
  break;
51
50
  case 'geoarrow.point':
52
- geometry = arrowPointToFeature(data);
51
+ geometry = arrowPointToFeature(arrowCellValue);
53
52
  break;
54
53
  case 'geoarrow.multilinestring':
55
- geometry = arrowMultiLineStringToFeature(data);
54
+ geometry = arrowMultiLineStringToFeature(arrowCellValue);
56
55
  break;
57
56
  case 'geoarrow.linestring':
58
- geometry = arrowLineStringToFeature(data);
57
+ geometry = arrowLineStringToFeature(arrowCellValue);
59
58
  break;
60
59
  case 'geoarrow.wkb':
61
- throw Error(`GeoArrow encoding not supported ${encoding}`);
60
+ geometry = arrowWKBToFeature(arrowCellValue);
61
+ break;
62
62
  case 'geoarrow.wkt':
63
- throw Error(`GeoArrow encoding not supported ${encoding}`);
63
+ geometry = arrowWKTToFeature(arrowCellValue);
64
+ break;
64
65
  default: {
65
66
  throw Error(`GeoArrow encoding not supported ${encoding}`);
66
67
  }
67
68
  }
68
- return {
69
- type: 'Feature',
70
- geometry,
71
- properties: {}
72
- };
69
+
70
+ return geometry;
71
+ }
72
+
73
+ function arrowWKBToFeature(arrowCellValue: any) {
74
+ // The actual WKB array buffer starts from byteOffset and ends at byteOffset + byteLength
75
+ const arrayBuffer: ArrayBuffer = arrowCellValue.buffer.slice(
76
+ arrowCellValue.byteOffset,
77
+ arrowCellValue.byteOffset + arrowCellValue.byteLength
78
+ );
79
+ const binaryGeometry = WKBLoader.parseSync?.(arrayBuffer)! as BinaryGeometry;
80
+ const geometry = binaryToGeometry(binaryGeometry);
81
+ return geometry;
82
+ }
83
+
84
+ function arrowWKTToFeature(arrowCellValue: any) {
85
+ const string: string = arrowCellValue;
86
+ return WKTLoader.parseTextSync?.(string)!;
73
87
  }
74
88
 
75
89
  /**
76
90
  * convert Arrow MultiPolygon to geojson Feature
77
91
  */
78
- function arrowMultiPolygonToFeature(arrowMultiPolygon: arrow.Vector): MultiPolygon {
92
+ function arrowMultiPolygonToFeature(arrowMultiPolygon: any): MultiPolygon {
79
93
  const multiPolygon: Position[][][] = [];
80
94
  for (let m = 0; m < arrowMultiPolygon.length; m++) {
81
95
  const arrowPolygon = arrowMultiPolygon.get(m);
@@ -102,7 +116,7 @@ function arrowMultiPolygonToFeature(arrowMultiPolygon: arrow.Vector): MultiPolyg
102
116
  /**
103
117
  * convert Arrow Polygon to geojson Feature
104
118
  */
105
- function arrowPolygonToFeature(arrowPolygon: arrow.Vector): Polygon {
119
+ function arrowPolygonToFeature(arrowPolygon: any): Polygon {
106
120
  const polygon: Position[][] = [];
107
121
  for (let i = 0; arrowPolygon && i < arrowPolygon.length; i++) {
108
122
  const arrowRing = arrowPolygon.get(i);
@@ -124,7 +138,7 @@ function arrowPolygonToFeature(arrowPolygon: arrow.Vector): Polygon {
124
138
  /**
125
139
  * convert Arrow MultiPoint to geojson MultiPoint
126
140
  */
127
- function arrowMultiPointToFeature(arrowMultiPoint: arrow.Vector): MultiPoint {
141
+ function arrowMultiPointToFeature(arrowMultiPoint: any): MultiPoint {
128
142
  const multiPoint: Position[] = [];
129
143
  for (let i = 0; arrowMultiPoint && i < arrowMultiPoint.length; i++) {
130
144
  const arrowPoint = arrowMultiPoint.get(i);
@@ -133,29 +147,27 @@ function arrowMultiPointToFeature(arrowMultiPoint: arrow.Vector): MultiPoint {
133
147
  multiPoint.push(coord);
134
148
  }
135
149
  }
136
- const geometry: MultiPoint = {
150
+ return {
137
151
  type: 'MultiPoint',
138
152
  coordinates: multiPoint
139
153
  };
140
- return geometry;
141
154
  }
142
155
 
143
156
  /**
144
157
  * convert Arrow Point to geojson Point
145
158
  */
146
- function arrowPointToFeature(arrowPoint: arrow.Vector): Point {
159
+ function arrowPointToFeature(arrowPoint: any): Point {
147
160
  const point: Position = Array.from(arrowPoint);
148
- const geometry: Point = {
161
+ return {
149
162
  type: 'Point',
150
163
  coordinates: point
151
164
  };
152
- return geometry;
153
165
  }
154
166
 
155
167
  /**
156
168
  * convert Arrow MultiLineString to geojson MultiLineString
157
169
  */
158
- function arrowMultiLineStringToFeature(arrowMultiLineString: arrow.Vector): MultiLineString {
170
+ function arrowMultiLineStringToFeature(arrowMultiLineString: any): MultiLineString {
159
171
  const multiLineString: Position[][] = [];
160
172
  for (let i = 0; arrowMultiLineString && i < arrowMultiLineString.length; i++) {
161
173
  const arrowLineString = arrowMultiLineString.get(i);
@@ -169,17 +181,16 @@ function arrowMultiLineStringToFeature(arrowMultiLineString: arrow.Vector): Mult
169
181
  }
170
182
  multiLineString.push(lineString);
171
183
  }
172
- const geometry: MultiLineString = {
184
+ return {
173
185
  type: 'MultiLineString',
174
186
  coordinates: multiLineString
175
187
  };
176
- return geometry;
177
188
  }
178
189
 
179
190
  /**
180
191
  * convert Arrow LineString to geojson LineString
181
192
  */
182
- function arrowLineStringToFeature(arrowLineString: arrow.Vector): LineString {
193
+ function arrowLineStringToFeature(arrowLineString: any): LineString {
183
194
  const lineString: Position[] = [];
184
195
  for (let i = 0; arrowLineString && i < arrowLineString.length; i++) {
185
196
  const arrowCoord = arrowLineString.get(i);
@@ -188,9 +199,8 @@ function arrowLineStringToFeature(arrowLineString: arrow.Vector): LineString {
188
199
  lineString.push(coords);
189
200
  }
190
201
  }
191
- const geometry: LineString = {
202
+ return {
192
203
  type: 'LineString',
193
204
  coordinates: lineString
194
205
  };
195
- return geometry;
196
206
  }
@@ -8,10 +8,6 @@ import type {ArrowTable, ArrowTableBatch} from './lib/arrow-table';
8
8
  import {parseGeoArrowSync} from './parsers/parse-geoarrow-sync';
9
9
  import {parseGeoArrowInBatches} from './parsers/parse-geoarrow-in-batches';
10
10
 
11
- // __VERSION__ is injected by babel-plugin-version-inline
12
- // @ts-ignore TS2304: Cannot find name '__VERSION__'.
13
- const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
14
-
15
11
  export type GeoArrowLoaderOptions = LoaderOptions & {
16
12
  arrow?: {
17
13
  shape: 'arrow-table' | 'binary-geometry';
package/src/index.ts CHANGED
@@ -60,7 +60,7 @@ export {
60
60
 
61
61
  export {updateBoundsFromGeoArrowSamples} from './geoarrow/get-arrow-bounds';
62
62
 
63
- export {parseGeometryFromArrow} from './geoarrow/convert-geoarrow-to-geojson';
63
+ export {parseGeometryFromArrow} from './geoarrow/convert-geoarrow-to-geojson-geometry';
64
64
 
65
65
  export {convertArrowToGeoJSONTable} from './tables/convert-arrow-to-geojson-table';
66
66
 
@@ -6,6 +6,7 @@ import type {ArrowTable} from '../lib/arrow-table';
6
6
  import {convertTable} from '@loaders.gl/schema';
7
7
  import * as arrow from 'apache-arrow';
8
8
  import {convertArrowToColumnarTable} from '../tables/convert-arrow-to-columnar-table';
9
+ import {serializeArrowSchema} from '../schema/convert-arrow-schema';
9
10
 
10
11
  // Parses arrow to a columnar table
11
12
  export function parseArrowSync(
@@ -13,7 +14,11 @@ export function parseArrowSync(
13
14
  options?: {shape?: 'arrow-table' | 'columnar-table' | 'object-row-table' | 'array-row-table'}
14
15
  ): ArrowTable | ColumnarTable | ObjectRowTable | ArrayRowTable {
15
16
  const apacheArrowTable = arrow.tableFromIPC([new Uint8Array(arrayBuffer)]);
16
- const arrowTable: ArrowTable = {shape: 'arrow-table', data: apacheArrowTable};
17
+ const arrowTable: ArrowTable = {
18
+ shape: 'arrow-table',
19
+ schema: serializeArrowSchema(apacheArrowTable.schema),
20
+ data: apacheArrowTable
21
+ };
17
22
 
18
23
  const shape = options?.shape || 'arrow-table';
19
24
  switch (shape) {
@@ -24,6 +24,7 @@ export function convertArrowToColumnarTable(table: ArrowTable): ColumnarTable {
24
24
 
25
25
  return {
26
26
  shape: 'columnar-table',
27
+ schema: table.schema,
27
28
  data: columnarTable
28
29
  };
29
30
  }
@@ -2,7 +2,7 @@
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
4
  import type {Feature, GeoJSONTable} from '@loaders.gl/schema';
5
- import type * as arrow from 'apache-arrow';
5
+ import * as arrow from 'apache-arrow';
6
6
  import type {ArrowTable} from '../lib/arrow-table';
7
7
  import {serializeArrowSchema, parseGeometryFromArrow} from '@loaders.gl/arrow';
8
8
  import {getGeometryColumnsFromSchema} from '@loaders.gl/gis';
@@ -16,6 +16,7 @@ import {getGeometryColumnsFromSchema} from '@loaders.gl/gis';
16
16
  export function convertApacheArrowToArrowTable(arrowTable: arrow.Table): ArrowTable {
17
17
  return {
18
18
  shape: 'arrow-table',
19
+ schema: serializeArrowSchema(arrowTable.schema),
19
20
  data: arrowTable
20
21
  };
21
22
  }
@@ -34,21 +35,31 @@ export function convertArrowToGeoJSONTable(table: ArrowTable): GeoJSONTable {
34
35
 
35
36
  const features: Feature[] = [];
36
37
 
37
- for (let row = 0; row < arrowTable.numRows; row++) {
38
- // get first geometry from arrow geometry column
39
- const arrowGeometry = arrowTable.getChild('geometry')?.get(row);
40
- const arrowGeometryObject = {encoding, data: arrowGeometry};
38
+ // Remove geometry columns
39
+ const propertyColumnNames = arrowTable.schema.fields
40
+ .map((field) => field.name)
41
+ // TODO - this deletes all geometry columns
42
+ .filter((name) => !(name in geometryColumns));
43
+ const propertiesTable = arrowTable.select(propertyColumnNames);
44
+
45
+ const arrowGeometryColumn = arrowTable.getChild('geometry');
41
46
 
47
+ for (let row = 0; row < arrowTable.numRows; row++) {
48
+ // get the geometry value from arrow geometry column
49
+ // Note that type can vary
50
+ const arrowGeometry = arrowGeometryColumn?.get(row);
42
51
  // parse arrow geometry to geojson feature
43
- const feature = parseGeometryFromArrow(arrowGeometryObject);
52
+ const feature = parseGeometryFromArrow(arrowGeometry, encoding);
44
53
  if (feature) {
45
- features.push(feature);
54
+ const properties = propertiesTable.get(row)?.toJSON() || {};
55
+ features.push({type: 'Feature', geometry: feature, properties});
46
56
  }
47
57
  }
48
58
 
49
59
  return {
50
60
  shape: 'geojson-table',
51
61
  type: 'FeatureCollection',
62
+ schema: table.schema,
52
63
  features
53
64
  };
54
65
  }
@@ -24,6 +24,7 @@ export function convertColumnarToRowFormatTable(columnarTable: ColumnarTable): O
24
24
 
25
25
  return {
26
26
  shape: 'object-row-table',
27
+ schema: columnarTable.schema,
27
28
  data: rowFormatTable
28
29
  };
29
30
  }
@@ -22,7 +22,7 @@ export type TriangulateInput = {
22
22
 
23
23
  /** Result type for operation: 'triangulate' */
24
24
  export type TriangulateResult = TriangulateInput & {
25
- triangleIndices: Uint32Array;
25
+ triangleIndices?: Uint32Array;
26
26
  };
27
27
 
28
28
  /**
@@ -35,5 +35,5 @@ function triangulateBatch(data: TriangulateInput): TriangulateResult {
35
35
  data.flatCoordinateArray,
36
36
  data.nDim
37
37
  );
38
- return {...data, triangleIndices};
38
+ return {...data, ...(triangleIndices ? {triangleIndices} : {})};
39
39
  }
@@ -1,20 +0,0 @@
1
- import * as arrow from 'apache-arrow';
2
- import { Feature } from '@loaders.gl/schema';
3
- import type { GeoArrowEncoding } from '@loaders.gl/gis';
4
- type RawArrowFeature = {
5
- data: arrow.Vector;
6
- encoding?: GeoArrowEncoding;
7
- };
8
- /**
9
- * parse geometry from arrow data that is returned from processArrowData()
10
- * NOTE: this function could be duplicated with the binaryToFeature() in deck.gl,
11
- * it is currently only used for picking because currently deck.gl returns only the index of the feature
12
- * So the following functions could be deprecated once deck.gl returns the feature directly for binary geojson layer
13
- *
14
- * @param rawData the raw geometry data returned from processArrowData, which is an object with two properties: encoding and data
15
- * @see processArrowData
16
- * @returns Feature or null
17
- */
18
- export declare function parseGeometryFromArrow(rawData: RawArrowFeature): Feature | null;
19
- export {};
20
- //# sourceMappingURL=convert-geoarrow-to-geojson.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"convert-geoarrow-to-geojson.d.ts","sourceRoot":"","sources":["../../src/geoarrow/convert-geoarrow-to-geojson.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,OAAO,EAQR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAEtD,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,GAAG,IAAI,CAyC/E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"convert-geoarrow-to-geojson.js","names":["parseGeometryFromArrow","rawData","_rawData$encoding","encoding","toLowerCase","data","geometry","arrowMultiPolygonToFeature","arrowPolygonToFeature","arrowMultiPointToFeature","arrowPointToFeature","arrowMultiLineStringToFeature","arrowLineStringToFeature","Error","type","properties","arrowMultiPolygon","multiPolygon","m","length","arrowPolygon","get","polygon","i","arrowRing","ring","j","arrowCoord","coord","Array","from","push","coordinates","coords","arrowMultiPoint","multiPoint","arrowPoint","point","arrowMultiLineString","multiLineString","arrowLineString","lineString"],"sources":["../../src/geoarrow/convert-geoarrow-to-geojson.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Copyright (c) vis.gl contributors\n\nimport * as arrow from 'apache-arrow';\nimport {\n Feature,\n MultiPolygon,\n Position,\n Polygon,\n MultiPoint,\n Point,\n MultiLineString,\n LineString\n} from '@loaders.gl/schema';\nimport type {GeoArrowEncoding} from '@loaders.gl/gis';\n\ntype RawArrowFeature = {\n data: arrow.Vector;\n encoding?: GeoArrowEncoding;\n};\n\n/**\n * parse geometry from arrow data that is returned from processArrowData()\n * NOTE: this function could be duplicated with the binaryToFeature() in deck.gl,\n * it is currently only used for picking because currently deck.gl returns only the index of the feature\n * So the following functions could be deprecated once deck.gl returns the feature directly for binary geojson layer\n *\n * @param rawData the raw geometry data returned from processArrowData, which is an object with two properties: encoding and data\n * @see processArrowData\n * @returns Feature or null\n */\nexport function parseGeometryFromArrow(rawData: RawArrowFeature): Feature | null {\n const encoding = rawData.encoding?.toLowerCase() as typeof rawData.encoding;\n const data = rawData.data;\n if (!encoding || !data) {\n return null;\n }\n\n let geometry;\n\n switch (encoding) {\n case 'geoarrow.multipolygon':\n geometry = arrowMultiPolygonToFeature(data);\n break;\n case 'geoarrow.polygon':\n geometry = arrowPolygonToFeature(data);\n break;\n case 'geoarrow.multipoint':\n geometry = arrowMultiPointToFeature(data);\n break;\n case 'geoarrow.point':\n geometry = arrowPointToFeature(data);\n break;\n case 'geoarrow.multilinestring':\n geometry = arrowMultiLineStringToFeature(data);\n break;\n case 'geoarrow.linestring':\n geometry = arrowLineStringToFeature(data);\n break;\n case 'geoarrow.wkb':\n throw Error(`GeoArrow encoding not supported ${encoding}`);\n case 'geoarrow.wkt':\n throw Error(`GeoArrow encoding not supported ${encoding}`);\n default: {\n throw Error(`GeoArrow encoding not supported ${encoding}`);\n }\n }\n return {\n type: 'Feature',\n geometry,\n properties: {}\n };\n}\n\n/**\n * convert Arrow MultiPolygon to geojson Feature\n */\nfunction arrowMultiPolygonToFeature(arrowMultiPolygon: arrow.Vector): MultiPolygon {\n const multiPolygon: Position[][][] = [];\n for (let m = 0; m < arrowMultiPolygon.length; m++) {\n const arrowPolygon = arrowMultiPolygon.get(m);\n const polygon: Position[][] = [];\n for (let i = 0; arrowPolygon && i < arrowPolygon?.length; i++) {\n const arrowRing = arrowPolygon?.get(i);\n const ring: Position[] = [];\n for (let j = 0; arrowRing && j < arrowRing.length; j++) {\n const arrowCoord = arrowRing.get(j);\n const coord: Position = Array.from(arrowCoord);\n ring.push(coord);\n }\n polygon.push(ring);\n }\n multiPolygon.push(polygon);\n }\n const geometry: MultiPolygon = {\n type: 'MultiPolygon',\n coordinates: multiPolygon\n };\n return geometry;\n}\n\n/**\n * convert Arrow Polygon to geojson Feature\n */\nfunction arrowPolygonToFeature(arrowPolygon: arrow.Vector): Polygon {\n const polygon: Position[][] = [];\n for (let i = 0; arrowPolygon && i < arrowPolygon.length; i++) {\n const arrowRing = arrowPolygon.get(i);\n const ring: Position[] = [];\n for (let j = 0; arrowRing && j < arrowRing.length; j++) {\n const arrowCoord = arrowRing.get(j);\n const coords: Position = Array.from(arrowCoord);\n ring.push(coords);\n }\n polygon.push(ring);\n }\n const geometry: Polygon = {\n type: 'Polygon',\n coordinates: polygon\n };\n return geometry;\n}\n\n/**\n * convert Arrow MultiPoint to geojson MultiPoint\n */\nfunction arrowMultiPointToFeature(arrowMultiPoint: arrow.Vector): MultiPoint {\n const multiPoint: Position[] = [];\n for (let i = 0; arrowMultiPoint && i < arrowMultiPoint.length; i++) {\n const arrowPoint = arrowMultiPoint.get(i);\n if (arrowPoint) {\n const coord: Position = Array.from(arrowPoint);\n multiPoint.push(coord);\n }\n }\n const geometry: MultiPoint = {\n type: 'MultiPoint',\n coordinates: multiPoint\n };\n return geometry;\n}\n\n/**\n * convert Arrow Point to geojson Point\n */\nfunction arrowPointToFeature(arrowPoint: arrow.Vector): Point {\n const point: Position = Array.from(arrowPoint);\n const geometry: Point = {\n type: 'Point',\n coordinates: point\n };\n return geometry;\n}\n\n/**\n * convert Arrow MultiLineString to geojson MultiLineString\n */\nfunction arrowMultiLineStringToFeature(arrowMultiLineString: arrow.Vector): MultiLineString {\n const multiLineString: Position[][] = [];\n for (let i = 0; arrowMultiLineString && i < arrowMultiLineString.length; i++) {\n const arrowLineString = arrowMultiLineString.get(i);\n const lineString: Position[] = [];\n for (let j = 0; arrowLineString && j < arrowLineString.length; j++) {\n const arrowCoord = arrowLineString.get(j);\n if (arrowCoord) {\n const coords: Position = Array.from(arrowCoord);\n lineString.push(coords);\n }\n }\n multiLineString.push(lineString);\n }\n const geometry: MultiLineString = {\n type: 'MultiLineString',\n coordinates: multiLineString\n };\n return geometry;\n}\n\n/**\n * convert Arrow LineString to geojson LineString\n */\nfunction arrowLineStringToFeature(arrowLineString: arrow.Vector): LineString {\n const lineString: Position[] = [];\n for (let i = 0; arrowLineString && i < arrowLineString.length; i++) {\n const arrowCoord = arrowLineString.get(i);\n if (arrowCoord) {\n const coords: Position = Array.from(arrowCoord);\n lineString.push(coords);\n }\n }\n const geometry: LineString = {\n type: 'LineString',\n coordinates: lineString\n };\n return geometry;\n}\n"],"mappings":"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"}