@math.gl/geoarrow 5.0.0-alpha.2 → 5.0.0-alpha.3
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.
- package/README.md +45 -15
- package/dist/builder-entry.cjs +561 -0
- package/dist/builder-entry.cjs.map +6 -0
- package/dist/builder-entry.d.ts +4 -0
- package/dist/builder-entry.d.ts.map +1 -0
- package/dist/builder-entry.js +5 -0
- package/dist/builder-entry.js.map +1 -0
- package/dist/builder.d.ts +12 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +112 -10
- package/dist/builder.js.map +1 -1
- package/dist/codecs.d.ts.map +1 -1
- package/dist/codecs.js +205 -7
- package/dist/codecs.js.map +1 -1
- package/dist/index.cjs +904 -120
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernels.d.ts +8 -3
- package/dist/kernels.d.ts.map +1 -1
- package/dist/kernels.js +610 -107
- package/dist/kernels.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +28 -5
- package/dist/layout.js.map +1 -1
- package/dist/tessellation-entry.cjs +427 -0
- package/dist/tessellation-entry.cjs.map +6 -0
- package/dist/tessellation-entry.d.ts +4 -0
- package/dist/tessellation-entry.d.ts.map +1 -0
- package/dist/tessellation-entry.js +5 -0
- package/dist/tessellation-entry.js.map +1 -0
- package/dist/types.d.ts +37 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wkb-entry.cjs +1005 -0
- package/dist/wkb-entry.cjs.map +6 -0
- package/dist/wkb-entry.d.ts +3 -0
- package/dist/wkb-entry.d.ts.map +1 -0
- package/dist/wkb-entry.js +6 -0
- package/dist/wkb-entry.js.map +1 -0
- package/dist/worker.cjs +4 -0
- package/dist/worker.cjs.map +1 -1
- package/package.json +21 -6
- package/src/builder-entry.ts +18 -0
- package/src/builder.ts +133 -19
- package/src/codecs.ts +251 -9
- package/src/index.ts +1 -0
- package/src/kernels.ts +811 -133
- package/src/layout.ts +38 -13
- package/src/tessellation-entry.ts +7 -0
- package/src/types.ts +23 -4
- package/src/wkb-entry.ts +11 -0
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# @math.gl/geoarrow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Arrow-independent columnar geometry descriptors and synchronous buffer algorithms for
|
|
4
|
+
GeoArrow-compatible memory layouts.
|
|
4
5
|
|
|
5
6
|
`@math.gl/geoarrow` works directly over borrowed typed arrays. It deliberately does not require an
|
|
6
7
|
Arrow runtime: a loader, dataframe, database client, or application can adapt its buffers to the
|
|
7
|
-
small descriptor ABI and use the same validation, conversion,
|
|
8
|
-
|
|
8
|
+
small descriptor ABI and use the same validation, conversion, and coordinate algorithms. Optional
|
|
9
|
+
format and mesh capabilities are isolated behind subpaths so consumers only bundle what they use.
|
|
9
10
|
|
|
10
11
|
## Install
|
|
11
12
|
|
|
12
13
|
```bash
|
|
13
14
|
npm install @math.gl/geoarrow
|
|
15
|
+
# Only needed when using the /wkb subpath directly.
|
|
16
|
+
npm install @math.gl/wkb
|
|
14
17
|
```
|
|
15
18
|
|
|
16
19
|
## Why descriptors?
|
|
@@ -34,11 +37,11 @@ identity as a reliable zero-copy signal.
|
|
|
34
37
|
|
|
35
38
|
```typescript
|
|
36
39
|
import {
|
|
37
|
-
GeoArrowBuilder,
|
|
38
40
|
getGeoArrowBounds,
|
|
39
41
|
getGeoArrowVertexCount,
|
|
40
42
|
mapGeoArrowCoordinates
|
|
41
43
|
} from '@math.gl/geoarrow';
|
|
44
|
+
import {GeoArrowBuilder} from '@math.gl/geoarrow/builder';
|
|
42
45
|
|
|
43
46
|
const column = GeoArrowBuilder.build(
|
|
44
47
|
[
|
|
@@ -173,11 +176,13 @@ The following operations traverse descriptors directly and do not create per-row
|
|
|
173
176
|
- `validateGeoArrowColumn`
|
|
174
177
|
- `getGeoArrowVertexCount`
|
|
175
178
|
- `getGeoArrowBounds`
|
|
179
|
+
- `getGeoArrowRowBounds`
|
|
176
180
|
- `visitGeoArrowCoordinates`
|
|
177
181
|
- `getGeoArrowTransferList`
|
|
178
182
|
|
|
179
|
-
Allocating transforms such as coordinate mapping, physical conversion, winding normalization
|
|
180
|
-
|
|
183
|
+
Allocating transforms such as coordinate mapping, physical conversion, and winding normalization
|
|
184
|
+
return new descriptors. Their inputs remain unchanged. Serialized codecs are isolated in the
|
|
185
|
+
`/wkb` subpath.
|
|
181
186
|
|
|
182
187
|
## Conversion and winding
|
|
183
188
|
|
|
@@ -207,7 +212,7 @@ import {
|
|
|
207
212
|
encodeGeoArrowWKB,
|
|
208
213
|
decodeGeoArrowWKT,
|
|
209
214
|
encodeGeoArrowWKT
|
|
210
|
-
} from '@math.gl/geoarrow';
|
|
215
|
+
} from '@math.gl/geoarrow/wkb';
|
|
211
216
|
|
|
212
217
|
const wkb = encodeGeoArrowWKB(polygons);
|
|
213
218
|
const decoded = decodeGeoArrowWKB(wkb);
|
|
@@ -221,19 +226,20 @@ families, dimension tokens, both MultiPoint spellings, and empties. Decoding nor
|
|
|
221
226
|
serialized coordinates to the column's declared semantic dimension.
|
|
222
227
|
|
|
223
228
|
Parsing or formatting one geometry is intentionally provided by the dependency-free
|
|
224
|
-
`@math.gl/wkb` package:
|
|
229
|
+
`@math.gl/wkb` package. The GeoArrow `/wkb` bridge consumes its visitors and two-pass builder:
|
|
225
230
|
|
|
226
231
|
```typescript
|
|
227
232
|
import {parseWKB, writeWKB, parseWKT, formatWKT} from '@math.gl/wkb';
|
|
228
233
|
```
|
|
229
234
|
|
|
230
|
-
|
|
231
|
-
|
|
235
|
+
The descriptor and buffer-algorithm implementation does not require Apache Arrow. The `/wkb`
|
|
236
|
+
subpath (and the legacy root codec re-exports) uses `@math.gl/wkb`; install it when using those
|
|
237
|
+
functions.
|
|
232
238
|
|
|
233
239
|
## Polygon tessellation
|
|
234
240
|
|
|
235
241
|
```typescript
|
|
236
|
-
import {tessellateGeoArrowPolygons} from '@math.gl/geoarrow';
|
|
242
|
+
import {tessellateGeoArrowPolygons} from '@math.gl/geoarrow/tessellation';
|
|
237
243
|
|
|
238
244
|
const mesh = tessellateGeoArrowPolygons(polygons, {
|
|
239
245
|
positionSize: 3,
|
|
@@ -280,6 +286,29 @@ worker.postMessage(payload.column, {transfer: payload.transferList});
|
|
|
280
286
|
explicit `postMessage` call transfers ownership. Shared buffers are omitted because they are not
|
|
281
287
|
transferable.
|
|
282
288
|
|
|
289
|
+
## Loaders.gl integration
|
|
290
|
+
|
|
291
|
+
The intended loaders.gl architecture keeps Apache Arrow at the boundary:
|
|
292
|
+
|
|
293
|
+
```text
|
|
294
|
+
Arrow Data / Vector / Table
|
|
295
|
+
│ loaders.gl adapter
|
|
296
|
+
▼
|
|
297
|
+
GeoArrowColumn descriptors ──► @math.gl/geoarrow buffer algorithms
|
|
298
|
+
│
|
|
299
|
+
└── loaders.gl Arrow field + extension metadata
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The adapter should borrow Arrow buffers and preserve chunking, offsets, validity, dense-union
|
|
303
|
+
dispatch, dimensions, layouts, CRS, and extension metadata. It should not call Arrow scalar
|
|
304
|
+
accessors in conversion paths. Keep GeoJSON conversion, adaptive target policy, Arrow schema
|
|
305
|
+
construction, and row-shaped compatibility values in loaders.gl.
|
|
306
|
+
|
|
307
|
+
Use the optional `/wkb` bridge only for serialized columns and `/builder` when emitting native
|
|
308
|
+
descriptors from a feature stream. For event-built MultiPolygons, call `beginPolygon()` before each
|
|
309
|
+
part; omitting it retains the compatibility behavior of treating all rings as one polygon. This
|
|
310
|
+
keeps the common Arrow-to-native path independent of text and binary codec code.
|
|
311
|
+
|
|
283
312
|
## Adapting another columnar runtime
|
|
284
313
|
|
|
285
314
|
Keep runtime-specific objects at the boundary. Read their physical buffers and construct a
|
|
@@ -299,11 +328,12 @@ the producer runtime.
|
|
|
299
328
|
|
|
300
329
|
- Descriptors: `GeoArrowColumn`, `GeoArrowArray`, all physical array descriptor types
|
|
301
330
|
- Layout: `inspectGeoArrowColumn`, `validateGeoArrowColumn`, slicing and traversal
|
|
302
|
-
-
|
|
303
|
-
|
|
304
|
-
-
|
|
331
|
+
- Buffer algorithms: count, bounds, row bounds, map, interleave, convert, rewind, union
|
|
332
|
+
normalization, resource limits
|
|
333
|
+
- Construction: `@math.gl/geoarrow/builder`
|
|
334
|
+
- Column codecs: `@math.gl/geoarrow/wkb` (individual parsing/formatting is provided by
|
|
305
335
|
`@math.gl/wkb`)
|
|
306
|
-
- Meshes: `
|
|
336
|
+
- Meshes: `@math.gl/geoarrow/tessellation`
|
|
307
337
|
- Transfer: `getGeoArrowTransferList`, plus `@math.gl/geoarrow/worker`
|
|
308
338
|
|
|
309
339
|
See the math.gl documentation for the full [physical-layout guide](../../docs/modules/geoarrow/physical-layouts.md),
|
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// dist/builder-entry.js
|
|
20
|
+
var builder_entry_exports = {};
|
|
21
|
+
__export(builder_entry_exports, {
|
|
22
|
+
GeoArrowBuilder: () => GeoArrowBuilder,
|
|
23
|
+
allocateGeoArrowBuilderTarget: () => allocateGeoArrowBuilderTarget,
|
|
24
|
+
makeGeoArrowColumnFromGeometryRows: () => makeGeoArrowColumnFromGeometryRows
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(builder_entry_exports);
|
|
27
|
+
|
|
28
|
+
// dist/types.js
|
|
29
|
+
function getGeoArrowDimensionSize(dimension) {
|
|
30
|
+
switch (dimension) {
|
|
31
|
+
case "xy":
|
|
32
|
+
return 2;
|
|
33
|
+
case "xyz":
|
|
34
|
+
case "xym":
|
|
35
|
+
return 3;
|
|
36
|
+
case "xyzm":
|
|
37
|
+
return 4;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function getGeoArrowGeometryType(encoding) {
|
|
41
|
+
switch (encoding) {
|
|
42
|
+
case "geoarrow.point":
|
|
43
|
+
return "Point";
|
|
44
|
+
case "geoarrow.linestring":
|
|
45
|
+
return "LineString";
|
|
46
|
+
case "geoarrow.polygon":
|
|
47
|
+
return "Polygon";
|
|
48
|
+
case "geoarrow.multipoint":
|
|
49
|
+
return "MultiPoint";
|
|
50
|
+
case "geoarrow.multilinestring":
|
|
51
|
+
return "MultiLineString";
|
|
52
|
+
case "geoarrow.multipolygon":
|
|
53
|
+
return "MultiPolygon";
|
|
54
|
+
case "geoarrow.geometrycollection":
|
|
55
|
+
return "GeometryCollection";
|
|
56
|
+
default:
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function getGeoArrowEncodingForGeometry(type) {
|
|
61
|
+
return `geoarrow.${type.toLowerCase()}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// dist/builder.js
|
|
65
|
+
var GeoArrowBuilder = class _GeoArrowBuilder {
|
|
66
|
+
constructor(options) {
|
|
67
|
+
this.length = 0;
|
|
68
|
+
this.nullCount = 0;
|
|
69
|
+
this.coordinateCount = 0;
|
|
70
|
+
this.partCount = 0;
|
|
71
|
+
this.ringCount = 0;
|
|
72
|
+
this.eventStack = [];
|
|
73
|
+
this.mode = options.mode;
|
|
74
|
+
this.encoding = options.encoding;
|
|
75
|
+
this.dimension = options.dimension || "xy";
|
|
76
|
+
this.coordinateLayout = options.coordinateLayout || "interleaved";
|
|
77
|
+
this.offsetType = options.offsetType || "int32";
|
|
78
|
+
this.coordinateType = options.coordinateType || "float64";
|
|
79
|
+
this.target = options.mode === "write" ? options.target : void 0;
|
|
80
|
+
if (this.target)
|
|
81
|
+
this.initializeTargetOffsets(this.target);
|
|
82
|
+
}
|
|
83
|
+
/** Appends one geometry row or null. */
|
|
84
|
+
append(geometry) {
|
|
85
|
+
var _a, _b, _c, _d, _e, _f;
|
|
86
|
+
const rowIndex = this.length++;
|
|
87
|
+
if (!geometry) {
|
|
88
|
+
this.nullCount++;
|
|
89
|
+
this.appendNull(rowIndex);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
const expectedType = getGeoArrowGeometryType(this.encoding);
|
|
93
|
+
if (geometry.type !== expectedType) {
|
|
94
|
+
throw new Error(`GeoArrowBuilder for ${this.encoding} cannot append ${geometry.type}`);
|
|
95
|
+
}
|
|
96
|
+
if (geometry.type === "GeometryCollection") {
|
|
97
|
+
throw new Error("GeoArrowBuilder only accepts concrete geometry families");
|
|
98
|
+
}
|
|
99
|
+
if (this.target)
|
|
100
|
+
setValidityBit(this.target.validity, rowIndex);
|
|
101
|
+
const depth = getBuilderDepth(this.encoding);
|
|
102
|
+
const coordinates = geometry.coordinates;
|
|
103
|
+
if (depth === 0) {
|
|
104
|
+
this.writeCoordinateValues(coordinates);
|
|
105
|
+
} else if (depth === 1) {
|
|
106
|
+
this.writeCoordinateList(coordinates);
|
|
107
|
+
this.writeOffset((_a = this.target) == null ? void 0 : _a.geometryOffsets, rowIndex + 1, this.coordinateCount);
|
|
108
|
+
} else if (depth === 2) {
|
|
109
|
+
for (const part of coordinates) {
|
|
110
|
+
this.writeCoordinateList(part);
|
|
111
|
+
this.partCount++;
|
|
112
|
+
this.writeOffset((_b = this.target) == null ? void 0 : _b.partOffsets, this.partCount, this.coordinateCount);
|
|
113
|
+
}
|
|
114
|
+
this.writeOffset((_c = this.target) == null ? void 0 : _c.geometryOffsets, rowIndex + 1, this.partCount);
|
|
115
|
+
} else {
|
|
116
|
+
for (const polygon of coordinates) {
|
|
117
|
+
for (const ring of polygon) {
|
|
118
|
+
this.writeCoordinateList(ring);
|
|
119
|
+
this.ringCount++;
|
|
120
|
+
this.writeOffset((_d = this.target) == null ? void 0 : _d.ringOffsets, this.ringCount, this.coordinateCount);
|
|
121
|
+
}
|
|
122
|
+
this.partCount++;
|
|
123
|
+
this.writeOffset((_e = this.target) == null ? void 0 : _e.partOffsets, this.partCount, this.ringCount);
|
|
124
|
+
}
|
|
125
|
+
this.writeOffset((_f = this.target) == null ? void 0 : _f.geometryOffsets, rowIndex + 1, this.partCount);
|
|
126
|
+
}
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
/** Returns current exact allocation counts. */
|
|
130
|
+
getMeasurement() {
|
|
131
|
+
const depth = getBuilderDepth(this.encoding);
|
|
132
|
+
return {
|
|
133
|
+
length: this.length,
|
|
134
|
+
nullCount: this.nullCount,
|
|
135
|
+
coordinateCount: this.coordinateCount,
|
|
136
|
+
geometryOffsetCount: depth >= 1 ? this.length + 1 : 0,
|
|
137
|
+
partOffsetCount: depth >= 2 ? this.partCount + 1 : 0,
|
|
138
|
+
ringOffsetCount: depth >= 3 ? this.ringCount + 1 : 0
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** Allocates a write target from the current measure pass. */
|
|
142
|
+
allocateTarget() {
|
|
143
|
+
if (this.mode !== "measure")
|
|
144
|
+
throw new Error("Only a measure builder can allocate a target");
|
|
145
|
+
return allocateGeoArrowBuilderTarget(this.getMeasurement(), {
|
|
146
|
+
encoding: this.encoding,
|
|
147
|
+
dimension: this.dimension,
|
|
148
|
+
coordinateLayout: this.coordinateLayout,
|
|
149
|
+
offsetType: this.offsetType,
|
|
150
|
+
coordinateType: this.coordinateType
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** Finishes a write pass and returns a one-chunk borrowed column. */
|
|
154
|
+
finish() {
|
|
155
|
+
if (!this.target)
|
|
156
|
+
throw new Error("A measure builder has no finished column");
|
|
157
|
+
const measurement = this.getMeasurement();
|
|
158
|
+
assertTargetCapacity(this.target, measurement, getGeoArrowDimensionSize(this.dimension));
|
|
159
|
+
const coordinates = makeCoordinateArray(this.target.coordinates, measurement.coordinateCount, this.dimension, this.coordinateLayout);
|
|
160
|
+
const depth = getBuilderDepth(this.encoding);
|
|
161
|
+
let chunk = coordinates;
|
|
162
|
+
if (depth >= 3) {
|
|
163
|
+
chunk = {
|
|
164
|
+
kind: "list",
|
|
165
|
+
length: this.ringCount,
|
|
166
|
+
offsets: this.target.ringOffsets,
|
|
167
|
+
child: chunk
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (depth >= 2) {
|
|
171
|
+
chunk = {
|
|
172
|
+
kind: "list",
|
|
173
|
+
length: this.partCount,
|
|
174
|
+
offsets: this.target.partOffsets,
|
|
175
|
+
child: chunk
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (depth >= 1) {
|
|
179
|
+
chunk = {
|
|
180
|
+
kind: "list",
|
|
181
|
+
length: this.length,
|
|
182
|
+
offsets: this.target.geometryOffsets,
|
|
183
|
+
child: chunk,
|
|
184
|
+
validity: { values: this.target.validity }
|
|
185
|
+
};
|
|
186
|
+
} else {
|
|
187
|
+
chunk = { ...chunk, validity: { values: this.target.validity } };
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
encoding: this.encoding,
|
|
191
|
+
dimension: this.dimension,
|
|
192
|
+
coordinateLayout: this.coordinateLayout,
|
|
193
|
+
chunks: [chunk]
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/** Builds a homogeneous column using an internal measure/write pair. */
|
|
197
|
+
static build(rows, options) {
|
|
198
|
+
const measure = new _GeoArrowBuilder({ ...options, mode: "measure" });
|
|
199
|
+
for (const row of rows)
|
|
200
|
+
measure.append(row);
|
|
201
|
+
const write = new _GeoArrowBuilder({
|
|
202
|
+
...options,
|
|
203
|
+
mode: "write",
|
|
204
|
+
target: measure.allocateTarget()
|
|
205
|
+
});
|
|
206
|
+
for (const row of rows)
|
|
207
|
+
write.append(row);
|
|
208
|
+
return write.finish();
|
|
209
|
+
}
|
|
210
|
+
appendNull(rowIndex) {
|
|
211
|
+
var _a;
|
|
212
|
+
const depth = getBuilderDepth(this.encoding);
|
|
213
|
+
if (depth === 0) {
|
|
214
|
+
this.writeCoordinateValues(new Array(getGeoArrowDimensionSize(this.dimension)).fill(0));
|
|
215
|
+
} else {
|
|
216
|
+
this.writeOffset((_a = this.target) == null ? void 0 : _a.geometryOffsets, rowIndex + 1, depth === 1 ? this.coordinateCount : this.partCount);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
writeCoordinateList(coordinates) {
|
|
220
|
+
for (const coordinate of coordinates)
|
|
221
|
+
this.writeCoordinateValues(coordinate);
|
|
222
|
+
}
|
|
223
|
+
writeCoordinateValues(coordinate) {
|
|
224
|
+
const size = getGeoArrowDimensionSize(this.dimension);
|
|
225
|
+
if (coordinate.length !== size) {
|
|
226
|
+
throw new Error(`Expected ${size} coordinate values for ${this.dimension}`);
|
|
227
|
+
}
|
|
228
|
+
if (this.target)
|
|
229
|
+
writeCoordinate(this.target.coordinates, this.coordinateCount, coordinate, this.dimension);
|
|
230
|
+
this.coordinateCount++;
|
|
231
|
+
}
|
|
232
|
+
/** Begins an event-driven geometry. Events are accepted by both measure and write builders. */
|
|
233
|
+
beginGeometry(type, dimension = this.dimension, _count) {
|
|
234
|
+
this.eventStack.push({ type, dimension, rings: [], polygons: [], children: [] });
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
/** Begins a polygon part inside an event-built MultiPolygon. */
|
|
238
|
+
beginPolygon() {
|
|
239
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
240
|
+
if (!state || state.type !== "MultiPolygon") {
|
|
241
|
+
throw new Error("beginPolygon must follow beginGeometry('MultiPolygon')");
|
|
242
|
+
}
|
|
243
|
+
state.currentPolygon = [];
|
|
244
|
+
state.polygons.push(state.currentPolygon);
|
|
245
|
+
state.currentRing = void 0;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
/** Begins a ring/part in the current event geometry. */
|
|
249
|
+
beginRing(_count) {
|
|
250
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
251
|
+
if (!state)
|
|
252
|
+
throw new Error("beginRing must follow beginGeometry");
|
|
253
|
+
state.currentRing = [];
|
|
254
|
+
if (state.type === "MultiPolygon") {
|
|
255
|
+
if (!state.currentPolygon)
|
|
256
|
+
this.beginPolygon();
|
|
257
|
+
state.currentPolygon.push(state.currentRing);
|
|
258
|
+
} else {
|
|
259
|
+
state.rings.push(state.currentRing);
|
|
260
|
+
}
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
/** Writes one coordinate into the current event ring or point. */
|
|
264
|
+
writeCoordinate(x, y, z, m) {
|
|
265
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
266
|
+
if (!state)
|
|
267
|
+
throw new Error("writeCoordinate must follow beginGeometry");
|
|
268
|
+
const coordinate = Array.isArray(x) ? [...x] : [x, y, ...z === void 0 ? [] : [z], ...m === void 0 ? [] : [m]];
|
|
269
|
+
const size = getGeoArrowDimensionSize(state.dimension);
|
|
270
|
+
if (coordinate.length !== size)
|
|
271
|
+
throw new Error(`Expected ${size} coordinate values for ${state.dimension}`);
|
|
272
|
+
if (state.type === "Point") {
|
|
273
|
+
state.rings = [[coordinate]];
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
276
|
+
if (!state.currentRing)
|
|
277
|
+
this.beginRing();
|
|
278
|
+
state.currentRing.push(coordinate);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
/** Ends the current event geometry and appends it to the builder/parent. */
|
|
282
|
+
endGeometry() {
|
|
283
|
+
var _a;
|
|
284
|
+
const state = this.eventStack.pop();
|
|
285
|
+
if (!state)
|
|
286
|
+
throw new Error("endGeometry without beginGeometry");
|
|
287
|
+
const coordinates = state.rings;
|
|
288
|
+
let geometry;
|
|
289
|
+
switch (state.type) {
|
|
290
|
+
case "Point":
|
|
291
|
+
geometry = { type: "Point", coordinates: ((_a = coordinates[0]) == null ? void 0 : _a[0]) || [] };
|
|
292
|
+
break;
|
|
293
|
+
case "LineString":
|
|
294
|
+
geometry = { type: "LineString", coordinates: coordinates[0] || [] };
|
|
295
|
+
break;
|
|
296
|
+
case "MultiPoint":
|
|
297
|
+
geometry = { type: "MultiPoint", coordinates: coordinates.flat() };
|
|
298
|
+
break;
|
|
299
|
+
case "Polygon":
|
|
300
|
+
geometry = { type: "Polygon", coordinates };
|
|
301
|
+
break;
|
|
302
|
+
case "MultiLineString":
|
|
303
|
+
geometry = { type: "MultiLineString", coordinates };
|
|
304
|
+
break;
|
|
305
|
+
case "MultiPolygon":
|
|
306
|
+
geometry = {
|
|
307
|
+
type: "MultiPolygon",
|
|
308
|
+
coordinates: state.polygons.length ? state.polygons : [coordinates]
|
|
309
|
+
};
|
|
310
|
+
break;
|
|
311
|
+
case "GeometryCollection":
|
|
312
|
+
geometry = { type: "GeometryCollection", geometries: state.children };
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
const parent = this.eventStack[this.eventStack.length - 1];
|
|
316
|
+
if ((parent == null ? void 0 : parent.type) === "GeometryCollection")
|
|
317
|
+
parent.children.push(geometry);
|
|
318
|
+
else
|
|
319
|
+
this.append(geometry);
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
322
|
+
writeOffset(target, index, value) {
|
|
323
|
+
if (!target)
|
|
324
|
+
return;
|
|
325
|
+
if (target instanceof BigInt64Array)
|
|
326
|
+
target[index] = BigInt(value);
|
|
327
|
+
else
|
|
328
|
+
target[index] = value;
|
|
329
|
+
}
|
|
330
|
+
initializeTargetOffsets(target) {
|
|
331
|
+
this.writeOffset(target.geometryOffsets, 0, 0);
|
|
332
|
+
this.writeOffset(target.partOffsets, 0, 0);
|
|
333
|
+
this.writeOffset(target.ringOffsets, 0, 0);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
function allocateGeoArrowBuilderTarget(measurement, options) {
|
|
337
|
+
const dimension = options.dimension || "xy";
|
|
338
|
+
const size = getGeoArrowDimensionSize(dimension);
|
|
339
|
+
const FloatArray = options.coordinateType === "float32" ? Float32Array : Float64Array;
|
|
340
|
+
const coordinateLayout = options.coordinateLayout || "interleaved";
|
|
341
|
+
const coordinates = coordinateLayout === "interleaved" ? new FloatArray(measurement.coordinateCount * size) : makeSeparatedCoordinateTarget(FloatArray, measurement.coordinateCount, dimension);
|
|
342
|
+
const OffsetArray = options.offsetType === "int64" ? BigInt64Array : Int32Array;
|
|
343
|
+
return {
|
|
344
|
+
validity: new Uint8Array(Math.ceil(measurement.length / 8)),
|
|
345
|
+
coordinates,
|
|
346
|
+
geometryOffsets: measurement.geometryOffsetCount ? new OffsetArray(measurement.geometryOffsetCount) : void 0,
|
|
347
|
+
partOffsets: measurement.partOffsetCount ? new OffsetArray(measurement.partOffsetCount) : void 0,
|
|
348
|
+
ringOffsets: measurement.ringOffsetCount ? new OffsetArray(measurement.ringOffsetCount) : void 0
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function makeGeoArrowColumnFromGeometryRows(rows, options = {}) {
|
|
352
|
+
const geometryTypes = [...new Set(rows.filter(Boolean).map((row) => row.type))];
|
|
353
|
+
const dimension = options.dimension || inferRowsDimension(rows);
|
|
354
|
+
if (options.encoding === "geoarrow.geometry") {
|
|
355
|
+
return {
|
|
356
|
+
encoding: "geoarrow.geometry",
|
|
357
|
+
dimension,
|
|
358
|
+
coordinateLayout: options.coordinateLayout || "interleaved",
|
|
359
|
+
chunks: [makeDenseUnionArray(rows, options, dimension)]
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (geometryTypes.length === 0) {
|
|
363
|
+
return GeoArrowBuilder.build(rows, { ...options, dimension, encoding: "geoarrow.point" });
|
|
364
|
+
}
|
|
365
|
+
if (geometryTypes.length === 1 && geometryTypes[0] !== "GeometryCollection") {
|
|
366
|
+
return GeoArrowBuilder.build(rows, {
|
|
367
|
+
...options,
|
|
368
|
+
dimension,
|
|
369
|
+
encoding: getGeoArrowEncodingForGeometry(geometryTypes[0])
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
if (geometryTypes.length === 1 && geometryTypes[0] === "GeometryCollection") {
|
|
373
|
+
return {
|
|
374
|
+
encoding: "geoarrow.geometrycollection",
|
|
375
|
+
dimension,
|
|
376
|
+
coordinateLayout: options.coordinateLayout || "interleaved",
|
|
377
|
+
chunks: [makeGeometryCollectionArray(rows, options, dimension)]
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
encoding: "geoarrow.geometry",
|
|
382
|
+
dimension,
|
|
383
|
+
coordinateLayout: options.coordinateLayout || "interleaved",
|
|
384
|
+
chunks: [makeDenseUnionArray(rows, options, dimension)]
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function makeDenseUnionArray(rows, options, dimension) {
|
|
388
|
+
const nonNullTypes = [...new Set(rows.filter(Boolean).map((row) => row.type))];
|
|
389
|
+
const fallbackType = nonNullTypes[0] || "Point";
|
|
390
|
+
const childRows = /* @__PURE__ */ new Map();
|
|
391
|
+
for (const type of nonNullTypes.length ? nonNullTypes : [fallbackType])
|
|
392
|
+
childRows.set(type, []);
|
|
393
|
+
const typeIds = new Int8Array(rows.length);
|
|
394
|
+
const valueOffsets = new Int32Array(rows.length);
|
|
395
|
+
const validity = new Uint8Array(Math.ceil(rows.length / 8));
|
|
396
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
397
|
+
const geometry = rows[rowIndex];
|
|
398
|
+
const type = (geometry == null ? void 0 : geometry.type) || fallbackType;
|
|
399
|
+
const values = childRows.get(type) || [];
|
|
400
|
+
typeIds[rowIndex] = getGeometryTypeId(type, dimension);
|
|
401
|
+
valueOffsets[rowIndex] = values.length;
|
|
402
|
+
if (geometry) {
|
|
403
|
+
values.push(geometry);
|
|
404
|
+
childRows.set(type, values);
|
|
405
|
+
setValidityBit(validity, rowIndex);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const children = [...childRows.entries()].sort(([left], [right]) => getGeometryTypeId(left, dimension) - getGeometryTypeId(right, dimension)).map(([type, values]) => {
|
|
409
|
+
const data = type === "GeometryCollection" ? makeGeometryCollectionArray(values, options, dimension) : GeoArrowBuilder.build(values, {
|
|
410
|
+
...options,
|
|
411
|
+
dimension,
|
|
412
|
+
encoding: getGeoArrowEncodingForGeometry(type)
|
|
413
|
+
}).chunks[0];
|
|
414
|
+
return {
|
|
415
|
+
name: type,
|
|
416
|
+
typeId: getGeometryTypeId(type, dimension),
|
|
417
|
+
encoding: getGeoArrowEncodingForGeometry(type),
|
|
418
|
+
dimension,
|
|
419
|
+
coordinateLayout: options.coordinateLayout || "interleaved",
|
|
420
|
+
data
|
|
421
|
+
};
|
|
422
|
+
});
|
|
423
|
+
return {
|
|
424
|
+
kind: "dense-union",
|
|
425
|
+
length: rows.length,
|
|
426
|
+
typeIds,
|
|
427
|
+
valueOffsets,
|
|
428
|
+
children,
|
|
429
|
+
validity: { values: validity }
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function makeGeometryCollectionArray(rows, options, dimension) {
|
|
433
|
+
const offsets = new Int32Array(rows.length + 1);
|
|
434
|
+
const validity = new Uint8Array(Math.ceil(rows.length / 8));
|
|
435
|
+
const flattened = [];
|
|
436
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
437
|
+
const row = rows[rowIndex];
|
|
438
|
+
if ((row == null ? void 0 : row.type) === "GeometryCollection") {
|
|
439
|
+
flattened.push(...row.geometries);
|
|
440
|
+
setValidityBit(validity, rowIndex);
|
|
441
|
+
}
|
|
442
|
+
offsets[rowIndex + 1] = flattened.length;
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
kind: "list",
|
|
446
|
+
length: rows.length,
|
|
447
|
+
offsets,
|
|
448
|
+
child: makeDenseUnionArray(flattened, options, dimension),
|
|
449
|
+
validity: { values: validity }
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function makeCoordinateArray(coordinates, coordinateCount, dimension, layout) {
|
|
453
|
+
const size = getGeoArrowDimensionSize(dimension);
|
|
454
|
+
if (layout === "interleaved") {
|
|
455
|
+
const values = coordinates;
|
|
456
|
+
return {
|
|
457
|
+
kind: "fixed-size-list",
|
|
458
|
+
length: coordinateCount,
|
|
459
|
+
size,
|
|
460
|
+
child: { kind: "primitive", length: coordinateCount * size, values }
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const separated = coordinates;
|
|
464
|
+
const children = {
|
|
465
|
+
x: { kind: "primitive", length: coordinateCount, values: separated.x },
|
|
466
|
+
y: { kind: "primitive", length: coordinateCount, values: separated.y }
|
|
467
|
+
};
|
|
468
|
+
if (separated.z) {
|
|
469
|
+
children["z"] = { kind: "primitive", length: coordinateCount, values: separated.z };
|
|
470
|
+
}
|
|
471
|
+
if (separated.m) {
|
|
472
|
+
children["m"] = { kind: "primitive", length: coordinateCount, values: separated.m };
|
|
473
|
+
}
|
|
474
|
+
return { kind: "struct", length: coordinateCount, children };
|
|
475
|
+
}
|
|
476
|
+
function makeSeparatedCoordinateTarget(FloatArray, count, dimension) {
|
|
477
|
+
return {
|
|
478
|
+
x: new FloatArray(count),
|
|
479
|
+
y: new FloatArray(count),
|
|
480
|
+
z: dimension === "xyz" || dimension === "xyzm" ? new FloatArray(count) : void 0,
|
|
481
|
+
m: dimension === "xym" || dimension === "xyzm" ? new FloatArray(count) : void 0
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function writeCoordinate(target, coordinateIndex, coordinate, dimension) {
|
|
485
|
+
if (target instanceof Float32Array || target instanceof Float64Array) {
|
|
486
|
+
target.set(coordinate, coordinateIndex * coordinate.length);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
target.x[coordinateIndex] = coordinate[0];
|
|
490
|
+
target.y[coordinateIndex] = coordinate[1];
|
|
491
|
+
if (dimension === "xyz")
|
|
492
|
+
target.z[coordinateIndex] = coordinate[2];
|
|
493
|
+
else if (dimension === "xym")
|
|
494
|
+
target.m[coordinateIndex] = coordinate[2];
|
|
495
|
+
else if (dimension === "xyzm") {
|
|
496
|
+
target.z[coordinateIndex] = coordinate[2];
|
|
497
|
+
target.m[coordinateIndex] = coordinate[3];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
function setValidityBit(validity, index) {
|
|
501
|
+
validity[index >> 3] |= 1 << (index & 7);
|
|
502
|
+
}
|
|
503
|
+
function getBuilderDepth(encoding) {
|
|
504
|
+
switch (encoding) {
|
|
505
|
+
case "geoarrow.point":
|
|
506
|
+
return 0;
|
|
507
|
+
case "geoarrow.linestring":
|
|
508
|
+
case "geoarrow.multipoint":
|
|
509
|
+
return 1;
|
|
510
|
+
case "geoarrow.polygon":
|
|
511
|
+
case "geoarrow.multilinestring":
|
|
512
|
+
return 2;
|
|
513
|
+
case "geoarrow.multipolygon":
|
|
514
|
+
return 3;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function getGeometryTypeId(type, dimension = "xy") {
|
|
518
|
+
const family = [
|
|
519
|
+
"Point",
|
|
520
|
+
"LineString",
|
|
521
|
+
"Polygon",
|
|
522
|
+
"MultiPoint",
|
|
523
|
+
"MultiLineString",
|
|
524
|
+
"MultiPolygon",
|
|
525
|
+
"GeometryCollection"
|
|
526
|
+
].indexOf(type);
|
|
527
|
+
const dimensionIndex = ["xy", "xyz", "xym", "xyzm"].indexOf(dimension);
|
|
528
|
+
return family < 0 || dimensionIndex < 0 ? 1 : family * 4 + dimensionIndex + 1;
|
|
529
|
+
}
|
|
530
|
+
function inferRowsDimension(rows) {
|
|
531
|
+
let size = 2;
|
|
532
|
+
const visit = (value) => {
|
|
533
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
534
|
+
return;
|
|
535
|
+
if (typeof value[0] === "number")
|
|
536
|
+
size = Math.max(size, value.length);
|
|
537
|
+
else
|
|
538
|
+
for (const child of value)
|
|
539
|
+
visit(child);
|
|
540
|
+
};
|
|
541
|
+
const visitGeometry = (geometry) => {
|
|
542
|
+
if (geometry.type === "GeometryCollection") {
|
|
543
|
+
for (const child of geometry.geometries)
|
|
544
|
+
visitGeometry(child);
|
|
545
|
+
} else {
|
|
546
|
+
visit(geometry.coordinates);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
for (const row of rows) {
|
|
550
|
+
if (row)
|
|
551
|
+
visitGeometry(row);
|
|
552
|
+
}
|
|
553
|
+
return size >= 4 ? "xyzm" : size === 3 ? "xyz" : "xy";
|
|
554
|
+
}
|
|
555
|
+
function assertTargetCapacity(target, measurement, size) {
|
|
556
|
+
const coordinateLength = target.coordinates instanceof Float32Array || target.coordinates instanceof Float64Array ? target.coordinates.length / size : target.coordinates.x.length;
|
|
557
|
+
if (coordinateLength < measurement.coordinateCount || target.validity.length * 8 < measurement.length) {
|
|
558
|
+
throw new Error("GeoArrowBuilder target is smaller than its measured output");
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
//# sourceMappingURL=builder-entry.cjs.map
|