@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/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
getGeoArrowDimensionSize: () => getGeoArrowDimensionSize,
|
|
32
32
|
getGeoArrowEncodingForGeometry: () => getGeoArrowEncodingForGeometry,
|
|
33
33
|
getGeoArrowGeometryType: () => getGeoArrowGeometryType,
|
|
34
|
+
getGeoArrowRowBounds: () => getGeoArrowRowBounds,
|
|
34
35
|
getGeoArrowRowCount: () => getGeoArrowRowCount,
|
|
35
36
|
getGeoArrowTransferList: () => getGeoArrowTransferList,
|
|
36
37
|
getGeoArrowVertexCount: () => getGeoArrowVertexCount,
|
|
@@ -285,7 +286,7 @@ function visitUnionRowCoordinates(union, rowIndex, sourceRowIndex, visitor) {
|
|
|
285
286
|
const child = union.children.find((candidate) => candidate.typeId === typeId);
|
|
286
287
|
if (!child)
|
|
287
288
|
return;
|
|
288
|
-
const encoding = getEncodingFromChildName(child.name);
|
|
289
|
+
const encoding = child.encoding || getEncodingFromChildName(child.name);
|
|
289
290
|
if (encoding === "geoarrow.geometrycollection" && child.data.kind === "list") {
|
|
290
291
|
const [first, last] = getListRange(child.data, valueOffset);
|
|
291
292
|
if (child.data.child.kind === "dense-union") {
|
|
@@ -363,7 +364,7 @@ function materializeUnionRow(union, rowIndex) {
|
|
|
363
364
|
const child = union.children.find((candidate) => candidate.typeId === typeId);
|
|
364
365
|
if (!child || valueOffset < 0 || valueOffset >= child.data.length)
|
|
365
366
|
return null;
|
|
366
|
-
return materializeGeometryRow(child.data, valueOffset, getEncodingFromChildName(child.name));
|
|
367
|
+
return materializeGeometryRow(child.data, valueOffset, child.encoding || getEncodingFromChildName(child.name));
|
|
367
368
|
}
|
|
368
369
|
function getEncodingFromChildName(name) {
|
|
369
370
|
const normalized = name.replace(/[^a-z]/gi, "").toLowerCase();
|
|
@@ -509,7 +510,18 @@ function validateArray(array, path, issues) {
|
|
|
509
510
|
break;
|
|
510
511
|
}
|
|
511
512
|
case "serialized": {
|
|
512
|
-
|
|
513
|
+
if (array.views) {
|
|
514
|
+
const requiredWords = ((array.offset || 0) + array.length) * 4;
|
|
515
|
+
if (requiredWords > array.views.length) {
|
|
516
|
+
issues.push({
|
|
517
|
+
code: "invalid-length",
|
|
518
|
+
path,
|
|
519
|
+
message: "Serialized view records are too short."
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
validateOffsets(array.offsets, array.offset || 0, array.length, array.values.length, array.offsetBase, path, issues);
|
|
524
|
+
}
|
|
513
525
|
break;
|
|
514
526
|
}
|
|
515
527
|
}
|
|
@@ -627,12 +639,17 @@ function validateUnionLayouts(union, column, path, issues) {
|
|
|
627
639
|
for (const child of union.children) {
|
|
628
640
|
let encoding;
|
|
629
641
|
try {
|
|
630
|
-
encoding = getEncodingFromChildName(child.name);
|
|
642
|
+
encoding = child.encoding || getEncodingFromChildName(child.name);
|
|
631
643
|
} catch (error) {
|
|
632
644
|
addInvalidLayout(`${path}.${child.name}`, error.message, issues);
|
|
633
645
|
continue;
|
|
634
646
|
}
|
|
635
|
-
|
|
647
|
+
const childColumn = child.dimension || child.coordinateLayout ? {
|
|
648
|
+
...column,
|
|
649
|
+
dimension: child.dimension || column.dimension,
|
|
650
|
+
coordinateLayout: child.coordinateLayout || column.coordinateLayout
|
|
651
|
+
} : column;
|
|
652
|
+
validateGeometryLayout(child.data, encoding, childColumn, `${path}.${child.name}`, issues);
|
|
636
653
|
}
|
|
637
654
|
}
|
|
638
655
|
function validateCoordinateLayout(array, column, path, issues) {
|
|
@@ -704,6 +721,10 @@ function collectArrayBuffers(array, buffers) {
|
|
|
704
721
|
case "serialized":
|
|
705
722
|
addBuffer(array.offsets.buffer, buffers);
|
|
706
723
|
addBuffer(array.values.buffer, buffers);
|
|
724
|
+
if (array.views)
|
|
725
|
+
addBuffer(array.views.buffer, buffers);
|
|
726
|
+
for (const data of array.dataBuffers || [])
|
|
727
|
+
addBuffer(data.buffer, buffers);
|
|
707
728
|
break;
|
|
708
729
|
}
|
|
709
730
|
}
|
|
@@ -724,6 +745,7 @@ var GeoArrowBuilder = class _GeoArrowBuilder {
|
|
|
724
745
|
this.coordinateCount = 0;
|
|
725
746
|
this.partCount = 0;
|
|
726
747
|
this.ringCount = 0;
|
|
748
|
+
this.eventStack = [];
|
|
727
749
|
this.mode = options.mode;
|
|
728
750
|
this.encoding = options.encoding;
|
|
729
751
|
this.dimension = options.dimension || "xy";
|
|
@@ -755,7 +777,7 @@ var GeoArrowBuilder = class _GeoArrowBuilder {
|
|
|
755
777
|
const depth = getBuilderDepth(this.encoding);
|
|
756
778
|
const coordinates = geometry.coordinates;
|
|
757
779
|
if (depth === 0) {
|
|
758
|
-
this.
|
|
780
|
+
this.writeCoordinateValues(coordinates);
|
|
759
781
|
} else if (depth === 1) {
|
|
760
782
|
this.writeCoordinateList(coordinates);
|
|
761
783
|
this.writeOffset((_a = this.target) == null ? void 0 : _a.geometryOffsets, rowIndex + 1, this.coordinateCount);
|
|
@@ -865,16 +887,16 @@ var GeoArrowBuilder = class _GeoArrowBuilder {
|
|
|
865
887
|
var _a;
|
|
866
888
|
const depth = getBuilderDepth(this.encoding);
|
|
867
889
|
if (depth === 0) {
|
|
868
|
-
this.
|
|
890
|
+
this.writeCoordinateValues(new Array(getGeoArrowDimensionSize(this.dimension)).fill(0));
|
|
869
891
|
} else {
|
|
870
892
|
this.writeOffset((_a = this.target) == null ? void 0 : _a.geometryOffsets, rowIndex + 1, depth === 1 ? this.coordinateCount : this.partCount);
|
|
871
893
|
}
|
|
872
894
|
}
|
|
873
895
|
writeCoordinateList(coordinates) {
|
|
874
896
|
for (const coordinate of coordinates)
|
|
875
|
-
this.
|
|
897
|
+
this.writeCoordinateValues(coordinate);
|
|
876
898
|
}
|
|
877
|
-
|
|
899
|
+
writeCoordinateValues(coordinate) {
|
|
878
900
|
const size = getGeoArrowDimensionSize(this.dimension);
|
|
879
901
|
if (coordinate.length !== size) {
|
|
880
902
|
throw new Error(`Expected ${size} coordinate values for ${this.dimension}`);
|
|
@@ -883,6 +905,96 @@ var GeoArrowBuilder = class _GeoArrowBuilder {
|
|
|
883
905
|
writeCoordinate(this.target.coordinates, this.coordinateCount, coordinate, this.dimension);
|
|
884
906
|
this.coordinateCount++;
|
|
885
907
|
}
|
|
908
|
+
/** Begins an event-driven geometry. Events are accepted by both measure and write builders. */
|
|
909
|
+
beginGeometry(type, dimension = this.dimension, _count) {
|
|
910
|
+
this.eventStack.push({ type, dimension, rings: [], polygons: [], children: [] });
|
|
911
|
+
return this;
|
|
912
|
+
}
|
|
913
|
+
/** Begins a polygon part inside an event-built MultiPolygon. */
|
|
914
|
+
beginPolygon() {
|
|
915
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
916
|
+
if (!state || state.type !== "MultiPolygon") {
|
|
917
|
+
throw new Error("beginPolygon must follow beginGeometry('MultiPolygon')");
|
|
918
|
+
}
|
|
919
|
+
state.currentPolygon = [];
|
|
920
|
+
state.polygons.push(state.currentPolygon);
|
|
921
|
+
state.currentRing = void 0;
|
|
922
|
+
return this;
|
|
923
|
+
}
|
|
924
|
+
/** Begins a ring/part in the current event geometry. */
|
|
925
|
+
beginRing(_count) {
|
|
926
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
927
|
+
if (!state)
|
|
928
|
+
throw new Error("beginRing must follow beginGeometry");
|
|
929
|
+
state.currentRing = [];
|
|
930
|
+
if (state.type === "MultiPolygon") {
|
|
931
|
+
if (!state.currentPolygon)
|
|
932
|
+
this.beginPolygon();
|
|
933
|
+
state.currentPolygon.push(state.currentRing);
|
|
934
|
+
} else {
|
|
935
|
+
state.rings.push(state.currentRing);
|
|
936
|
+
}
|
|
937
|
+
return this;
|
|
938
|
+
}
|
|
939
|
+
/** Writes one coordinate into the current event ring or point. */
|
|
940
|
+
writeCoordinate(x, y, z, m) {
|
|
941
|
+
const state = this.eventStack[this.eventStack.length - 1];
|
|
942
|
+
if (!state)
|
|
943
|
+
throw new Error("writeCoordinate must follow beginGeometry");
|
|
944
|
+
const coordinate = Array.isArray(x) ? [...x] : [x, y, ...z === void 0 ? [] : [z], ...m === void 0 ? [] : [m]];
|
|
945
|
+
const size = getGeoArrowDimensionSize(state.dimension);
|
|
946
|
+
if (coordinate.length !== size)
|
|
947
|
+
throw new Error(`Expected ${size} coordinate values for ${state.dimension}`);
|
|
948
|
+
if (state.type === "Point") {
|
|
949
|
+
state.rings = [[coordinate]];
|
|
950
|
+
return this;
|
|
951
|
+
}
|
|
952
|
+
if (!state.currentRing)
|
|
953
|
+
this.beginRing();
|
|
954
|
+
state.currentRing.push(coordinate);
|
|
955
|
+
return this;
|
|
956
|
+
}
|
|
957
|
+
/** Ends the current event geometry and appends it to the builder/parent. */
|
|
958
|
+
endGeometry() {
|
|
959
|
+
var _a;
|
|
960
|
+
const state = this.eventStack.pop();
|
|
961
|
+
if (!state)
|
|
962
|
+
throw new Error("endGeometry without beginGeometry");
|
|
963
|
+
const coordinates = state.rings;
|
|
964
|
+
let geometry;
|
|
965
|
+
switch (state.type) {
|
|
966
|
+
case "Point":
|
|
967
|
+
geometry = { type: "Point", coordinates: ((_a = coordinates[0]) == null ? void 0 : _a[0]) || [] };
|
|
968
|
+
break;
|
|
969
|
+
case "LineString":
|
|
970
|
+
geometry = { type: "LineString", coordinates: coordinates[0] || [] };
|
|
971
|
+
break;
|
|
972
|
+
case "MultiPoint":
|
|
973
|
+
geometry = { type: "MultiPoint", coordinates: coordinates.flat() };
|
|
974
|
+
break;
|
|
975
|
+
case "Polygon":
|
|
976
|
+
geometry = { type: "Polygon", coordinates };
|
|
977
|
+
break;
|
|
978
|
+
case "MultiLineString":
|
|
979
|
+
geometry = { type: "MultiLineString", coordinates };
|
|
980
|
+
break;
|
|
981
|
+
case "MultiPolygon":
|
|
982
|
+
geometry = {
|
|
983
|
+
type: "MultiPolygon",
|
|
984
|
+
coordinates: state.polygons.length ? state.polygons : [coordinates]
|
|
985
|
+
};
|
|
986
|
+
break;
|
|
987
|
+
case "GeometryCollection":
|
|
988
|
+
geometry = { type: "GeometryCollection", geometries: state.children };
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
const parent = this.eventStack[this.eventStack.length - 1];
|
|
992
|
+
if ((parent == null ? void 0 : parent.type) === "GeometryCollection")
|
|
993
|
+
parent.children.push(geometry);
|
|
994
|
+
else
|
|
995
|
+
this.append(geometry);
|
|
996
|
+
return this;
|
|
997
|
+
}
|
|
886
998
|
writeOffset(target, index, value) {
|
|
887
999
|
if (!target)
|
|
888
1000
|
return;
|
|
@@ -961,7 +1073,7 @@ function makeDenseUnionArray(rows, options, dimension) {
|
|
|
961
1073
|
const geometry = rows[rowIndex];
|
|
962
1074
|
const type = (geometry == null ? void 0 : geometry.type) || fallbackType;
|
|
963
1075
|
const values = childRows.get(type) || [];
|
|
964
|
-
typeIds[rowIndex] = getGeometryTypeId(type);
|
|
1076
|
+
typeIds[rowIndex] = getGeometryTypeId(type, dimension);
|
|
965
1077
|
valueOffsets[rowIndex] = values.length;
|
|
966
1078
|
if (geometry) {
|
|
967
1079
|
values.push(geometry);
|
|
@@ -969,13 +1081,20 @@ function makeDenseUnionArray(rows, options, dimension) {
|
|
|
969
1081
|
setValidityBit(validity, rowIndex);
|
|
970
1082
|
}
|
|
971
1083
|
}
|
|
972
|
-
const children = [...childRows.entries()].sort(([left], [right]) => getGeometryTypeId(left) - getGeometryTypeId(right)).map(([type, values]) => {
|
|
1084
|
+
const children = [...childRows.entries()].sort(([left], [right]) => getGeometryTypeId(left, dimension) - getGeometryTypeId(right, dimension)).map(([type, values]) => {
|
|
973
1085
|
const data = type === "GeometryCollection" ? makeGeometryCollectionArray(values, options, dimension) : GeoArrowBuilder.build(values, {
|
|
974
1086
|
...options,
|
|
975
1087
|
dimension,
|
|
976
1088
|
encoding: getGeoArrowEncodingForGeometry(type)
|
|
977
1089
|
}).chunks[0];
|
|
978
|
-
return {
|
|
1090
|
+
return {
|
|
1091
|
+
name: type,
|
|
1092
|
+
typeId: getGeometryTypeId(type, dimension),
|
|
1093
|
+
encoding: getGeoArrowEncodingForGeometry(type),
|
|
1094
|
+
dimension,
|
|
1095
|
+
coordinateLayout: options.coordinateLayout || "interleaved",
|
|
1096
|
+
data
|
|
1097
|
+
};
|
|
979
1098
|
});
|
|
980
1099
|
return {
|
|
981
1100
|
kind: "dense-union",
|
|
@@ -1071,8 +1190,8 @@ function getBuilderDepth(encoding) {
|
|
|
1071
1190
|
return 3;
|
|
1072
1191
|
}
|
|
1073
1192
|
}
|
|
1074
|
-
function getGeometryTypeId(type) {
|
|
1075
|
-
|
|
1193
|
+
function getGeometryTypeId(type, dimension = "xy") {
|
|
1194
|
+
const family = [
|
|
1076
1195
|
"Point",
|
|
1077
1196
|
"LineString",
|
|
1078
1197
|
"Polygon",
|
|
@@ -1080,7 +1199,9 @@ function getGeometryTypeId(type) {
|
|
|
1080
1199
|
"MultiLineString",
|
|
1081
1200
|
"MultiPolygon",
|
|
1082
1201
|
"GeometryCollection"
|
|
1083
|
-
].indexOf(type)
|
|
1202
|
+
].indexOf(type);
|
|
1203
|
+
const dimensionIndex = ["xy", "xyz", "xym", "xyzm"].indexOf(dimension);
|
|
1204
|
+
return family < 0 || dimensionIndex < 0 ? 1 : family * 4 + dimensionIndex + 1;
|
|
1084
1205
|
}
|
|
1085
1206
|
function inferRowsDimension(rows) {
|
|
1086
1207
|
let size = 2;
|
|
@@ -1135,6 +1256,46 @@ function getGeoArrowBounds(column) {
|
|
|
1135
1256
|
});
|
|
1136
1257
|
return Number.isFinite(minimumX) ? [minimumX, minimumY, maximumX, maximumY] : null;
|
|
1137
1258
|
}
|
|
1259
|
+
function getGeoArrowRowBounds(column) {
|
|
1260
|
+
const rowCount = getGeoArrowRowCount(column);
|
|
1261
|
+
if (column.encoding === "geoarrow.box") {
|
|
1262
|
+
const result = [];
|
|
1263
|
+
for (const chunk of column.chunks) {
|
|
1264
|
+
for (let rowIndex = 0; rowIndex < chunk.length; rowIndex++) {
|
|
1265
|
+
if (chunk.kind !== "struct" || !isGeoArrowValueValid(chunk.validity, rowIndex)) {
|
|
1266
|
+
result.push(null);
|
|
1267
|
+
continue;
|
|
1268
|
+
}
|
|
1269
|
+
const index = (chunk.offset || 0) + rowIndex;
|
|
1270
|
+
const xmin = readPrimitiveNumber(chunk.children["xmin"], index);
|
|
1271
|
+
const ymin = readPrimitiveNumber(chunk.children["ymin"], index);
|
|
1272
|
+
const xmax = readPrimitiveNumber(chunk.children["xmax"], index);
|
|
1273
|
+
const ymax = readPrimitiveNumber(chunk.children["ymax"], index);
|
|
1274
|
+
result.push([xmin, ymin, xmax, ymax].every(Number.isFinite) ? [xmin, ymin, xmax, ymax] : null);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
return result;
|
|
1278
|
+
}
|
|
1279
|
+
const minimumX = new Float64Array(rowCount).fill(Number.POSITIVE_INFINITY);
|
|
1280
|
+
const minimumY = new Float64Array(rowCount).fill(Number.POSITIVE_INFINITY);
|
|
1281
|
+
const maximumX = new Float64Array(rowCount).fill(Number.NEGATIVE_INFINITY);
|
|
1282
|
+
const maximumY = new Float64Array(rowCount).fill(Number.NEGATIVE_INFINITY);
|
|
1283
|
+
visitGeoArrowCoordinates(column, (coordinate, sourceRowIndex) => {
|
|
1284
|
+
const [x, y] = coordinate;
|
|
1285
|
+
if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
1286
|
+
minimumX[sourceRowIndex] = Math.min(minimumX[sourceRowIndex], x);
|
|
1287
|
+
minimumY[sourceRowIndex] = Math.min(minimumY[sourceRowIndex], y);
|
|
1288
|
+
maximumX[sourceRowIndex] = Math.max(maximumX[sourceRowIndex], x);
|
|
1289
|
+
maximumY[sourceRowIndex] = Math.max(maximumY[sourceRowIndex], y);
|
|
1290
|
+
}
|
|
1291
|
+
return coordinate;
|
|
1292
|
+
});
|
|
1293
|
+
const bounds = [];
|
|
1294
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
1295
|
+
bounds.push(Number.isFinite(minimumX[rowIndex]) ? [minimumX[rowIndex], minimumY[rowIndex], maximumX[rowIndex], maximumY[rowIndex]] : null);
|
|
1296
|
+
}
|
|
1297
|
+
return bounds;
|
|
1298
|
+
}
|
|
1138
1299
|
function getGeoArrowBoxBounds(column) {
|
|
1139
1300
|
let minimumX = Number.POSITIVE_INFINITY;
|
|
1140
1301
|
let minimumY = Number.POSITIVE_INFINITY;
|
|
@@ -1175,20 +1336,20 @@ function readPrimitiveNumber(array, index) {
|
|
|
1175
1336
|
const valueIndex = (array.offset || 0) + index * (array.stride || 1);
|
|
1176
1337
|
return Number(array.values[valueIndex]);
|
|
1177
1338
|
}
|
|
1178
|
-
function mapGeoArrowCoordinates(column, mapper, options = {}) {
|
|
1339
|
+
function mapGeoArrowCoordinates(column, mapper, options = {}, sourceDimension) {
|
|
1179
1340
|
assertGeoArrowResourceLimits(column, options.limits);
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1341
|
+
if (column.encoding === "geoarrow.wkb" || column.encoding === "geoarrow.wkt") {
|
|
1342
|
+
throw new Error("Coordinate mapping requires native GeoArrow storage");
|
|
1343
|
+
}
|
|
1344
|
+
const dimension = options.dimension || column.dimension;
|
|
1345
|
+
const layout = options.coordinateLayout || column.coordinateLayout || "interleaved";
|
|
1346
|
+
let rowOffset = 0;
|
|
1347
|
+
const chunks = column.chunks.map((chunk) => {
|
|
1348
|
+
const mapped = mapArrayCoordinates(chunk, column.encoding, rowOffset, dimension, layout, mapper, options.coordinateType || "preserve", options.dimension !== void 0, options.coordinateLayout !== void 0, sourceDimension);
|
|
1349
|
+
rowOffset += chunk.length;
|
|
1185
1350
|
return mapped;
|
|
1186
1351
|
});
|
|
1187
|
-
|
|
1188
|
-
dimension: options.dimension || column.dimension,
|
|
1189
|
-
coordinateLayout: options.coordinateLayout || column.coordinateLayout || "interleaved"
|
|
1190
|
-
});
|
|
1191
|
-
return copyColumnMetadata(column, result);
|
|
1352
|
+
return { ...column, dimension, coordinateLayout: layout, chunks };
|
|
1192
1353
|
}
|
|
1193
1354
|
function mapGeoArrowCoordinatesInto(target, source, mapper, options = {}) {
|
|
1194
1355
|
const mapped = mapGeoArrowCoordinates(source, mapper, {
|
|
@@ -1233,45 +1394,56 @@ function normalizeGeoArrowUnion(column) {
|
|
|
1233
1394
|
return changed ? { ...column, chunks } : column;
|
|
1234
1395
|
}
|
|
1235
1396
|
function convertGeoArrowColumn(column, options = {}) {
|
|
1236
|
-
const encoding = options.encoding || column.encoding;
|
|
1397
|
+
const encoding = options.encoding === "native" || !options.encoding ? column.encoding : options.encoding;
|
|
1237
1398
|
const dimension = options.dimension || column.dimension;
|
|
1238
|
-
const coordinateLayout = options.coordinateLayout || column.coordinateLayout;
|
|
1239
|
-
|
|
1399
|
+
const coordinateLayout = options.coordinateLayout === "preserve" || !options.coordinateLayout ? column.coordinateLayout : options.coordinateLayout;
|
|
1400
|
+
const requestedOffsetType = options.offsetType || "preserve";
|
|
1401
|
+
const currentOffsetType = getColumnOffsetType(column);
|
|
1402
|
+
if (encoding === column.encoding && dimension === column.dimension && coordinateLayout === column.coordinateLayout && (requestedOffsetType === "preserve" || requestedOffsetType === currentOffsetType) && (!options.coordinateType || options.coordinateType === "preserve")) {
|
|
1240
1403
|
return column;
|
|
1241
1404
|
}
|
|
1242
1405
|
if (encoding === "geoarrow.wkb" || encoding === "geoarrow.wkt") {
|
|
1243
1406
|
throw new Error("Use encodeGeoArrowWKB or encodeGeoArrowWKT for serialized output");
|
|
1244
1407
|
}
|
|
1245
1408
|
assertGeoArrowResourceLimits(column, options.limits);
|
|
1246
|
-
const
|
|
1247
|
-
const result = makeGeoArrowColumnFromGeometryRows(rows, {
|
|
1248
|
-
encoding: encoding === "geoarrow.geometry" ? encoding : void 0,
|
|
1409
|
+
const mapped = mapGeoArrowCoordinates(column, (coordinate) => coordinate, {
|
|
1249
1410
|
dimension,
|
|
1250
|
-
coordinateLayout: coordinateLayout ||
|
|
1411
|
+
coordinateLayout: coordinateLayout || void 0,
|
|
1412
|
+
coordinateType: options.coordinateType,
|
|
1413
|
+
limits: options.limits
|
|
1414
|
+
}, column.dimension);
|
|
1415
|
+
const offsetConverted = requestedOffsetType === "preserve" ? mapped : {
|
|
1416
|
+
...mapped,
|
|
1417
|
+
chunks: mapped.chunks.map((chunk) => convertArrayOffsets(chunk, requestedOffsetType))
|
|
1418
|
+
};
|
|
1419
|
+
if (encoding === column.encoding)
|
|
1420
|
+
return offsetConverted;
|
|
1421
|
+
if (encoding === "geoarrow.geometry")
|
|
1422
|
+
return promoteToDenseUnion(offsetConverted);
|
|
1423
|
+
if (column.encoding === "geoarrow.geometry")
|
|
1424
|
+
return demoteDenseUnion(offsetConverted, encoding);
|
|
1425
|
+
throw new Error(`Rows cannot be represented as ${encoding}`);
|
|
1426
|
+
}
|
|
1427
|
+
function resizeCoordinate(coordinate, sourceDimension, targetDimension) {
|
|
1428
|
+
const sourceNames = getDimensionNames(sourceDimension);
|
|
1429
|
+
return getDimensionNames(targetDimension).map((name) => {
|
|
1430
|
+
const sourceIndex = sourceNames.indexOf(name);
|
|
1431
|
+
return sourceIndex >= 0 ? coordinate[sourceIndex] ?? 0 : 0;
|
|
1251
1432
|
});
|
|
1252
|
-
if (result.encoding !== encoding && encoding !== "geoarrow.geometry") {
|
|
1253
|
-
throw new Error(`Rows cannot be represented as ${encoding}`);
|
|
1254
|
-
}
|
|
1255
|
-
return copyColumnMetadata(column, result);
|
|
1256
1433
|
}
|
|
1257
1434
|
function rewindGeoArrow(column, options = {}) {
|
|
1258
1435
|
assertGeoArrowResourceLimits(column, options.limits);
|
|
1436
|
+
if (column.encoding === "geoarrow.wkb" || column.encoding === "geoarrow.wkt") {
|
|
1437
|
+
throw new Error("Rewinding requires native GeoArrow storage");
|
|
1438
|
+
}
|
|
1259
1439
|
const outerClockwise = (options.outer || "counter-clockwise") === "clockwise";
|
|
1260
1440
|
let changed = false;
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
changed || (changed = rewound !== row);
|
|
1266
|
-
return rewound;
|
|
1267
|
-
});
|
|
1268
|
-
if (!changed)
|
|
1269
|
-
return column;
|
|
1270
|
-
const result = makeGeoArrowColumnFromGeometryRows(rows, {
|
|
1271
|
-
dimension: column.dimension,
|
|
1272
|
-
coordinateLayout: column.coordinateLayout || "interleaved"
|
|
1441
|
+
const chunks = column.chunks.map((chunk) => {
|
|
1442
|
+
const clone = mapArrayCoordinates(chunk, column.encoding, 0, column.dimension, column.coordinateLayout || "interleaved", (coordinate) => coordinate, "preserve");
|
|
1443
|
+
changed || (changed = rewindArrayRings(clone, column.encoding, outerClockwise));
|
|
1444
|
+
return clone;
|
|
1273
1445
|
});
|
|
1274
|
-
return
|
|
1446
|
+
return changed ? { ...column, chunks } : column;
|
|
1275
1447
|
}
|
|
1276
1448
|
function assertGeoArrowResourceLimits(column, options = {}) {
|
|
1277
1449
|
const rows = getGeoArrowRowCount(column);
|
|
@@ -1298,86 +1470,210 @@ function assertGeoArrowResourceLimits(column, options = {}) {
|
|
|
1298
1470
|
}
|
|
1299
1471
|
}
|
|
1300
1472
|
}
|
|
1301
|
-
function
|
|
1302
|
-
if (geometry.
|
|
1473
|
+
function mapArrayCoordinates(array, encoding, rowOffset, targetDimension, targetLayout, mapper, coordinateType, forceDimension = false, forceLayout = false, sourceDimension, rowIndicesOverride) {
|
|
1474
|
+
if (encoding === "geoarrow.geometry" && array.kind === "dense-union") {
|
|
1475
|
+
const childRowIndices = collectUnionRowIndices(array, rowOffset);
|
|
1303
1476
|
return {
|
|
1304
|
-
...
|
|
1305
|
-
|
|
1477
|
+
...array,
|
|
1478
|
+
children: array.children.map((child, childIndex) => {
|
|
1479
|
+
const childEncoding = child.encoding || getEncodingFromChildName2(child.name);
|
|
1480
|
+
const childDimension = forceDimension ? targetDimension : child.dimension || targetDimension;
|
|
1481
|
+
const childLayout = forceLayout ? targetLayout : child.coordinateLayout || targetLayout;
|
|
1482
|
+
return {
|
|
1483
|
+
...child,
|
|
1484
|
+
data: mapArrayCoordinates(child.data, childEncoding, rowOffset, childDimension, childLayout, mapper, coordinateType, forceDimension, forceLayout, childDimension, childRowIndices[childIndex]),
|
|
1485
|
+
dimension: childDimension,
|
|
1486
|
+
coordinateLayout: childLayout,
|
|
1487
|
+
encoding: childEncoding
|
|
1488
|
+
};
|
|
1489
|
+
})
|
|
1306
1490
|
};
|
|
1307
1491
|
}
|
|
1492
|
+
if (encoding === "geoarrow.geometrycollection" && array.kind === "list") {
|
|
1493
|
+
return {
|
|
1494
|
+
...array,
|
|
1495
|
+
child: mapArrayCoordinates(array.child, "geoarrow.geometry", rowOffset, targetDimension, targetLayout, mapper, coordinateType, forceDimension, forceLayout, sourceDimension, rowIndicesOverride)
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
const depth = getEncodingDepth2(encoding);
|
|
1499
|
+
const rowIndices = rowIndicesOverride || collectLeafRowIndices(array, depth, rowOffset);
|
|
1500
|
+
return mapNestedArray(array, depth, rowOffset, targetDimension, targetLayout, mapper, coordinateType, rowIndices, sourceDimension);
|
|
1501
|
+
}
|
|
1502
|
+
function mapNestedArray(array, depth, rowOffset, targetDimension, targetLayout, mapper, coordinateType, rowIndices, sourceDimension) {
|
|
1503
|
+
if (depth === 0) {
|
|
1504
|
+
return mapCoordinateLeaf(array, rowOffset, targetDimension, targetLayout, mapper, coordinateType, rowIndices, sourceDimension);
|
|
1505
|
+
}
|
|
1506
|
+
if (array.kind !== "list")
|
|
1507
|
+
return array;
|
|
1308
1508
|
return {
|
|
1309
|
-
...
|
|
1310
|
-
|
|
1509
|
+
...array,
|
|
1510
|
+
child: mapNestedArray(array.child, depth - 1, rowOffset, targetDimension, targetLayout, mapper, coordinateType, rowIndices, sourceDimension)
|
|
1311
1511
|
};
|
|
1312
1512
|
}
|
|
1313
|
-
function
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1513
|
+
function mapCoordinateLeaf(array, rowOffset, targetDimension, targetLayout, mapper, coordinateType, rowIndices, sourceDimension) {
|
|
1514
|
+
const count = array.length;
|
|
1515
|
+
const targetSize = getGeoArrowDimensionSize(targetDimension);
|
|
1516
|
+
const sourceValues = new Array(count);
|
|
1517
|
+
for (let index = 0; index < count; index++) {
|
|
1518
|
+
const coordinate = readCoordinateAt(array, index);
|
|
1519
|
+
const mapped = coordinate ? mapper(sourceDimension ? resizeCoordinate(coordinate, sourceDimension, targetDimension) : coordinate, (rowIndices == null ? void 0 : rowIndices[index]) ?? rowOffset) : new Array(targetSize).fill(0);
|
|
1520
|
+
if (mapped.length !== targetSize) {
|
|
1521
|
+
throw new Error(`Coordinate mapper returned ${mapped.length} values; expected ${targetSize}`);
|
|
1522
|
+
}
|
|
1523
|
+
sourceValues[index] = [...mapped];
|
|
1524
|
+
}
|
|
1525
|
+
const FloatArray = resolveCoordinateConstructor(array, coordinateType);
|
|
1526
|
+
return makeCoordinateLeaf(sourceValues, targetDimension, targetLayout, FloatArray, array.validity);
|
|
1319
1527
|
}
|
|
1320
|
-
function
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1528
|
+
function collectLeafRowIndices(array, depth, rowOffset) {
|
|
1529
|
+
const output = new Array(getLeafLength(array, depth)).fill(rowOffset);
|
|
1530
|
+
for (let rowIndex = 0; rowIndex < array.length; rowIndex++) {
|
|
1531
|
+
if (isGeoArrowValueValid(array.validity, rowIndex)) {
|
|
1532
|
+
assignNestedRowIndices(array, rowIndex, depth, rowOffset + rowIndex, output);
|
|
1533
|
+
}
|
|
1324
1534
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1535
|
+
return output;
|
|
1536
|
+
}
|
|
1537
|
+
function assignNestedRowIndices(array, index, depth, rowIndex, output) {
|
|
1538
|
+
if (depth === 0) {
|
|
1539
|
+
if (index >= 0 && index < output.length)
|
|
1540
|
+
output[index] = rowIndex;
|
|
1541
|
+
return;
|
|
1328
1542
|
}
|
|
1329
|
-
if (
|
|
1330
|
-
|
|
1331
|
-
|
|
1543
|
+
if (array.kind !== "list")
|
|
1544
|
+
return;
|
|
1545
|
+
const [first, last] = getListRange(array, index);
|
|
1546
|
+
for (let childIndex = first; childIndex < last; childIndex++) {
|
|
1547
|
+
assignNestedRowIndices(array.child, childIndex, depth - 1, rowIndex, output);
|
|
1332
1548
|
}
|
|
1333
|
-
return geometry;
|
|
1334
1549
|
}
|
|
1335
|
-
function
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
return ring;
|
|
1342
|
-
changed = true;
|
|
1343
|
-
return [...ring].reverse();
|
|
1550
|
+
function collectUnionRowIndices(union, rowOffset) {
|
|
1551
|
+
if (union.kind !== "dense-union")
|
|
1552
|
+
return [];
|
|
1553
|
+
const output = union.children.map((child) => {
|
|
1554
|
+
const encoding = child.encoding || getEncodingFromChildName2(child.name);
|
|
1555
|
+
return new Array(getLeafLength(child.data, getEncodingDepth2(encoding))).fill(rowOffset);
|
|
1344
1556
|
});
|
|
1345
|
-
|
|
1557
|
+
for (let rowIndex = 0; rowIndex < union.length; rowIndex++) {
|
|
1558
|
+
if (!isGeoArrowValueValid(union.validity, rowIndex))
|
|
1559
|
+
continue;
|
|
1560
|
+
const physical = (union.offset || 0) + rowIndex;
|
|
1561
|
+
const childIndex = union.children.findIndex((child2) => child2.typeId === union.typeIds[physical]);
|
|
1562
|
+
if (childIndex < 0)
|
|
1563
|
+
continue;
|
|
1564
|
+
const child = union.children[childIndex];
|
|
1565
|
+
assignUnionRowIndices(child.data, child.encoding || getEncodingFromChildName2(child.name), union.valueOffsets[physical], rowOffset + rowIndex, output[childIndex]);
|
|
1566
|
+
}
|
|
1567
|
+
return output;
|
|
1568
|
+
}
|
|
1569
|
+
function assignUnionRowIndices(array, encoding, index, rowIndex, output) {
|
|
1570
|
+
if (encoding === "geoarrow.geometry" && array.kind === "dense-union") {
|
|
1571
|
+
const physical = (array.offset || 0) + index;
|
|
1572
|
+
const childIndex = array.children.findIndex((child) => child.typeId === array.typeIds[physical]);
|
|
1573
|
+
if (childIndex >= 0) {
|
|
1574
|
+
const child = array.children[childIndex];
|
|
1575
|
+
assignUnionRowIndices(child.data, child.encoding || getEncodingFromChildName2(child.name), array.valueOffsets[physical], rowIndex, output);
|
|
1576
|
+
}
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (encoding === "geoarrow.geometrycollection" && array.kind === "list") {
|
|
1580
|
+
const [first, last] = getListRange(array, index);
|
|
1581
|
+
if (array.child.kind === "dense-union") {
|
|
1582
|
+
for (let childIndex = first; childIndex < last; childIndex++) {
|
|
1583
|
+
assignUnionRowIndices(array.child, "geoarrow.geometry", childIndex, rowIndex, output);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
assignNestedRowIndices(array, index, getEncodingDepth2(encoding), rowIndex, output);
|
|
1346
1589
|
}
|
|
1347
|
-
function
|
|
1348
|
-
let
|
|
1349
|
-
for (let
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1590
|
+
function getLeafLength(array, depth) {
|
|
1591
|
+
let current = array;
|
|
1592
|
+
for (let level = 0; level < depth; level++) {
|
|
1593
|
+
if (current.kind !== "list")
|
|
1594
|
+
return 0;
|
|
1595
|
+
current = current.child;
|
|
1353
1596
|
}
|
|
1354
|
-
return
|
|
1597
|
+
return current.length;
|
|
1355
1598
|
}
|
|
1356
|
-
function
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1599
|
+
function resolveCoordinateConstructor(array, coordinateType) {
|
|
1600
|
+
if (coordinateType === "float32")
|
|
1601
|
+
return Float32Array;
|
|
1602
|
+
if (coordinateType === "float64")
|
|
1603
|
+
return Float64Array;
|
|
1604
|
+
if (array.kind === "fixed-size-list" && array.child.kind === "primitive") {
|
|
1605
|
+
return array.child.values instanceof Float32Array ? Float32Array : Float64Array;
|
|
1606
|
+
}
|
|
1607
|
+
if (array.kind === "struct") {
|
|
1608
|
+
const child = array.children["x"];
|
|
1609
|
+
if ((child == null ? void 0 : child.kind) === "primitive" && child.values instanceof Float32Array)
|
|
1610
|
+
return Float32Array;
|
|
1611
|
+
}
|
|
1612
|
+
return Float64Array;
|
|
1613
|
+
}
|
|
1614
|
+
function makeCoordinateLeaf(coordinates, dimension, layout, FloatArray, validity) {
|
|
1615
|
+
const size = getGeoArrowDimensionSize(dimension);
|
|
1616
|
+
if (layout === "interleaved") {
|
|
1617
|
+
const values = new FloatArray(coordinates.length * size);
|
|
1618
|
+
for (let index = 0; index < coordinates.length; index++) {
|
|
1619
|
+
values.set(coordinates[index], index * size);
|
|
1361
1620
|
}
|
|
1362
|
-
|
|
1621
|
+
return {
|
|
1622
|
+
kind: "fixed-size-list",
|
|
1623
|
+
length: coordinates.length,
|
|
1624
|
+
size,
|
|
1625
|
+
child: { kind: "primitive", length: values.length, values },
|
|
1626
|
+
validity
|
|
1627
|
+
};
|
|
1363
1628
|
}
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
|
|
1629
|
+
const children = {
|
|
1630
|
+
x: { kind: "primitive", length: coordinates.length, values: new FloatArray(coordinates.length) },
|
|
1631
|
+
y: { kind: "primitive", length: coordinates.length, values: new FloatArray(coordinates.length) }
|
|
1632
|
+
};
|
|
1633
|
+
const names = getDimensionNames(dimension);
|
|
1634
|
+
for (let component = 2; component < names.length; component++) {
|
|
1635
|
+
children[names[component]] = {
|
|
1636
|
+
kind: "primitive",
|
|
1637
|
+
length: coordinates.length,
|
|
1638
|
+
values: new FloatArray(coordinates.length)
|
|
1639
|
+
};
|
|
1367
1640
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1641
|
+
for (let index = 0; index < coordinates.length; index++) {
|
|
1642
|
+
const coordinate = coordinates[index];
|
|
1643
|
+
for (let component = 0; component < names.length; component++) {
|
|
1644
|
+
const child = children[names[component]];
|
|
1645
|
+
if (child.kind === "primitive")
|
|
1646
|
+
child.values[index] = coordinate[component];
|
|
1647
|
+
}
|
|
1371
1648
|
}
|
|
1372
|
-
return {
|
|
1649
|
+
return { kind: "struct", length: coordinates.length, children, validity };
|
|
1373
1650
|
}
|
|
1374
|
-
function
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
const
|
|
1379
|
-
|
|
1380
|
-
|
|
1651
|
+
function readCoordinateAt(array, index) {
|
|
1652
|
+
if (!isGeoArrowValueValid(array.validity, index))
|
|
1653
|
+
return null;
|
|
1654
|
+
if (array.kind === "fixed-size-list") {
|
|
1655
|
+
const logicalIndex = (array.offset || 0) + index;
|
|
1656
|
+
if (array.child.kind !== "primitive")
|
|
1657
|
+
return null;
|
|
1658
|
+
const values = [];
|
|
1659
|
+
for (let component = 0; component < array.size; component++) {
|
|
1660
|
+
const scalarIndex = logicalIndex * array.size + component;
|
|
1661
|
+
values.push(Number(array.child.values[(array.child.offset || 0) + scalarIndex * (array.child.stride || 1)]));
|
|
1662
|
+
}
|
|
1663
|
+
return values;
|
|
1664
|
+
}
|
|
1665
|
+
if (array.kind === "struct") {
|
|
1666
|
+
const logicalIndex = (array.offset || 0) + index;
|
|
1667
|
+
const values = [];
|
|
1668
|
+
for (const name of ["x", "y", "z", "m"]) {
|
|
1669
|
+
const child = array.children[name];
|
|
1670
|
+
if ((child == null ? void 0 : child.kind) === "primitive") {
|
|
1671
|
+
values.push(Number(child.values[(child.offset || 0) + logicalIndex * (child.stride || 1)]));
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return values.length >= 2 ? values : null;
|
|
1675
|
+
}
|
|
1676
|
+
return null;
|
|
1381
1677
|
}
|
|
1382
1678
|
function getDimensionNames(dimension) {
|
|
1383
1679
|
switch (dimension) {
|
|
@@ -1391,14 +1687,321 @@ function getDimensionNames(dimension) {
|
|
|
1391
1687
|
return ["x", "y", "z", "m"];
|
|
1392
1688
|
}
|
|
1393
1689
|
}
|
|
1394
|
-
function
|
|
1690
|
+
function getEncodingFromChildName2(name) {
|
|
1691
|
+
const normalized = name.replace(/[^a-z]/gi, "").toLowerCase();
|
|
1692
|
+
const encoding = `geoarrow.${normalized}`;
|
|
1693
|
+
if (encoding === "geoarrow.point" || encoding === "geoarrow.linestring" || encoding === "geoarrow.polygon" || encoding === "geoarrow.multipoint" || encoding === "geoarrow.multilinestring" || encoding === "geoarrow.multipolygon" || encoding === "geoarrow.geometrycollection") {
|
|
1694
|
+
return encoding;
|
|
1695
|
+
}
|
|
1696
|
+
throw new Error(`Unknown GeoArrow dense-union child ${name}`);
|
|
1697
|
+
}
|
|
1698
|
+
function getEncodingDepth2(encoding) {
|
|
1699
|
+
switch (encoding) {
|
|
1700
|
+
case "geoarrow.point":
|
|
1701
|
+
return 0;
|
|
1702
|
+
case "geoarrow.linestring":
|
|
1703
|
+
case "geoarrow.multipoint":
|
|
1704
|
+
return 1;
|
|
1705
|
+
case "geoarrow.polygon":
|
|
1706
|
+
case "geoarrow.multilinestring":
|
|
1707
|
+
return 2;
|
|
1708
|
+
case "geoarrow.multipolygon":
|
|
1709
|
+
return 3;
|
|
1710
|
+
default:
|
|
1711
|
+
return 0;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
function promoteToDenseUnion(column) {
|
|
1715
|
+
if (column.encoding === "geoarrow.geometry")
|
|
1716
|
+
return column;
|
|
1717
|
+
const chunks = column.chunks.map((chunk) => {
|
|
1718
|
+
const typeId = getCanonicalTypeId(column.encoding, column.dimension);
|
|
1719
|
+
const typeIds = new Int8Array(chunk.length);
|
|
1720
|
+
typeIds.fill(typeId);
|
|
1721
|
+
const valueOffsets = new Int32Array(chunk.length);
|
|
1722
|
+
for (let index = 0; index < chunk.length; index++)
|
|
1723
|
+
valueOffsets[index] = index;
|
|
1724
|
+
return {
|
|
1725
|
+
kind: "dense-union",
|
|
1726
|
+
length: chunk.length,
|
|
1727
|
+
typeIds,
|
|
1728
|
+
valueOffsets,
|
|
1729
|
+
validity: chunk.validity,
|
|
1730
|
+
children: [
|
|
1731
|
+
{
|
|
1732
|
+
name: getGeoArrowGeometryTypeName(column.encoding),
|
|
1733
|
+
typeId,
|
|
1734
|
+
encoding: column.encoding,
|
|
1735
|
+
dimension: column.dimension,
|
|
1736
|
+
coordinateLayout: column.coordinateLayout,
|
|
1737
|
+
data: chunk
|
|
1738
|
+
}
|
|
1739
|
+
]
|
|
1740
|
+
};
|
|
1741
|
+
});
|
|
1742
|
+
return { ...column, encoding: "geoarrow.geometry", chunks };
|
|
1743
|
+
}
|
|
1744
|
+
function demoteDenseUnion(column, encoding) {
|
|
1745
|
+
if (encoding === "geoarrow.geometry" || encoding === "geoarrow.geometrycollection")
|
|
1746
|
+
return column;
|
|
1747
|
+
const rows = [];
|
|
1748
|
+
for (const chunk of column.chunks) {
|
|
1749
|
+
if (chunk.kind !== "dense-union")
|
|
1750
|
+
throw new Error("Expected dense-union storage");
|
|
1751
|
+
for (let index = 0; index < chunk.length; index++) {
|
|
1752
|
+
if (!isGeoArrowValueValid(chunk.validity, index)) {
|
|
1753
|
+
rows.push(null);
|
|
1754
|
+
continue;
|
|
1755
|
+
}
|
|
1756
|
+
const physical = (chunk.offset || 0) + index;
|
|
1757
|
+
const child = chunk.children.find((candidate) => candidate.typeId === chunk.typeIds[physical]);
|
|
1758
|
+
const childEncoding = child && (child.encoding || getEncodingFromChildName2(child.name));
|
|
1759
|
+
if (!child || childEncoding !== encoding) {
|
|
1760
|
+
throw new Error(`Rows cannot be represented as ${encoding}`);
|
|
1761
|
+
}
|
|
1762
|
+
const geometry = materializeGeometryRow(child.data, chunk.valueOffsets[physical], childEncoding);
|
|
1763
|
+
rows.push(geometry ? resizeGeometryValue(geometry, child.dimension || column.dimension, column.dimension) : null);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
const built = makeGeoArrowColumnFromGeometryRows(rows, {
|
|
1767
|
+
dimension: column.dimension,
|
|
1768
|
+
coordinateLayout: column.coordinateLayout || "interleaved",
|
|
1769
|
+
offsetType: getColumnOffsetType(column)
|
|
1770
|
+
});
|
|
1771
|
+
return {
|
|
1772
|
+
...built,
|
|
1773
|
+
encoding,
|
|
1774
|
+
spatialReference: column.spatialReference,
|
|
1775
|
+
edges: column.edges,
|
|
1776
|
+
metadata: column.metadata
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
function resizeGeometryValue(geometry, sourceDimension, targetDimension) {
|
|
1780
|
+
const map = (value) => {
|
|
1781
|
+
if (Array.isArray(value) && (value.length === 0 || typeof value[0] === "number")) {
|
|
1782
|
+
return resizeCoordinate(value, sourceDimension, targetDimension);
|
|
1783
|
+
}
|
|
1784
|
+
return Array.isArray(value) ? value.map(map) : value;
|
|
1785
|
+
};
|
|
1786
|
+
if (geometry.type === "GeometryCollection") {
|
|
1787
|
+
return {
|
|
1788
|
+
type: geometry.type,
|
|
1789
|
+
geometries: geometry.geometries.map((child) => resizeGeometryValue(child, sourceDimension, targetDimension))
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1395
1792
|
return {
|
|
1396
|
-
...
|
|
1397
|
-
|
|
1398
|
-
edges: source.edges,
|
|
1399
|
-
metadata: source.metadata
|
|
1793
|
+
...geometry,
|
|
1794
|
+
coordinates: map(geometry.coordinates)
|
|
1400
1795
|
};
|
|
1401
1796
|
}
|
|
1797
|
+
function getCanonicalTypeId(encoding, dimension) {
|
|
1798
|
+
const families = [
|
|
1799
|
+
"point",
|
|
1800
|
+
"linestring",
|
|
1801
|
+
"polygon",
|
|
1802
|
+
"multipoint",
|
|
1803
|
+
"multilinestring",
|
|
1804
|
+
"multipolygon",
|
|
1805
|
+
"geometrycollection"
|
|
1806
|
+
];
|
|
1807
|
+
const dimensions = ["xy", "xyz", "xym", "xyzm"];
|
|
1808
|
+
const family = encoding.replace("geoarrow.", "");
|
|
1809
|
+
const familyIndex = families.indexOf(family);
|
|
1810
|
+
const dimensionIndex = dimensions.indexOf(dimension);
|
|
1811
|
+
return familyIndex < 0 || dimensionIndex < 0 ? 1 : familyIndex * 4 + dimensionIndex + 1;
|
|
1812
|
+
}
|
|
1813
|
+
function getColumnOffsetType(column) {
|
|
1814
|
+
for (const chunk of column.chunks) {
|
|
1815
|
+
const found = findOffsetType(chunk);
|
|
1816
|
+
if (found)
|
|
1817
|
+
return found;
|
|
1818
|
+
}
|
|
1819
|
+
return "int32";
|
|
1820
|
+
}
|
|
1821
|
+
function findOffsetType(array) {
|
|
1822
|
+
switch (array.kind) {
|
|
1823
|
+
case "list":
|
|
1824
|
+
case "serialized":
|
|
1825
|
+
return array.offsets instanceof BigInt64Array ? "int64" : "int32";
|
|
1826
|
+
case "fixed-size-list":
|
|
1827
|
+
return findOffsetType(array.child);
|
|
1828
|
+
case "struct": {
|
|
1829
|
+
for (const child of Object.values(array.children)) {
|
|
1830
|
+
const found = findOffsetType(child);
|
|
1831
|
+
if (found)
|
|
1832
|
+
return found;
|
|
1833
|
+
}
|
|
1834
|
+
return null;
|
|
1835
|
+
}
|
|
1836
|
+
case "dense-union":
|
|
1837
|
+
for (const child of array.children) {
|
|
1838
|
+
const found = findOffsetType(child.data);
|
|
1839
|
+
if (found)
|
|
1840
|
+
return found;
|
|
1841
|
+
}
|
|
1842
|
+
return null;
|
|
1843
|
+
default:
|
|
1844
|
+
return null;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function convertArrayOffsets(array, offsetType) {
|
|
1848
|
+
const toOffsets = (offsets, offsetBase) => {
|
|
1849
|
+
if (offsetType === "int64") {
|
|
1850
|
+
const result2 = new BigInt64Array(offsets.length);
|
|
1851
|
+
for (let index = 0; index < offsets.length; index++)
|
|
1852
|
+
result2[index] = BigInt(offsets[index]);
|
|
1853
|
+
return { offsets: result2, ...offsetBase === void 0 ? {} : { offsetBase } };
|
|
1854
|
+
}
|
|
1855
|
+
const result = new Int32Array(offsets.length);
|
|
1856
|
+
const base = BigInt(offsetBase ?? 0);
|
|
1857
|
+
for (let index = 0; index < offsets.length; index++) {
|
|
1858
|
+
const value = BigInt(offsets[index]) - base;
|
|
1859
|
+
if (value < -2147483648n || value > 2147483647n) {
|
|
1860
|
+
throw new Error("GeoArrow offset cannot be represented as Int32");
|
|
1861
|
+
}
|
|
1862
|
+
result[index] = Number(value);
|
|
1863
|
+
}
|
|
1864
|
+
return { offsets: result, offsetBase: 0 };
|
|
1865
|
+
};
|
|
1866
|
+
switch (array.kind) {
|
|
1867
|
+
case "list":
|
|
1868
|
+
if (array.offsets instanceof (offsetType === "int64" ? BigInt64Array : Int32Array)) {
|
|
1869
|
+
return { ...array, child: convertArrayOffsets(array.child, offsetType) };
|
|
1870
|
+
}
|
|
1871
|
+
return {
|
|
1872
|
+
...array,
|
|
1873
|
+
...toOffsets(array.offsets, array.offsetBase),
|
|
1874
|
+
child: convertArrayOffsets(array.child, offsetType)
|
|
1875
|
+
};
|
|
1876
|
+
case "serialized":
|
|
1877
|
+
if (array.offsets instanceof (offsetType === "int64" ? BigInt64Array : Int32Array))
|
|
1878
|
+
return array;
|
|
1879
|
+
return { ...array, ...toOffsets(array.offsets, array.offsetBase) };
|
|
1880
|
+
case "fixed-size-list":
|
|
1881
|
+
return { ...array, child: convertArrayOffsets(array.child, offsetType) };
|
|
1882
|
+
case "struct":
|
|
1883
|
+
return {
|
|
1884
|
+
...array,
|
|
1885
|
+
children: Object.fromEntries(Object.entries(array.children).map(([name, child]) => [
|
|
1886
|
+
name,
|
|
1887
|
+
convertArrayOffsets(child, offsetType)
|
|
1888
|
+
]))
|
|
1889
|
+
};
|
|
1890
|
+
case "dense-union":
|
|
1891
|
+
return {
|
|
1892
|
+
...array,
|
|
1893
|
+
children: array.children.map((child) => ({
|
|
1894
|
+
...child,
|
|
1895
|
+
data: convertArrayOffsets(child.data, offsetType)
|
|
1896
|
+
}))
|
|
1897
|
+
};
|
|
1898
|
+
default:
|
|
1899
|
+
return array;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
function getGeoArrowGeometryTypeName(encoding) {
|
|
1903
|
+
return encoding.replace("geoarrow.", "").replace(/^./, (character) => character.toUpperCase());
|
|
1904
|
+
}
|
|
1905
|
+
function rewindArrayRings(array, encoding, outerClockwise) {
|
|
1906
|
+
if (encoding === "geoarrow.geometry" && array.kind === "dense-union") {
|
|
1907
|
+
let changed2 = false;
|
|
1908
|
+
for (const child of array.children) {
|
|
1909
|
+
if (rewindArrayRings(child.data, child.encoding || getEncodingFromChildName2(child.name), outerClockwise))
|
|
1910
|
+
changed2 = true;
|
|
1911
|
+
}
|
|
1912
|
+
return changed2;
|
|
1913
|
+
}
|
|
1914
|
+
if (encoding === "geoarrow.geometrycollection" && array.kind === "list") {
|
|
1915
|
+
if (array.child.kind !== "dense-union")
|
|
1916
|
+
return false;
|
|
1917
|
+
let changed2 = false;
|
|
1918
|
+
for (const child of array.child.children) {
|
|
1919
|
+
if (rewindArrayRings(child.data, child.encoding || getEncodingFromChildName2(child.name), outerClockwise))
|
|
1920
|
+
changed2 = true;
|
|
1921
|
+
}
|
|
1922
|
+
return changed2;
|
|
1923
|
+
}
|
|
1924
|
+
if (encoding !== "geoarrow.polygon" && encoding !== "geoarrow.multipolygon")
|
|
1925
|
+
return false;
|
|
1926
|
+
if (array.kind !== "list" || array.child.kind !== "list")
|
|
1927
|
+
return false;
|
|
1928
|
+
let changed = false;
|
|
1929
|
+
for (let rowIndex = 0; rowIndex < array.length; rowIndex++) {
|
|
1930
|
+
if (!isGeoArrowValueValid(array.validity, rowIndex))
|
|
1931
|
+
continue;
|
|
1932
|
+
const [, rowEnd] = getListRange(array, rowIndex);
|
|
1933
|
+
const rowStart = getListRange(array, rowIndex)[0];
|
|
1934
|
+
if (encoding === "geoarrow.polygon") {
|
|
1935
|
+
const rings = array.child;
|
|
1936
|
+
if (rewindRingGroup(rings, rowStart, rowEnd, outerClockwise))
|
|
1937
|
+
changed = true;
|
|
1938
|
+
} else {
|
|
1939
|
+
const polygons = array.child;
|
|
1940
|
+
for (let polygonIndex = rowStart; polygonIndex < rowEnd; polygonIndex++) {
|
|
1941
|
+
const [ringStart, ringEnd] = getListRange(polygons, polygonIndex);
|
|
1942
|
+
if (rewindRingGroup(polygons.child, ringStart, ringEnd, outerClockwise))
|
|
1943
|
+
changed = true;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
return changed;
|
|
1948
|
+
}
|
|
1949
|
+
function rewindRingGroup(rings, firstRing, lastRing, outerClockwise) {
|
|
1950
|
+
if (rings.kind !== "list")
|
|
1951
|
+
return false;
|
|
1952
|
+
const leaf = rings.child;
|
|
1953
|
+
if (leaf.kind !== "fixed-size-list" && leaf.kind !== "struct")
|
|
1954
|
+
return false;
|
|
1955
|
+
let changed = false;
|
|
1956
|
+
for (let ringIndex = firstRing; ringIndex < lastRing; ringIndex++) {
|
|
1957
|
+
const [first, last] = getListRange(rings, ringIndex);
|
|
1958
|
+
const area = getRingArea(leaf, first, last);
|
|
1959
|
+
if (!Number.isFinite(area) || area === 0)
|
|
1960
|
+
continue;
|
|
1961
|
+
const shouldClockwise = ringIndex === firstRing ? outerClockwise : !outerClockwise;
|
|
1962
|
+
if (area < 0 !== shouldClockwise) {
|
|
1963
|
+
reverseCoordinateRange(leaf, first, last);
|
|
1964
|
+
changed = true;
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
return changed;
|
|
1968
|
+
}
|
|
1969
|
+
function getRingArea(leaf, first, last) {
|
|
1970
|
+
let area = 0;
|
|
1971
|
+
for (let index = first; index < last; index++) {
|
|
1972
|
+
const current = readCoordinateAt(leaf, index);
|
|
1973
|
+
const next = readCoordinateAt(leaf, index + 1 < last ? index + 1 : first);
|
|
1974
|
+
if (!current || !next)
|
|
1975
|
+
return Number.NaN;
|
|
1976
|
+
area += current[0] * next[1] - next[0] * current[1];
|
|
1977
|
+
}
|
|
1978
|
+
return area / 2;
|
|
1979
|
+
}
|
|
1980
|
+
function reverseCoordinateRange(leaf, first, last) {
|
|
1981
|
+
const values = [];
|
|
1982
|
+
for (let index = first; index < last; index++)
|
|
1983
|
+
values.push(readCoordinateAt(leaf, index));
|
|
1984
|
+
values.reverse();
|
|
1985
|
+
for (let index = first; index < last; index++)
|
|
1986
|
+
writeCoordinateAt(leaf, index, values[index - first]);
|
|
1987
|
+
}
|
|
1988
|
+
function writeCoordinateAt(array, index, coordinate) {
|
|
1989
|
+
if (array.kind === "fixed-size-list" && array.child.kind === "primitive") {
|
|
1990
|
+
const logical = (array.offset || 0) + index;
|
|
1991
|
+
for (let component = 0; component < array.size; component++) {
|
|
1992
|
+
const scalar = (array.child.offset || 0) + logical * array.size + component;
|
|
1993
|
+
array.child.values[scalar] = coordinate[component];
|
|
1994
|
+
}
|
|
1995
|
+
} else if (array.kind === "struct") {
|
|
1996
|
+
const logical = (array.offset || 0) + index;
|
|
1997
|
+
const names = ["x", "y", "z", "m"];
|
|
1998
|
+
for (let component = 0; component < names.length; component++) {
|
|
1999
|
+
const child = array.children[names[component]];
|
|
2000
|
+
if ((child == null ? void 0 : child.kind) === "primitive")
|
|
2001
|
+
child.values[(child.offset || 0) + logical * (child.stride || 1)] = coordinate[component];
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
1402
2005
|
function collectCoordinateLeaves(column) {
|
|
1403
2006
|
const leaves = [];
|
|
1404
2007
|
for (const chunk of column.chunks)
|
|
@@ -1447,6 +2050,7 @@ function getArrayDepth(array) {
|
|
|
1447
2050
|
|
|
1448
2051
|
// dist/codecs.js
|
|
1449
2052
|
var import_wkb = require("@math.gl/wkb");
|
|
2053
|
+
var import_wkb2 = require("@math.gl/wkb");
|
|
1450
2054
|
var textEncoder = new TextEncoder();
|
|
1451
2055
|
var textDecoder = new TextDecoder();
|
|
1452
2056
|
function decodeGeoArrowWKB(column) {
|
|
@@ -1458,9 +2062,38 @@ function decodeGeoArrowWKB(column) {
|
|
|
1458
2062
|
function encodeGeoArrowWKB(column) {
|
|
1459
2063
|
if (column.encoding === "geoarrow.wkb")
|
|
1460
2064
|
return column;
|
|
1461
|
-
const
|
|
1462
|
-
const
|
|
1463
|
-
|
|
2065
|
+
const writers = [];
|
|
2066
|
+
const dimensions = [];
|
|
2067
|
+
for (const chunk of column.chunks) {
|
|
2068
|
+
for (let rowIndex = 0; rowIndex < chunk.length; rowIndex++) {
|
|
2069
|
+
if (!isGeoArrowValueValid(chunk.validity, rowIndex)) {
|
|
2070
|
+
writers.push(null);
|
|
2071
|
+
dimensions.push(column.dimension);
|
|
2072
|
+
continue;
|
|
2073
|
+
}
|
|
2074
|
+
dimensions.push(getPhysicalGeometryDimension(chunk, rowIndex, column.encoding, column.dimension));
|
|
2075
|
+
writers.push((builder) => writePhysicalGeometry(builder, chunk, rowIndex, column.encoding, column.dimension));
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
const built = import_wkb2.WKBBuilder.buildGeometryArray(writers, {
|
|
2079
|
+
dimension: column.dimension,
|
|
2080
|
+
dimensionResolver: (index) => dimensions[index] || column.dimension
|
|
2081
|
+
});
|
|
2082
|
+
return copyMetadata(column, {
|
|
2083
|
+
encoding: "geoarrow.wkb",
|
|
2084
|
+
dimension: column.dimension,
|
|
2085
|
+
coordinateLayout: null,
|
|
2086
|
+
chunks: [
|
|
2087
|
+
{
|
|
2088
|
+
kind: "serialized",
|
|
2089
|
+
encoding: "binary",
|
|
2090
|
+
length: writers.length,
|
|
2091
|
+
offsets: built.valueOffsets,
|
|
2092
|
+
values: built.values,
|
|
2093
|
+
...built.nullBitmap ? { validity: { values: built.nullBitmap } } : {}
|
|
2094
|
+
}
|
|
2095
|
+
]
|
|
2096
|
+
});
|
|
1464
2097
|
}
|
|
1465
2098
|
function decodeGeoArrowWKT(column) {
|
|
1466
2099
|
if (column.encoding !== "geoarrow.wkt")
|
|
@@ -1471,10 +2104,146 @@ function decodeGeoArrowWKT(column) {
|
|
|
1471
2104
|
function encodeGeoArrowWKT(column) {
|
|
1472
2105
|
if (column.encoding === "geoarrow.wkt")
|
|
1473
2106
|
return column;
|
|
1474
|
-
const
|
|
1475
|
-
|
|
2107
|
+
const values = [];
|
|
2108
|
+
for (const chunk of column.chunks) {
|
|
2109
|
+
for (let rowIndex = 0; rowIndex < chunk.length; rowIndex++) {
|
|
2110
|
+
const row = isGeoArrowValueValid(chunk.validity, rowIndex) ? materializeGeometryRow(chunk, rowIndex, column.encoding) : null;
|
|
2111
|
+
values.push(row ? textEncoder.encode((0, import_wkb.formatWKT)(row, column.dimension)) : null);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
1476
2114
|
return copyMetadata(column, makeSerializedColumn(values, "geoarrow.wkt", column.dimension));
|
|
1477
2115
|
}
|
|
2116
|
+
function writePhysicalGeometry(builder, array, rowIndex, encoding, dimension) {
|
|
2117
|
+
const depth = getEncodingDepth3(encoding);
|
|
2118
|
+
if (encoding === "geoarrow.geometry" && array.kind === "dense-union") {
|
|
2119
|
+
const physical = (array.offset || 0) + rowIndex;
|
|
2120
|
+
const typeId = array.typeIds[physical];
|
|
2121
|
+
const child = array.children.find((candidate) => candidate.typeId === typeId);
|
|
2122
|
+
if (!child)
|
|
2123
|
+
throw new Error("Dense-union row references an unknown child");
|
|
2124
|
+
const childDimension = child.dimension || dimension;
|
|
2125
|
+
builder.withDimension(childDimension, () => writePhysicalGeometry(builder, child.data, array.valueOffsets[physical], child.encoding || encodingFromName(child.name), childDimension));
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
if (encoding === "geoarrow.geometrycollection" && array.kind === "list") {
|
|
2129
|
+
const [first, last] = getListRange2(array, rowIndex);
|
|
2130
|
+
builder.beginGeometry("GeometryCollection", last - first);
|
|
2131
|
+
if (array.child.kind !== "dense-union")
|
|
2132
|
+
throw new Error("GeometryCollection requires dense union child");
|
|
2133
|
+
const union = array.child;
|
|
2134
|
+
for (let index = first; index < last; index++) {
|
|
2135
|
+
const physical = (union.offset || 0) + index;
|
|
2136
|
+
const child = union.children.find((candidate) => candidate.typeId === union.typeIds[physical]);
|
|
2137
|
+
if (child) {
|
|
2138
|
+
const childDimension = child.dimension || dimension;
|
|
2139
|
+
builder.withDimension(childDimension, () => writePhysicalGeometry(builder, child.data, union.valueOffsets[physical], child.encoding || encodingFromName(child.name), childDimension));
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
if (array.kind !== "list" && depth > 0)
|
|
2145
|
+
throw new Error(`Invalid ${encoding} storage`);
|
|
2146
|
+
const writeCoordinate2 = (leaf, index) => {
|
|
2147
|
+
const coordinate = readPhysicalCoordinate(leaf, index);
|
|
2148
|
+
if (!coordinate)
|
|
2149
|
+
throw new Error("Invalid GeoArrow coordinate storage");
|
|
2150
|
+
if (dimension === "xym")
|
|
2151
|
+
builder.writeCoordinate(coordinate[0], coordinate[1], void 0, coordinate[2]);
|
|
2152
|
+
else if (dimension === "xyzm")
|
|
2153
|
+
builder.writeCoordinate(coordinate[0], coordinate[1], coordinate[2], coordinate[3]);
|
|
2154
|
+
else
|
|
2155
|
+
builder.writeCoordinate(coordinate[0], coordinate[1], coordinate[2]);
|
|
2156
|
+
};
|
|
2157
|
+
const writeSequence = (leaf, first, last) => {
|
|
2158
|
+
for (let index = first; index < last; index++)
|
|
2159
|
+
writeCoordinate2(leaf, index);
|
|
2160
|
+
};
|
|
2161
|
+
if (encoding === "geoarrow.point") {
|
|
2162
|
+
builder.beginPoint();
|
|
2163
|
+
writeCoordinate2(array, rowIndex);
|
|
2164
|
+
} else if (encoding === "geoarrow.linestring" || encoding === "geoarrow.multipoint") {
|
|
2165
|
+
const [first, last] = getListRange2(array, rowIndex);
|
|
2166
|
+
if (encoding === "geoarrow.linestring") {
|
|
2167
|
+
builder.beginLineString(last - first);
|
|
2168
|
+
writeSequence(array.child, first, last);
|
|
2169
|
+
} else {
|
|
2170
|
+
builder.beginMultiPoint(last - first);
|
|
2171
|
+
const leaf = array.child;
|
|
2172
|
+
for (let index = first; index < last; index++) {
|
|
2173
|
+
builder.beginPoint();
|
|
2174
|
+
writeCoordinate2(leaf, index);
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
} else if (encoding === "geoarrow.polygon" || encoding === "geoarrow.multilinestring") {
|
|
2178
|
+
const [first, last] = getListRange2(array, rowIndex);
|
|
2179
|
+
const parts = array.child;
|
|
2180
|
+
if (encoding === "geoarrow.polygon")
|
|
2181
|
+
builder.beginPolygon(last - first);
|
|
2182
|
+
else
|
|
2183
|
+
builder.beginMultiLineString(last - first);
|
|
2184
|
+
for (let partIndex = first; partIndex < last; partIndex++) {
|
|
2185
|
+
const [ringFirst, ringLast] = getListRange2(parts, partIndex);
|
|
2186
|
+
const leaf = parts.child;
|
|
2187
|
+
if (encoding === "geoarrow.polygon")
|
|
2188
|
+
builder.beginLinearRing(ringLast - ringFirst);
|
|
2189
|
+
else
|
|
2190
|
+
builder.beginLineString(ringLast - ringFirst);
|
|
2191
|
+
writeSequence(leaf, ringFirst, ringLast);
|
|
2192
|
+
}
|
|
2193
|
+
} else if (encoding === "geoarrow.multipolygon") {
|
|
2194
|
+
const [first, last] = getListRange2(array, rowIndex);
|
|
2195
|
+
const polygons = array.child;
|
|
2196
|
+
builder.beginMultiPolygon(last - first);
|
|
2197
|
+
for (let polygonIndex = first; polygonIndex < last; polygonIndex++) {
|
|
2198
|
+
const [partFirst, partLast] = getListRange2(polygons, polygonIndex);
|
|
2199
|
+
const parts = polygons.child;
|
|
2200
|
+
builder.beginPolygon(partLast - partFirst);
|
|
2201
|
+
for (let partIndex = partFirst; partIndex < partLast; partIndex++) {
|
|
2202
|
+
const [ringFirst, ringLast] = getListRange2(parts, partIndex);
|
|
2203
|
+
builder.beginLinearRing(ringLast - ringFirst);
|
|
2204
|
+
writeSequence(parts.child, ringFirst, ringLast);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
function getPhysicalGeometryDimension(array, rowIndex, encoding, dimension) {
|
|
2210
|
+
if (encoding !== "geoarrow.geometry" || array.kind !== "dense-union")
|
|
2211
|
+
return dimension;
|
|
2212
|
+
const physical = (array.offset || 0) + rowIndex;
|
|
2213
|
+
const child = array.children.find((candidate) => candidate.typeId === array.typeIds[physical]);
|
|
2214
|
+
return (child == null ? void 0 : child.dimension) || dimension;
|
|
2215
|
+
}
|
|
2216
|
+
function readPhysicalCoordinate(array, index) {
|
|
2217
|
+
if (array.kind === "fixed-size-list" && array.child.kind === "primitive") {
|
|
2218
|
+
const logical = (array.offset || 0) + index;
|
|
2219
|
+
const values = [];
|
|
2220
|
+
for (let component = 0; component < array.size; component++)
|
|
2221
|
+
values.push(Number(array.child.values[(array.child.offset || 0) + (logical * array.size + component) * (array.child.stride || 1)]));
|
|
2222
|
+
return values;
|
|
2223
|
+
}
|
|
2224
|
+
if (array.kind === "struct") {
|
|
2225
|
+
const logical = (array.offset || 0) + index;
|
|
2226
|
+
return ["x", "y", "z", "m"].flatMap((name) => {
|
|
2227
|
+
const child = array.children[name];
|
|
2228
|
+
return (child == null ? void 0 : child.kind) === "primitive" ? [Number(child.values[(child.offset || 0) + logical * (child.stride || 1)])] : [];
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
return null;
|
|
2232
|
+
}
|
|
2233
|
+
function getListRange2(list, index) {
|
|
2234
|
+
const offset = (list.offset || 0) + index;
|
|
2235
|
+
const base = typeof (list.offsetBase ?? 0) === "bigint" ? Number(list.offsetBase) : Number(list.offsetBase ?? 0);
|
|
2236
|
+
return [
|
|
2237
|
+
getGeoArrowOffset(list.offsets, offset) - base,
|
|
2238
|
+
getGeoArrowOffset(list.offsets, offset + 1) - base
|
|
2239
|
+
];
|
|
2240
|
+
}
|
|
2241
|
+
function getEncodingDepth3(encoding) {
|
|
2242
|
+
return encoding === "geoarrow.point" ? 0 : encoding === "geoarrow.linestring" || encoding === "geoarrow.multipoint" ? 1 : encoding === "geoarrow.polygon" || encoding === "geoarrow.multilinestring" ? 2 : 3;
|
|
2243
|
+
}
|
|
2244
|
+
function encodingFromName(name) {
|
|
2245
|
+
return `geoarrow.${name.toLowerCase()}`;
|
|
2246
|
+
}
|
|
1478
2247
|
function normalizeRowsToDimension(rows, dimension) {
|
|
1479
2248
|
const size = getGeoArrowDimensionSize(dimension);
|
|
1480
2249
|
const normalizeGeometry = (geometry) => {
|
|
@@ -1515,6 +2284,21 @@ function decodeSerializedRows(column, decoder) {
|
|
|
1515
2284
|
return rows;
|
|
1516
2285
|
}
|
|
1517
2286
|
function getSerializedBytes(array, rowIndex) {
|
|
2287
|
+
var _a;
|
|
2288
|
+
if (array.views) {
|
|
2289
|
+
const viewIndex = ((array.offset || 0) + rowIndex) * 4;
|
|
2290
|
+
const length = array.views[viewIndex];
|
|
2291
|
+
if (length <= 12) {
|
|
2292
|
+
const byteOffset2 = array.views.byteOffset + viewIndex * 4 + 4;
|
|
2293
|
+
return new Uint8Array(array.views.buffer, byteOffset2, length);
|
|
2294
|
+
}
|
|
2295
|
+
const bufferIndex = array.views[viewIndex + 2];
|
|
2296
|
+
const byteOffset = array.views[viewIndex + 3];
|
|
2297
|
+
const data = (_a = array.dataBuffers) == null ? void 0 : _a[bufferIndex];
|
|
2298
|
+
if (!data)
|
|
2299
|
+
throw new Error(`Serialized view references missing data buffer ${bufferIndex}`);
|
|
2300
|
+
return data.subarray(byteOffset, byteOffset + length);
|
|
2301
|
+
}
|
|
1518
2302
|
const offsetIndex = (array.offset || 0) + rowIndex;
|
|
1519
2303
|
const baseValue = array.offsetBase ?? 0;
|
|
1520
2304
|
const base = typeof baseValue === "bigint" ? Number(baseValue) : baseValue;
|