@loaders.gl/geoarrow 4.4.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 (70) hide show
  1. package/LICENSE +41 -0
  2. package/README.md +7 -0
  3. package/dist/geo-column/geo-column-info.d.ts +20 -0
  4. package/dist/geo-column/geo-column-info.d.ts.map +1 -0
  5. package/dist/geo-column/geo-column-info.js +74 -0
  6. package/dist/geo-column/geo-column.d.ts +61 -0
  7. package/dist/geo-column/geo-column.d.ts.map +1 -0
  8. package/dist/geo-column/geo-column.js +4 -0
  9. package/dist/geoarrow-functions.d.ts +131 -0
  10. package/dist/geoarrow-functions.d.ts.map +1 -0
  11. package/dist/geoarrow-functions.js +218 -0
  12. package/dist/geoarrow-types.d.ts +49 -0
  13. package/dist/geoarrow-types.d.ts.map +1 -0
  14. package/dist/geoarrow-types.js +4 -0
  15. package/dist/get-arrow-bounds.d.ts +11 -0
  16. package/dist/get-arrow-bounds.d.ts.map +1 -0
  17. package/dist/get-arrow-bounds.js +34 -0
  18. package/dist/get-geoarrow-geometry-info.d.ts +30 -0
  19. package/dist/get-geoarrow-geometry-info.d.ts.map +1 -0
  20. package/dist/get-geoarrow-geometry-info.js +124 -0
  21. package/dist/index.cjs +430 -0
  22. package/dist/index.cjs.map +7 -0
  23. package/dist/index.d.ts +11 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +12 -0
  26. package/dist/mesharrow/arrow-fixed-size-list-utils.d.ts +11 -0
  27. package/dist/mesharrow/arrow-fixed-size-list-utils.d.ts.map +1 -0
  28. package/dist/mesharrow/arrow-fixed-size-list-utils.js +39 -0
  29. package/dist/mesharrow/arrow-list-of-fixed-size-list-utils.d.ts +11 -0
  30. package/dist/mesharrow/arrow-list-of-fixed-size-list-utils.d.ts.map +1 -0
  31. package/dist/mesharrow/arrow-list-of-fixed-size-list-utils.js +31 -0
  32. package/dist/mesharrow/get-bounding-box.d.ts +5 -0
  33. package/dist/mesharrow/get-bounding-box.d.ts.map +1 -0
  34. package/dist/mesharrow/get-bounding-box.js +33 -0
  35. package/dist/mesharrow/get-deck-binary-data.d.ts +13 -0
  36. package/dist/mesharrow/get-deck-binary-data.d.ts.map +1 -0
  37. package/dist/mesharrow/get-deck-binary-data.js +24 -0
  38. package/dist/mesharrow/mesh-accessors.d.ts +8 -0
  39. package/dist/mesharrow/mesh-accessors.d.ts.map +1 -0
  40. package/dist/mesharrow/mesh-accessors.js +18 -0
  41. package/dist/metadata/geoarrow-metadata.d.ts +27 -0
  42. package/dist/metadata/geoarrow-metadata.d.ts.map +1 -0
  43. package/dist/metadata/geoarrow-metadata.js +71 -0
  44. package/dist/metadata/geoparquet-metadata-schema.d.ts +79 -0
  45. package/dist/metadata/geoparquet-metadata-schema.d.ts.map +1 -0
  46. package/dist/metadata/geoparquet-metadata-schema.js +69 -0
  47. package/dist/metadata/geoparquet-metadata.d.ts +45 -0
  48. package/dist/metadata/geoparquet-metadata.d.ts.map +1 -0
  49. package/dist/metadata/geoparquet-metadata.js +131 -0
  50. package/dist/metadata/metadata-utils.d.ts +21 -0
  51. package/dist/metadata/metadata-utils.d.ts.map +1 -0
  52. package/dist/metadata/metadata-utils.js +14 -0
  53. package/package.json +63 -0
  54. package/src/geo-column/geo-column-info.ts +114 -0
  55. package/src/geo-column/geo-column.ts +85 -0
  56. package/src/geoarrow-functions.ts +258 -0
  57. package/src/geoarrow-types.ts +72 -0
  58. package/src/get-arrow-bounds.ts +41 -0
  59. package/src/get-geo-column-from-geoarrow.ts.disabled +251 -0
  60. package/src/get-geoarrow-geometry-info.ts +172 -0
  61. package/src/index.ts +57 -0
  62. package/src/mesharrow/arrow-fixed-size-list-utils.ts +62 -0
  63. package/src/mesharrow/arrow-list-of-fixed-size-list-utils.ts +47 -0
  64. package/src/mesharrow/get-bounding-box.ts +39 -0
  65. package/src/mesharrow/get-deck-binary-data.ts +43 -0
  66. package/src/mesharrow/mesh-accessors.ts +27 -0
  67. package/src/metadata/geoarrow-metadata.ts +102 -0
  68. package/src/metadata/geoparquet-metadata-schema.ts +71 -0
  69. package/src/metadata/geoparquet-metadata.ts +195 -0
  70. package/src/metadata/metadata-utils.ts +32 -0
@@ -0,0 +1,172 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import * as arrow from 'apache-arrow';
6
+ import type {GeoArrowEncoding} from './metadata/geoarrow-metadata';
7
+
8
+ /**
9
+ * @see https://geoarrow.org/format.html#memory-layouts
10
+ */
11
+ export type GeoArrowGeometryInfo = {
12
+ /** Geometry encodings that are compatible with this column (Field) */
13
+ compatibleEncodings: GeoArrowEncoding[];
14
+ /** How many levels of List<> nesting */
15
+ nesting: 0 | 1 | 2 | 3;
16
+ /** How many values per coordinate */
17
+ dimension: number;
18
+ /**
19
+ * - 0: A point is just a Coordinate
20
+ * - 1: A line string or a multipoint is a List<Coordinate>
21
+ * - 2: A polygon or a multilinestring are List<List<Coordinate>>
22
+ * - 3: multipolygons are List<List<List<Coordinate>>>
23
+ */
24
+ /** Coordinate memory layout {x,y,...} vs [x,y,...] */
25
+ coordinates: 'separated' | 'interleaved';
26
+ /** Coordinate */
27
+ valueType: 'double'; // 'float'
28
+ };
29
+
30
+ /** Helper type used to test coordinates */
31
+ type CoordinateFieldInfo = {
32
+ coordinates: 'interleaved' | 'separated';
33
+ dimension: 2 | 3 | 4;
34
+ valueType: 'double';
35
+ };
36
+
37
+ /**
38
+ * Examines a column containing GeoArrow formatted data and returns information about the geometry type
39
+ * that can be useful during traversal
40
+ * @see https://geoarrow.org/format.html#memory-layouts
41
+ */
42
+ // eslint-disable-next-line max-statements
43
+ export function getGeoArrowGeometryInfo(arrowField: arrow.Field): GeoArrowGeometryInfo | null {
44
+ if (arrowField.type instanceof arrow.Utf8) {
45
+ return {
46
+ compatibleEncodings: ['geoarrow.wkt'],
47
+ nesting: 0,
48
+ /** @note: Dimension encoded in WKT */
49
+ dimension: 2,
50
+ coordinates: 'interleaved',
51
+ valueType: 'double'
52
+ };
53
+ }
54
+
55
+ if (arrowField.type instanceof arrow.Binary || arrowField.type instanceof arrow.LargeBinary) {
56
+ return {
57
+ compatibleEncodings: ['geoarrow.wkb'],
58
+ nesting: 0,
59
+ /** @note: Dimension encoded in WKB */
60
+ dimension: 2,
61
+ coordinates: 'interleaved',
62
+ valueType: 'double'
63
+ };
64
+ }
65
+ let coordinateInfo = getCoordinateFieldInfo(arrowField);
66
+ // A point is just a Coordinate
67
+ if (coordinateInfo) {
68
+ return {
69
+ compatibleEncodings: ['geoarrow.point'],
70
+ nesting: 0,
71
+ ...coordinateInfo
72
+ };
73
+ }
74
+
75
+ // A line string or a multipoint is a List<Coordinate>
76
+ if (!(arrowField.type instanceof arrow.List)) {
77
+ return null;
78
+ }
79
+ arrowField = arrowField.type.children[0];
80
+
81
+ coordinateInfo = getCoordinateFieldInfo(arrowField);
82
+ if (coordinateInfo) {
83
+ return {
84
+ compatibleEncodings: ['geoarrow.linestring', 'geoarrow.multipoint'],
85
+ nesting: 1,
86
+ ...coordinateInfo
87
+ };
88
+ }
89
+
90
+ // A polygon or a multiline string are List<List<Coordinate>>
91
+ if (!(arrowField.type instanceof arrow.List)) {
92
+ return null;
93
+ }
94
+ arrowField = arrowField.type.children[0];
95
+
96
+ coordinateInfo = getCoordinateFieldInfo(arrowField);
97
+ if (coordinateInfo) {
98
+ return {
99
+ compatibleEncodings: ['geoarrow.polygon', 'geoarrow.multilinestring'],
100
+ nesting: 2,
101
+ ...coordinateInfo
102
+ };
103
+ }
104
+
105
+ // A multipolygons are List<List<List<Coordinate>>>
106
+ if (!(arrowField.type instanceof arrow.List)) {
107
+ return null;
108
+ }
109
+ arrowField = arrowField.type.children[0];
110
+
111
+ coordinateInfo = getCoordinateFieldInfo(arrowField);
112
+ if (coordinateInfo) {
113
+ return {
114
+ compatibleEncodings: ['geoarrow.multipolygon'],
115
+ nesting: 3,
116
+ ...coordinateInfo
117
+ };
118
+ }
119
+
120
+ return null;
121
+ }
122
+
123
+ /**
124
+ * @see https://geoarrow.org/format.html#memory-layouts
125
+ */
126
+ function getCoordinateFieldInfo(arrowField: arrow.Field): CoordinateFieldInfo | null {
127
+ // interleaved case
128
+ if (arrowField.type instanceof arrow.FixedSizeList) {
129
+ const dimension = arrowField.type.listSize;
130
+ if (dimension < 2 || dimension > 4) {
131
+ return null;
132
+ }
133
+
134
+ const child = arrowField.type.children[0];
135
+ // Spec currently only supports 64 bit coordinates
136
+ if (!(child.type instanceof arrow.Float)) {
137
+ return null;
138
+ }
139
+
140
+ return {
141
+ coordinates: 'interleaved',
142
+ dimension: dimension as 2 | 3 | 4,
143
+ valueType: 'double'
144
+ };
145
+ }
146
+
147
+ // separated case
148
+ if (arrowField.type instanceof arrow.Struct) {
149
+ const children = arrowField.type.children;
150
+
151
+ const dimension = children.length;
152
+ if (dimension < 2 || dimension > 4) {
153
+ return null;
154
+ }
155
+
156
+ // Spec currently only supports 64 bit coordinates
157
+ for (const child of children) {
158
+ if (!(child.type instanceof arrow.Float)) {
159
+ return null;
160
+ }
161
+ }
162
+
163
+ return {
164
+ coordinates: 'separated',
165
+ dimension: dimension as 2 | 3 | 4,
166
+ valueType: 'double'
167
+ };
168
+ }
169
+
170
+ // No other types are valid coordinates
171
+ return null;
172
+ }
package/src/index.ts ADDED
@@ -0,0 +1,57 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // MESH CATEGORY
6
+
7
+ export {getBoundingBoxFromArrowPositions} from './mesharrow/get-bounding-box';
8
+ export {getDeckBinaryDataFromArrowMesh} from './mesharrow/get-deck-binary-data';
9
+
10
+ // GIS CATEGORY - GEOARROW
11
+ export type {GeoArrowMetadata, GeoArrowEncoding} from './metadata/geoarrow-metadata';
12
+
13
+ export type {
14
+ GeoArrowWKB,
15
+ GeoArrowWKT,
16
+ GeoArrowCoordInterleaved,
17
+ GeoArrowCoordSeparated,
18
+ GeoArrowCoord,
19
+ GeoArrowPoint,
20
+ GeoArrowLineString,
21
+ GeoArrowPolygon,
22
+ GeoArrowMultiPoint,
23
+ GeoArrowMultiLineString,
24
+ GeoArrowMultiPolygon,
25
+ GeoArrowGeometry,
26
+ GeoArrowPointSeparated,
27
+ GeoArrowLineStringSeparated,
28
+ GeoArrowPolygonSeparated,
29
+ GeoArrowMultiPointSeparated,
30
+ GeoArrowMultiLineStringSeparated,
31
+ GeoArrowMultiPolygonSeparated,
32
+ GeoArrowGeometrySeparated
33
+ } from './geoarrow-types';
34
+
35
+ export {
36
+ isGeoArrowPoint,
37
+ isGeoArrowLineString,
38
+ isGeoArrowPolygon,
39
+ isGeoArrowMultiPoint,
40
+ isGeoArrowMultiLineString,
41
+ isGeoArrowMultiPolygon,
42
+ isGeoArrowGeometry
43
+ } from './geoarrow-functions';
44
+
45
+ // GEOARROW / GEOPARQUET METADATA
46
+ export {getGeometryColumnsFromSchema} from './metadata/geoarrow-metadata';
47
+
48
+ export type {GeoColumnMetadata} from './metadata/geoparquet-metadata';
49
+ export {
50
+ getGeoMetadata,
51
+ unpackGeoMetadata,
52
+ unpackJSONStringMetadata
53
+ } from './metadata/geoparquet-metadata';
54
+
55
+ export {getGeoArrowGeometryInfo} from './get-geoarrow-geometry-info';
56
+
57
+ export {updateBoundsFromGeoArrowSamples} from './get-arrow-bounds';
@@ -0,0 +1,62 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TypedArray} from '@math.gl/types';
6
+ import * as arrow from 'apache-arrow';
7
+ import {getDataTypeFromArray, deserializeArrowType} from '@loaders.gl/schema-utils';
8
+
9
+ export function isFixedSizeList(vector: arrow.Vector): vector is arrow.Vector<arrow.FixedSizeList> {
10
+ return vector.type instanceof arrow.FixedSizeList;
11
+ }
12
+
13
+ export function getFixedSizeListSize(vector: arrow.Vector): number {
14
+ return vector.type instanceof arrow.FixedSizeList ? vector.type.listSize : 1;
15
+ }
16
+
17
+ /** Get Arrow FixedSizeList vector from a typed array */
18
+ export function getFixedSizeListVector(
19
+ typedArray: TypedArray,
20
+ stride: number
21
+ ): arrow.Vector<arrow.FixedSizeList> {
22
+ const data = getFixedSizeListData(typedArray, stride);
23
+ return new arrow.Vector<arrow.FixedSizeList>([data]);
24
+ }
25
+
26
+ /** Get Arrow FixedSizeList vector from a typed array */
27
+ export function getFixedSizeListData(
28
+ typedArray: TypedArray,
29
+ stride: number
30
+ ): arrow.Data<arrow.FixedSizeList> {
31
+ const listType = getFixedSizeListType(typedArray, stride);
32
+ const nestedType = listType.children[0].type;
33
+ const buffers: Partial<Record<arrow.BufferType, any>> = {
34
+ // valueOffsets: undefined,
35
+ [arrow.BufferType.DATA]: typedArray // values
36
+ // nullBitmap: undefined,
37
+ // typeIds: undefined
38
+ };
39
+
40
+ // Note: The contiguous array of data is held by the nested "primitive type" column
41
+ const nestedData = new arrow.Data(nestedType, 0, typedArray.length, 0, buffers);
42
+
43
+ // Wrapped in a FixedSizeList column that provides a "strided" view of the data
44
+ const data = new arrow.Data<arrow.FixedSizeList>(
45
+ listType,
46
+ 0,
47
+ typedArray.length / stride,
48
+ 0,
49
+ undefined,
50
+ [nestedData]
51
+ );
52
+
53
+ return data;
54
+ }
55
+
56
+ /** Get Arrow FixedSizeList vector from a typed array */
57
+ export function getFixedSizeListType(typedArray: TypedArray, stride: number): arrow.FixedSizeList {
58
+ const {type} = getDataTypeFromArray(typedArray);
59
+ const arrowType = deserializeArrowType(type);
60
+ const listType = new arrow.FixedSizeList(stride, new arrow.Field('value', arrowType));
61
+ return listType;
62
+ }
@@ -0,0 +1,47 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TypedArray} from '@math.gl/types';
6
+ import * as arrow from 'apache-arrow';
7
+ import {getDataTypeFromArray, deserializeArrowType} from '@loaders.gl/schema-utils';
8
+
9
+ export function isListFixedSizeList(
10
+ vector: arrow.Vector
11
+ ): vector is arrow.Vector<arrow.FixedSizeList> {
12
+ return vector.type instanceof arrow.FixedSizeList;
13
+ }
14
+
15
+ export function getListFixedSizeListSize(vector: arrow.Vector): number {
16
+ return vector.type instanceof arrow.FixedSizeList ? vector.type.listSize : 1;
17
+ }
18
+
19
+ /** Get Arrow FixedSizeList vector from a typed array */
20
+ export function getListFixedSizeListVector(
21
+ indexes: Uint32Array,
22
+ typedArray: TypedArray,
23
+ stride: number
24
+ ): arrow.Vector<arrow.FixedSizeList> {
25
+ const data = getFixedSizeListData(typedArray, stride);
26
+ return new arrow.Vector<arrow.FixedSizeList>([data]);
27
+ }
28
+
29
+ /** Get Arrow FixedSizeList vector from a typed array */
30
+ export function getFixedSizeListData(
31
+ typedArray: TypedArray,
32
+ stride: number
33
+ ): arrow.Data<arrow.FixedSizeList> {
34
+ const listType = getFixedSizeListType(typedArray, stride);
35
+ const data = new arrow.Data<arrow.FixedSizeList>(listType, 0, typedArray.length / stride, 0, [
36
+ typedArray
37
+ ]);
38
+ return data;
39
+ }
40
+
41
+ /** Get Arrow FixedSizeList vector from a typed array */
42
+ export function getFixedSizeListType(typedArray: TypedArray, stride: number): arrow.FixedSizeList {
43
+ const {type} = getDataTypeFromArray(typedArray);
44
+ const arrowType = deserializeArrowType(type);
45
+ const listType = new arrow.FixedSizeList(stride, new arrow.Field('value', arrowType));
46
+ return listType;
47
+ }
@@ -0,0 +1,39 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import * as arrow from 'apache-arrow';
6
+
7
+ export type BoundingBox = [[number, number, number], [number, number, number]];
8
+
9
+ /** basic helper method to calculate a models upper and lower bounds */
10
+ export function getBoundingBoxFromArrowPositions(
11
+ column: arrow.Vector<arrow.FixedSizeList>
12
+ ): BoundingBox {
13
+ const mins: [number, number, number] = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
14
+ const maxs: [number, number, number] = [Number.MIN_VALUE, Number.MIN_VALUE, Number.MIN_VALUE];
15
+
16
+ const valueColumn = column.getChildAt(0)!;
17
+ for (const data of valueColumn.data) {
18
+ const pointSize = 3; // attributes.POSITION.size;
19
+ const pointData = data.buffers[arrow.BufferType.DATA];
20
+ const pointCount = pointData.length / pointSize;
21
+
22
+ for (let i = 0; i < pointCount; i += pointSize) {
23
+ const x = pointData[i];
24
+ const y = pointData[i + 1];
25
+ const z = pointData[i + 2];
26
+
27
+ if (x < mins[0]) mins[0] = x;
28
+ else if (x > maxs[0]) maxs[0] = x;
29
+
30
+ if (y < mins[1]) mins[1] = y;
31
+ else if (y > maxs[1]) maxs[1] = y;
32
+
33
+ if (z < mins[2]) mins[2] = z;
34
+ else if (z > maxs[2]) maxs[2] = z;
35
+ }
36
+ }
37
+
38
+ return [mins, maxs];
39
+ }
@@ -0,0 +1,43 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TypedArray} from '@math.gl/types';
6
+ import {getSizeAndValueFromMeshArrowVector} from './mesh-accessors';
7
+ import * as arrow from 'apache-arrow';
8
+
9
+ /** */
10
+ export type DeckBinaryData = {
11
+ length: number;
12
+ attributes: Record<
13
+ string,
14
+ {
15
+ value: TypedArray;
16
+ size: number;
17
+ }
18
+ >;
19
+ };
20
+
21
+ /** */
22
+ export function getDeckBinaryDataFromArrowMesh(table: arrow.Table): DeckBinaryData {
23
+ const positionVector = table.getChild('POSITION');
24
+ if (!positionVector) {
25
+ throw new Error('POSITION attribute not found');
26
+ }
27
+
28
+ const getPosition = getSizeAndValueFromMeshArrowVector(positionVector);
29
+
30
+ const deckAttributes: DeckBinaryData['attributes'] = {
31
+ getPosition
32
+ };
33
+
34
+ const colorVector = table.getChild('COLOR_0');
35
+ if (colorVector) {
36
+ deckAttributes.getColor = getSizeAndValueFromMeshArrowVector(colorVector);
37
+ }
38
+ // Check PointCloudLayer docs for other supported props?
39
+ return {
40
+ length: table.numRows,
41
+ attributes: deckAttributes
42
+ };
43
+ }
@@ -0,0 +1,27 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TypedArray} from '@math.gl/types';
6
+ import {getFixedSizeListSize} from './arrow-fixed-size-list-utils';
7
+ import * as arrow from 'apache-arrow';
8
+
9
+ export function getSizeAndValueFromMeshArrowVector(attributeVector: arrow.Vector): {
10
+ size: number;
11
+ value: TypedArray;
12
+ } {
13
+ const size = getFixedSizeListSize(attributeVector);
14
+ const typedArrays = getTypedArraysFromMeshArrowVector(attributeVector);
15
+ return {size, value: typedArrays[0]};
16
+ }
17
+
18
+ export function getTypedArraysFromMeshArrowVector(attributeVector: arrow.Vector): TypedArray[] {
19
+ const typedArrays: TypedArray[] = [];
20
+ for (const attributeData of attributeVector.data) {
21
+ const valueData = attributeData?.children[0];
22
+ const typedArray = valueData.values;
23
+ typedArrays.push(typedArray);
24
+ }
25
+
26
+ return typedArrays;
27
+ }
@@ -0,0 +1,102 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Metadata, SchemaWithMetadata, getMetadataValue} from './metadata-utils';
6
+
7
+ export type GeoArrowEncoding =
8
+ | 'geoarrow.multipolygon'
9
+ | 'geoarrow.polygon'
10
+ | 'geoarrow.multilinestring'
11
+ | 'geoarrow.linestring'
12
+ | 'geoarrow.multipoint'
13
+ | 'geoarrow.point'
14
+ | 'geoarrow.wkb'
15
+ | 'geoarrow.wkt';
16
+
17
+ /** Array containing all encodings */
18
+ const GEOARROW_ENCODINGS = [
19
+ 'geoarrow.multipolygon',
20
+ 'geoarrow.polygon',
21
+ 'geoarrow.multilinestring',
22
+ 'geoarrow.linestring',
23
+ 'geoarrow.multipoint',
24
+ 'geoarrow.point',
25
+ 'geoarrow.wkb',
26
+ 'geoarrow.wkt'
27
+ ] as const satisfies GeoArrowEncoding[];
28
+
29
+ const GEOARROW_ENCODING = 'ARROW:extension:name';
30
+ const GEOARROW_METADATA = 'ARROW:extension:metadata';
31
+
32
+ /**
33
+ * Geospatial metadata for one column, extracted from Apache Arrow metadata
34
+ * @see https://github.com/geoarrow/geoarrow/blob/main/extension-types.md
35
+ */
36
+ export type GeoArrowMetadata = {
37
+ /** Encoding of geometry in this column */
38
+ encoding?: GeoArrowEncoding;
39
+ /** CRS in [PROJJSON](https://proj.org/specifications/projjson.html). Omitted if producer has no information about CRS */
40
+ crs?: Record<string, unknown>;
41
+ /** Edges are either spherical or omitted */
42
+ edges?: 'spherical';
43
+ [key: string]: unknown;
44
+ };
45
+
46
+ /**
47
+ * get geometry columns from arrow table
48
+ */
49
+ export function getGeometryColumnsFromSchema(
50
+ schema: SchemaWithMetadata
51
+ ): Record<string, GeoArrowMetadata> {
52
+ const geometryColumns: Record<string, GeoArrowMetadata> = {};
53
+ for (const field of schema.fields || []) {
54
+ const metadata = getGeometryMetadataForField(field?.metadata || {});
55
+ if (metadata) {
56
+ geometryColumns[field.name] = metadata;
57
+ }
58
+ }
59
+ return geometryColumns;
60
+ }
61
+ /**
62
+ * Extracts GeoArrow metadata from a field
63
+ * @param field
64
+ * @returns
65
+ * @see https://github.com/geoarrow/geoarrow/blob/d2f56704414d9ae71e8a5170a8671343ed15eefe/extension-types.md
66
+ */
67
+ export function getGeometryMetadataForField(fieldMetadata: Metadata): GeoArrowMetadata | null {
68
+ let metadata: GeoArrowMetadata | null = null;
69
+
70
+ // Check for GeoArrow column encoding
71
+ let geoEncoding = getMetadataValue(fieldMetadata, GEOARROW_ENCODING);
72
+ if (geoEncoding) {
73
+ geoEncoding = geoEncoding.toLowerCase();
74
+ // at time of testing, ogr2ogr uses WKB/WKT for encoding.
75
+ if (geoEncoding === 'wkb') {
76
+ geoEncoding = 'geoarrow.wkb';
77
+ }
78
+ if (geoEncoding === 'wkt') {
79
+ geoEncoding = 'geoarrow.wkt';
80
+ }
81
+ if (!GEOARROW_ENCODINGS.includes(geoEncoding as GeoArrowEncoding)) {
82
+ // eslint-disable-next-line no-console
83
+ console.warn(`Invalid GeoArrow encoding: ${geoEncoding}`);
84
+ } else {
85
+ metadata ||= {} as GeoArrowMetadata;
86
+ metadata.encoding = geoEncoding as GeoArrowEncoding;
87
+ }
88
+ }
89
+
90
+ // Check for GeoArrow metadata
91
+ const columnMetadata = getMetadataValue(fieldMetadata, GEOARROW_METADATA);
92
+ if (columnMetadata) {
93
+ try {
94
+ metadata = JSON.parse(columnMetadata);
95
+ } catch (error) {
96
+ // eslint-disable-next-line no-console
97
+ console.warn('Failed to parse GeoArrow metadata', error);
98
+ }
99
+ }
100
+
101
+ return metadata || null;
102
+ }
@@ -0,0 +1,71 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /* eslint-disable camelcase */
6
+
7
+ /**
8
+ * Geoparquet JSON schema for geo metadata
9
+ * @see https://github.com/geoarrow/geoarrow/blob/main/metadata.md
10
+ * @see https://github.com/opengeospatial/geoparquet/blob/main/format-specs/geoparquet.md
11
+ */
12
+ export const GEOPARQUET_METADATA_JSON_SCHEMA = {
13
+ $schema: 'http://json-schema.org/draft-07/schema#',
14
+ title: 'GeoParquet',
15
+ description: 'Parquet metadata included in the geo field.',
16
+ type: 'object',
17
+ required: ['version', 'primary_column', 'columns'],
18
+ properties: {
19
+ version: {type: 'string', const: '1.0.0-beta.1'},
20
+ primary_column: {type: 'string', minLength: 1},
21
+ columns: {
22
+ type: 'object',
23
+ minProperties: 1,
24
+ patternProperties: {
25
+ '.+': {
26
+ type: 'object',
27
+ required: ['encoding', 'geometry_types'],
28
+ properties: {
29
+ encoding: {type: 'string', const: 'WKB'},
30
+ geometry_types: {
31
+ type: 'array',
32
+ uniqueItems: true,
33
+ items: {
34
+ type: 'string',
35
+ pattern: '^(GeometryCollection|(Multi)?(Point|LineString|Polygon))( Z)?$'
36
+ }
37
+ },
38
+ crs: {
39
+ oneOf: [
40
+ {
41
+ $ref: 'https://proj.org/schemas/v0.5/projjson.schema.json'
42
+ },
43
+ {type: 'null'}
44
+ ]
45
+ },
46
+ edges: {type: 'string', enum: ['planar', 'spherical']},
47
+ orientation: {type: 'string', const: 'counterclockwise'},
48
+ bbox: {
49
+ type: 'array',
50
+ items: {type: 'number'},
51
+ oneOf: [
52
+ {
53
+ description: '2D bbox consisting of (xmin, ymin, xmax, ymax)',
54
+ minItems: 4,
55
+ maxItems: 4
56
+ },
57
+ {
58
+ description: '3D bbox consisting of (xmin, ymin, zmin, xmax, ymax, zmax)',
59
+ minItems: 6,
60
+ maxItems: 6
61
+ }
62
+ ]
63
+ },
64
+ epoch: {type: 'number'}
65
+ }
66
+ }
67
+ },
68
+ additionalProperties: false
69
+ }
70
+ }
71
+ };