@math.gl/wkb 5.0.0-alpha.2

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/dist/index.cjs ADDED
@@ -0,0 +1,947 @@
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/index.js
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ WKBBuilder: () => WKBBuilder,
23
+ formatWKT: () => formatWKT,
24
+ getWellKnownDimensionSize: () => getWellKnownDimensionSize,
25
+ inferWellKnownGeometryDimension: () => inferWellKnownGeometryDimension,
26
+ inspectWKBHeader: () => inspectWKBHeader,
27
+ parseWKB: () => parseWKB,
28
+ parseWKT: () => parseWKT,
29
+ scanWKB: () => scanWKB,
30
+ visitWKB: () => visitWKB,
31
+ writeWKB: () => writeWKB
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // dist/types.js
36
+ function getWellKnownDimensionSize(dimension) {
37
+ switch (dimension) {
38
+ case "xy":
39
+ return 2;
40
+ case "xyz":
41
+ case "xym":
42
+ return 3;
43
+ case "xyzm":
44
+ return 4;
45
+ }
46
+ }
47
+ function inferWellKnownGeometryDimension(geometry) {
48
+ const size = getGeometryDimensionSize(geometry);
49
+ return size >= 4 ? "xyzm" : size === 3 ? "xyz" : "xy";
50
+ }
51
+ function getGeometryDimensionSize(geometry) {
52
+ if (geometry.type === "GeometryCollection") {
53
+ return Math.max(2, ...geometry.geometries.map(getGeometryDimensionSize));
54
+ }
55
+ return getCoordinateDimension(geometry.coordinates);
56
+ }
57
+ function getCoordinateDimension(value) {
58
+ if (value.length === 0)
59
+ return 2;
60
+ if (typeof value[0] === "number")
61
+ return value.length;
62
+ return Math.max(2, ...value.map((child) => getCoordinateDimension(child)));
63
+ }
64
+
65
+ // dist/wkb-reader.js
66
+ var GEOMETRY_TYPES = [
67
+ "Point",
68
+ "LineString",
69
+ "Polygon",
70
+ "MultiPoint",
71
+ "MultiLineString",
72
+ "MultiPolygon",
73
+ "GeometryCollection"
74
+ ];
75
+ function inspectWKBHeader(input, byteOffset = 0) {
76
+ return inspectWKBHeaderView(getDataView(input), byteOffset);
77
+ }
78
+ function visitWKB(input, visitor, options = {}) {
79
+ const view = getDataView(input);
80
+ const state = {
81
+ maximumDepth: validateLimit(options.maximumDepth, 64, "maximumDepth"),
82
+ maximumElements: validateLimit(options.maximumElements, 1e8, "maximumElements"),
83
+ elementCount: 0,
84
+ visitor
85
+ };
86
+ const byteLength = visitGeometry(view, 0, state, 0).byteOffset;
87
+ if (byteLength !== view.byteLength)
88
+ throw new Error("WKB contains trailing bytes");
89
+ return byteLength;
90
+ }
91
+ function scanWKB(input, options = {}) {
92
+ const header = inspectWKBHeader(input);
93
+ const geometryCounts = {
94
+ Point: 0,
95
+ LineString: 0,
96
+ Polygon: 0,
97
+ MultiPoint: 0,
98
+ MultiLineString: 0,
99
+ MultiPolygon: 0,
100
+ GeometryCollection: 0
101
+ };
102
+ const geometryTypes = /* @__PURE__ */ new Set();
103
+ const bounds = {};
104
+ let coordinateCount = 0;
105
+ let ringCount = 0;
106
+ let geometryCount = 0;
107
+ let maximumDepth = 0;
108
+ const byteLength = visitWKB(input, {
109
+ geometry: (geometryHeader, _count, depth) => {
110
+ geometryCounts[geometryHeader.geometryType]++;
111
+ geometryTypes.add(geometryHeader.geometryType);
112
+ geometryCount++;
113
+ maximumDepth = Math.max(maximumDepth, depth);
114
+ },
115
+ ring: () => ringCount++,
116
+ coordinate: (x, y, z, m) => {
117
+ coordinateCount++;
118
+ updateBounds(bounds, "x", x);
119
+ updateBounds(bounds, "y", y);
120
+ if (z !== void 0)
121
+ updateBounds(bounds, "z", z);
122
+ if (m !== void 0)
123
+ updateBounds(bounds, "m", m);
124
+ }
125
+ }, options);
126
+ const concreteBounds = makeBounds(bounds);
127
+ return {
128
+ header,
129
+ byteLength,
130
+ coordinateCount,
131
+ ringCount,
132
+ geometryCount,
133
+ maximumDepth,
134
+ geometryTypes: GEOMETRY_TYPES.filter((type) => geometryTypes.has(type)),
135
+ geometryCounts,
136
+ ...concreteBounds ? { bounds: concreteBounds } : {}
137
+ };
138
+ }
139
+ function visitGeometry(view, byteOffset, state, depth, expectedType) {
140
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
141
+ if (depth > state.maximumDepth)
142
+ throw new Error("WKB geometry nesting exceeds maximumDepth");
143
+ const header = inspectWKBHeaderView(view, byteOffset);
144
+ if (expectedType && header.geometryType !== expectedType) {
145
+ throw new Error(`WKB ${expectedType} collection contains a ${header.geometryType} child`);
146
+ }
147
+ byteOffset = header.bodyByteOffset;
148
+ switch (header.geometryType) {
149
+ case "Point":
150
+ (_b = (_a = state.visitor).geometry) == null ? void 0 : _b.call(_a, header, void 0, depth);
151
+ byteOffset = visitCoordinate(view, byteOffset, header, state.visitor, depth);
152
+ break;
153
+ case "LineString": {
154
+ const pointCount = readCount(view, byteOffset, header.littleEndian, state);
155
+ byteOffset += 4;
156
+ (_d = (_c = state.visitor).geometry) == null ? void 0 : _d.call(_c, header, pointCount, depth);
157
+ byteOffset = visitCoordinateSequence(view, byteOffset, pointCount, header, state, depth);
158
+ break;
159
+ }
160
+ case "Polygon": {
161
+ const ringCount = readCount(view, byteOffset, header.littleEndian, state);
162
+ byteOffset += 4;
163
+ (_f = (_e = state.visitor).geometry) == null ? void 0 : _f.call(_e, header, ringCount, depth);
164
+ for (let ringIndex = 0; ringIndex < ringCount; ringIndex++) {
165
+ const pointCount = readCount(view, byteOffset, header.littleEndian, state);
166
+ byteOffset += 4;
167
+ (_h = (_g = state.visitor).ring) == null ? void 0 : _h.call(_g, pointCount, ringIndex, depth);
168
+ byteOffset = visitCoordinateSequence(view, byteOffset, pointCount, header, state, depth);
169
+ }
170
+ break;
171
+ }
172
+ case "MultiPoint":
173
+ case "MultiLineString":
174
+ case "MultiPolygon":
175
+ case "GeometryCollection": {
176
+ const childCount = readCount(view, byteOffset, header.littleEndian, state);
177
+ byteOffset += 4;
178
+ (_j = (_i = state.visitor).geometry) == null ? void 0 : _j.call(_i, header, childCount, depth);
179
+ const childType = header.geometryType === "MultiPoint" ? "Point" : header.geometryType === "MultiLineString" ? "LineString" : header.geometryType === "MultiPolygon" ? "Polygon" : void 0;
180
+ for (let childIndex = 0; childIndex < childCount; childIndex++) {
181
+ byteOffset = visitGeometry(view, byteOffset, state, depth + 1, childType).byteOffset;
182
+ }
183
+ break;
184
+ }
185
+ }
186
+ return { byteOffset, header };
187
+ }
188
+ function visitCoordinateSequence(view, byteOffset, pointCount, header, state, depth) {
189
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex++) {
190
+ byteOffset = visitCoordinate(view, byteOffset, header, state.visitor, depth);
191
+ }
192
+ return byteOffset;
193
+ }
194
+ function visitCoordinate(view, byteOffset, header, visitor, depth) {
195
+ var _a;
196
+ const coordinateByteLength = getWellKnownDimensionSize(header.dimension) * 8;
197
+ assertRemaining(view, byteOffset, coordinateByteLength);
198
+ const x = view.getFloat64(byteOffset, header.littleEndian);
199
+ const y = view.getFloat64(byteOffset + 8, header.littleEndian);
200
+ const third = header.dimension === "xy" ? void 0 : view.getFloat64(byteOffset + 16, header.littleEndian);
201
+ const fourth = header.dimension === "xyzm" ? view.getFloat64(byteOffset + 24, header.littleEndian) : void 0;
202
+ const z = header.dimension === "xyz" || header.dimension === "xyzm" ? third : void 0;
203
+ const m = header.dimension === "xym" ? third : fourth;
204
+ (_a = visitor.coordinate) == null ? void 0 : _a.call(visitor, x, y, z, m, header.dimension, byteOffset, depth);
205
+ return byteOffset + coordinateByteLength;
206
+ }
207
+ function inspectWKBHeaderView(view, byteOffset) {
208
+ const startByteOffset = byteOffset;
209
+ assertRemaining(view, byteOffset, 5);
210
+ const byteOrder = view.getUint8(byteOffset++);
211
+ if (byteOrder !== 0 && byteOrder !== 1)
212
+ throw new Error("Invalid WKB byte order");
213
+ const littleEndian = byteOrder === 1;
214
+ const typeCode = view.getUint32(byteOffset, littleEndian);
215
+ byteOffset += 4;
216
+ const hasZ = Boolean(typeCode & 2147483648);
217
+ const hasM = Boolean(typeCode & 1073741824);
218
+ const hasSrid = Boolean(typeCode & 536870912);
219
+ let geometryCode = typeCode & 536870911;
220
+ let dimension;
221
+ if (geometryCode >= 3e3 && geometryCode < 4e3) {
222
+ dimension = "xyzm";
223
+ geometryCode -= 3e3;
224
+ } else if (geometryCode >= 2e3 && geometryCode < 3e3) {
225
+ dimension = "xym";
226
+ geometryCode -= 2e3;
227
+ } else if (geometryCode >= 1e3 && geometryCode < 2e3) {
228
+ dimension = "xyz";
229
+ geometryCode -= 1e3;
230
+ } else {
231
+ dimension = hasZ && hasM ? "xyzm" : hasZ ? "xyz" : hasM ? "xym" : "xy";
232
+ }
233
+ const geometryType = GEOMETRY_TYPES[geometryCode - 1];
234
+ if (!geometryType)
235
+ throw new Error(`Unsupported WKB geometry type ${geometryCode}`);
236
+ let srid;
237
+ if (hasSrid) {
238
+ assertRemaining(view, byteOffset, 4);
239
+ srid = view.getUint32(byteOffset, littleEndian);
240
+ byteOffset += 4;
241
+ }
242
+ const dialect = hasZ || hasM || hasSrid ? "ewkb" : dimension === "xy" ? "wkb" : "iso-wkb";
243
+ return {
244
+ geometryType,
245
+ dimension,
246
+ dialect,
247
+ littleEndian,
248
+ byteOffset: startByteOffset,
249
+ bodyByteOffset: byteOffset,
250
+ byteLength: byteOffset - startByteOffset,
251
+ ...srid === void 0 ? {} : { srid }
252
+ };
253
+ }
254
+ function readCount(view, byteOffset, littleEndian, state) {
255
+ assertRemaining(view, byteOffset, 4);
256
+ const count = view.getUint32(byteOffset, littleEndian);
257
+ state.elementCount += count;
258
+ if (state.elementCount > state.maximumElements) {
259
+ throw new Error("WKB element count exceeds maximumElements");
260
+ }
261
+ return count;
262
+ }
263
+ function updateBounds(bounds, axis, value) {
264
+ if (!Number.isFinite(value))
265
+ return;
266
+ const minimum = `${axis}min`;
267
+ const maximum = `${axis}max`;
268
+ bounds[minimum] = bounds[minimum] === void 0 ? value : Math.min(bounds[minimum], value);
269
+ bounds[maximum] = bounds[maximum] === void 0 ? value : Math.max(bounds[maximum], value);
270
+ }
271
+ function makeBounds(bounds) {
272
+ if (bounds.xmin === void 0 || bounds.ymin === void 0 || bounds.xmax === void 0 || bounds.ymax === void 0) {
273
+ return void 0;
274
+ }
275
+ return bounds;
276
+ }
277
+ function getDataView(input) {
278
+ return ArrayBuffer.isView(input) ? new DataView(input.buffer, input.byteOffset, input.byteLength) : new DataView(input);
279
+ }
280
+ function assertRemaining(view, byteOffset, byteLength) {
281
+ if (byteOffset < 0 || byteOffset + byteLength > view.byteLength) {
282
+ throw new Error("Unexpected end of WKB");
283
+ }
284
+ }
285
+ function validateLimit(value, fallback, name) {
286
+ const limit = value ?? fallback;
287
+ if (!Number.isSafeInteger(limit) || limit < 0) {
288
+ throw new Error(`${name} must be a non-negative safe integer`);
289
+ }
290
+ return limit;
291
+ }
292
+
293
+ // dist/wkb.js
294
+ function parseWKB(bytes, options = {}) {
295
+ const state = {
296
+ maximumDepth: validateLimit2(options.maximumDepth, 64, "maximumDepth"),
297
+ maximumElements: validateLimit2(options.maximumElements, 1e8, "maximumElements"),
298
+ elementCount: 0
299
+ };
300
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
301
+ const result = readWKBGeometry(view, 0, state, 0);
302
+ if (result.offset !== bytes.byteLength)
303
+ throw new Error("WKB contains trailing bytes");
304
+ return {
305
+ geometry: result.geometry,
306
+ byteLength: result.offset,
307
+ dimension: result.dimension,
308
+ ...result.srid === void 0 ? {} : { srid: result.srid }
309
+ };
310
+ }
311
+ function writeWKB(geometry, dimension = inferWellKnownGeometryDimension(geometry)) {
312
+ const bytes = [];
313
+ writeWKBGeometry(bytes, geometry, dimension);
314
+ return Uint8Array.from(bytes);
315
+ }
316
+ function readWKBGeometry(view, startOffset, state, depth) {
317
+ if (depth > state.maximumDepth)
318
+ throw new Error("WKB geometry nesting exceeds maximumDepth");
319
+ const header = inspectWKBHeader(view, startOffset);
320
+ let offset = header.bodyByteOffset;
321
+ const { dimension, geometryType, littleEndian, srid } = header;
322
+ const dimensions = getWellKnownDimensionSize(dimension);
323
+ const readCoordinate = () => {
324
+ assertRemaining2(view, offset, dimensions * 8);
325
+ const coordinate = new Array(dimensions);
326
+ for (let index = 0; index < dimensions; index++) {
327
+ coordinate[index] = view.getFloat64(offset, littleEndian);
328
+ offset += 8;
329
+ }
330
+ return coordinate;
331
+ };
332
+ const readCount2 = () => {
333
+ assertRemaining2(view, offset, 4);
334
+ const count = view.getUint32(offset, littleEndian);
335
+ offset += 4;
336
+ state.elementCount += count;
337
+ if (state.elementCount > state.maximumElements) {
338
+ throw new Error("WKB element count exceeds maximumElements");
339
+ }
340
+ return count;
341
+ };
342
+ const readCoordinates = () => {
343
+ const count = readCount2();
344
+ return Array.from({ length: count }, readCoordinate);
345
+ };
346
+ let geometry;
347
+ switch (geometryType) {
348
+ case "Point":
349
+ geometry = { type: "Point", coordinates: readCoordinate() };
350
+ break;
351
+ case "LineString":
352
+ geometry = { type: "LineString", coordinates: readCoordinates() };
353
+ break;
354
+ case "Polygon":
355
+ geometry = { type: "Polygon", coordinates: Array.from({ length: readCount2() }, readCoordinates) };
356
+ break;
357
+ case "MultiPoint":
358
+ case "MultiLineString":
359
+ case "MultiPolygon":
360
+ case "GeometryCollection": {
361
+ const children = [];
362
+ for (let index = 0, count = readCount2(); index < count; index++) {
363
+ const child = readWKBGeometry(view, offset, state, depth + 1);
364
+ children.push(child.geometry);
365
+ offset = child.offset;
366
+ }
367
+ if (geometryType === "MultiPoint") {
368
+ geometry = {
369
+ type: "MultiPoint",
370
+ coordinates: children.map(assertPoint).map((point) => point.coordinates)
371
+ };
372
+ } else if (geometryType === "MultiLineString") {
373
+ geometry = {
374
+ type: "MultiLineString",
375
+ coordinates: children.map(assertLineString).map((line) => line.coordinates)
376
+ };
377
+ } else if (geometryType === "MultiPolygon") {
378
+ geometry = {
379
+ type: "MultiPolygon",
380
+ coordinates: children.map(assertPolygon).map((polygon) => polygon.coordinates)
381
+ };
382
+ } else {
383
+ geometry = { type: "GeometryCollection", geometries: children };
384
+ }
385
+ break;
386
+ }
387
+ }
388
+ return { geometry, offset, dimension, ...srid === void 0 ? {} : { srid } };
389
+ }
390
+ function writeWKBGeometry(bytes, geometry, dimension) {
391
+ bytes.push(1);
392
+ const size = getWellKnownDimensionSize(dimension);
393
+ const dimensionOffset = dimension === "xyz" ? 1e3 : dimension === "xym" ? 2e3 : dimension === "xyzm" ? 3e3 : 0;
394
+ writeUint32(bytes, getWKBType(geometry.type) + dimensionOffset);
395
+ const writeCoordinate = (coordinate) => {
396
+ for (let index = 0; index < size; index++)
397
+ writeFloat64(bytes, coordinate[index] ?? 0);
398
+ };
399
+ const writeCoordinates = (coordinates) => {
400
+ writeUint32(bytes, coordinates.length);
401
+ for (const coordinate of coordinates)
402
+ writeCoordinate(coordinate);
403
+ };
404
+ switch (geometry.type) {
405
+ case "Point":
406
+ writeCoordinate(geometry.coordinates);
407
+ break;
408
+ case "LineString":
409
+ writeCoordinates(geometry.coordinates);
410
+ break;
411
+ case "Polygon":
412
+ writeUint32(bytes, geometry.coordinates.length);
413
+ for (const ring of geometry.coordinates)
414
+ writeCoordinates(ring);
415
+ break;
416
+ case "MultiPoint":
417
+ writeUint32(bytes, geometry.coordinates.length);
418
+ for (const coordinate of geometry.coordinates) {
419
+ writeWKBGeometry(bytes, { type: "Point", coordinates: coordinate }, dimension);
420
+ }
421
+ break;
422
+ case "MultiLineString":
423
+ writeUint32(bytes, geometry.coordinates.length);
424
+ for (const coordinates of geometry.coordinates) {
425
+ writeWKBGeometry(bytes, { type: "LineString", coordinates }, dimension);
426
+ }
427
+ break;
428
+ case "MultiPolygon":
429
+ writeUint32(bytes, geometry.coordinates.length);
430
+ for (const coordinates of geometry.coordinates) {
431
+ writeWKBGeometry(bytes, { type: "Polygon", coordinates }, dimension);
432
+ }
433
+ break;
434
+ case "GeometryCollection":
435
+ writeUint32(bytes, geometry.geometries.length);
436
+ for (const child of geometry.geometries)
437
+ writeWKBGeometry(bytes, child, dimension);
438
+ break;
439
+ }
440
+ }
441
+ function getWKBType(type) {
442
+ return [
443
+ "Point",
444
+ "LineString",
445
+ "Polygon",
446
+ "MultiPoint",
447
+ "MultiLineString",
448
+ "MultiPolygon",
449
+ "GeometryCollection"
450
+ ].indexOf(type) + 1;
451
+ }
452
+ function writeUint32(bytes, value) {
453
+ bytes.push(value & 255, value >>> 8 & 255, value >>> 16 & 255, value >>> 24 & 255);
454
+ }
455
+ function writeFloat64(bytes, value) {
456
+ const buffer = new ArrayBuffer(8);
457
+ new DataView(buffer).setFloat64(0, value, true);
458
+ bytes.push(...new Uint8Array(buffer));
459
+ }
460
+ function assertRemaining2(view, offset, length) {
461
+ if (offset + length > view.byteLength)
462
+ throw new Error("Unexpected end of WKB");
463
+ }
464
+ function assertPoint(value) {
465
+ if (value.type !== "Point")
466
+ throw new Error("WKB MultiPoint contains a non-Point child");
467
+ return value;
468
+ }
469
+ function assertLineString(value) {
470
+ if (value.type !== "LineString") {
471
+ throw new Error("WKB MultiLineString contains a non-LineString child");
472
+ }
473
+ return value;
474
+ }
475
+ function assertPolygon(value) {
476
+ if (value.type !== "Polygon")
477
+ throw new Error("WKB MultiPolygon contains a non-Polygon child");
478
+ return value;
479
+ }
480
+ function validateLimit2(value, fallback, name) {
481
+ const limit = value ?? fallback;
482
+ if (!Number.isSafeInteger(limit) || limit < 0) {
483
+ throw new Error(`${name} must be a non-negative safe integer`);
484
+ }
485
+ return limit;
486
+ }
487
+
488
+ // dist/wkb-builder.js
489
+ var GEOMETRY_TYPE_CODES = {
490
+ Point: 1,
491
+ LineString: 2,
492
+ Polygon: 3,
493
+ MultiPoint: 4,
494
+ MultiLineString: 5,
495
+ MultiPolygon: 6,
496
+ GeometryCollection: 7
497
+ };
498
+ var WKBBuilder = class _WKBBuilder {
499
+ constructor(options) {
500
+ this.mode = options.mode;
501
+ this.dimension = options.dimension ?? "xy";
502
+ this.littleEndian = options.byteOrder !== "big-endian";
503
+ this.srid = options.srid;
504
+ this.transform = options.transform;
505
+ validateSrid(this.srid);
506
+ if (options.mode === "write") {
507
+ const dataView = getTargetDataView(options.target);
508
+ const byteOffset = options.byteOffset ?? 0;
509
+ if (!Number.isSafeInteger(byteOffset) || byteOffset < 0 || byteOffset > dataView.byteLength) {
510
+ throw new Error("WKBBuilder byteOffset is outside the target");
511
+ }
512
+ this.dataView = dataView;
513
+ this.startByteOffset = byteOffset;
514
+ this.endByteOffset = dataView.byteLength;
515
+ this.byteOffset = byteOffset;
516
+ } else {
517
+ this.dataView = null;
518
+ this.startByteOffset = 0;
519
+ this.endByteOffset = Number.POSITIVE_INFINITY;
520
+ this.byteOffset = 0;
521
+ }
522
+ }
523
+ /** Begins a geometry and writes its count field when required. */
524
+ beginGeometry(type, count) {
525
+ switch (type) {
526
+ case "Point":
527
+ this.beginPoint();
528
+ break;
529
+ case "LineString":
530
+ this.beginLineString(count ?? 0);
531
+ break;
532
+ case "Polygon":
533
+ this.beginPolygon(count ?? 0);
534
+ break;
535
+ case "MultiPoint":
536
+ this.beginMultiPoint(count ?? 0);
537
+ break;
538
+ case "MultiLineString":
539
+ this.beginMultiLineString(count ?? 0);
540
+ break;
541
+ case "MultiPolygon":
542
+ this.beginMultiPolygon(count ?? 0);
543
+ break;
544
+ case "GeometryCollection":
545
+ this.writeHeader("GeometryCollection");
546
+ this.writeUint32(count ?? 0);
547
+ break;
548
+ }
549
+ }
550
+ /** Begins one point geometry. */
551
+ beginPoint() {
552
+ this.writeHeader("Point");
553
+ }
554
+ /** Begins one linestring geometry. */
555
+ beginLineString(pointCount) {
556
+ this.writeHeader("LineString");
557
+ this.writeUint32(pointCount);
558
+ }
559
+ /** Begins one polygon geometry. */
560
+ beginPolygon(ringCount) {
561
+ this.writeHeader("Polygon");
562
+ this.writeUint32(ringCount);
563
+ }
564
+ /** Begins one linear ring inside a polygon. */
565
+ beginLinearRing(pointCount) {
566
+ this.writeUint32(pointCount);
567
+ }
568
+ /** Begins one multipoint geometry. */
569
+ beginMultiPoint(pointCount) {
570
+ this.writeHeader("MultiPoint");
571
+ this.writeUint32(pointCount);
572
+ }
573
+ /** Begins one multilinestring geometry. */
574
+ beginMultiLineString(lineCount) {
575
+ this.writeHeader("MultiLineString");
576
+ this.writeUint32(lineCount);
577
+ }
578
+ /** Begins one multipolygon geometry. */
579
+ beginMultiPolygon(polygonCount) {
580
+ this.writeHeader("MultiPolygon");
581
+ this.writeUint32(polygonCount);
582
+ }
583
+ /** Writes one coordinate using the builder's semantic dimension. */
584
+ writeCoordinate(x, y, z, m) {
585
+ let coordinate = makeCoordinate(this.dimension, x, y, z, m);
586
+ if (this.transform)
587
+ coordinate = this.transform(coordinate, this.dimension);
588
+ const coordinateSize = getDimensionSize(this.dimension);
589
+ for (let index = 0; index < coordinateSize; index++) {
590
+ this.writeFloat64(coordinate[index] ?? Number.NaN);
591
+ }
592
+ }
593
+ /** Returns the number of bytes measured or written. */
594
+ finishGeometry() {
595
+ return this.byteOffset - this.startByteOffset;
596
+ }
597
+ /** Measures geometry callbacks and returns contiguous Binary offsets. */
598
+ static measureGeometryArray(geometryWriters, options = {}) {
599
+ const valueOffsets = new Int32Array(geometryWriters.length + 1);
600
+ for (let geometryIndex = 0; geometryIndex < geometryWriters.length; geometryIndex++) {
601
+ const geometryWriter = geometryWriters[geometryIndex];
602
+ const byteLength = geometryWriter ? measureGeometry(geometryWriter, options) : 0;
603
+ const nextOffset = valueOffsets[geometryIndex] + byteLength;
604
+ if (nextOffset > 2147483647)
605
+ throw new Error("WKB geometry array exceeds Int32 offsets");
606
+ valueOffsets[geometryIndex + 1] = nextOffset;
607
+ }
608
+ return valueOffsets;
609
+ }
610
+ /** Writes geometry callbacks into an existing contiguous values buffer. */
611
+ static writeGeometryArray(geometryWriters, valueOffsets, values, options = {}) {
612
+ if (valueOffsets.length !== geometryWriters.length + 1) {
613
+ throw new Error("WKB valueOffsets length must equal geometry count plus one");
614
+ }
615
+ if (valueOffsets[valueOffsets.length - 1] > values.byteLength) {
616
+ throw new Error("WKB values buffer is smaller than its final offset");
617
+ }
618
+ for (let geometryIndex = 0; geometryIndex < geometryWriters.length; geometryIndex++) {
619
+ const geometryWriter = geometryWriters[geometryIndex];
620
+ if (!geometryWriter)
621
+ continue;
622
+ const builder = new _WKBBuilder({
623
+ mode: "write",
624
+ target: values,
625
+ byteOffset: valueOffsets[geometryIndex],
626
+ ...options
627
+ });
628
+ geometryWriter(builder);
629
+ const byteLength = builder.finishGeometry();
630
+ if (valueOffsets[geometryIndex] + byteLength !== valueOffsets[geometryIndex + 1]) {
631
+ throw new Error("WKB measure and write passes produced different byte lengths");
632
+ }
633
+ }
634
+ return values;
635
+ }
636
+ /** Builds plain offsets, values, and validity buffers in two passes. */
637
+ static buildGeometryArray(geometryWriters, options = {}) {
638
+ const valueOffsets = _WKBBuilder.measureGeometryArray(geometryWriters, options);
639
+ const values = new Uint8Array(valueOffsets[valueOffsets.length - 1]);
640
+ _WKBBuilder.writeGeometryArray(geometryWriters, valueOffsets, values, options);
641
+ const { nullBitmap, nullCount } = makeNullBitmap(geometryWriters);
642
+ return {
643
+ valueOffsets,
644
+ values,
645
+ ...nullCount > 0 ? { nullBitmap } : {},
646
+ nullCount
647
+ };
648
+ }
649
+ writeHeader(geometryType) {
650
+ this.writeUint8(this.littleEndian ? 1 : 0);
651
+ this.writeUint32(getWKBTypeCode(geometryType, this.dimension, this.srid !== void 0));
652
+ if (this.srid !== void 0)
653
+ this.writeUint32(this.srid);
654
+ }
655
+ writeUint8(value) {
656
+ var _a;
657
+ this.ensureSize(1);
658
+ (_a = this.dataView) == null ? void 0 : _a.setUint8(this.byteOffset, value);
659
+ this.byteOffset++;
660
+ }
661
+ writeUint32(value) {
662
+ var _a;
663
+ if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) {
664
+ throw new Error("WKB count must be an unsigned 32-bit integer");
665
+ }
666
+ this.ensureSize(4);
667
+ (_a = this.dataView) == null ? void 0 : _a.setUint32(this.byteOffset, value, this.littleEndian);
668
+ this.byteOffset += 4;
669
+ }
670
+ writeFloat64(value) {
671
+ var _a;
672
+ this.ensureSize(8);
673
+ (_a = this.dataView) == null ? void 0 : _a.setFloat64(this.byteOffset, value, this.littleEndian);
674
+ this.byteOffset += 8;
675
+ }
676
+ ensureSize(byteLength) {
677
+ if (this.byteOffset + byteLength > this.endByteOffset) {
678
+ throw new Error("WKBBuilder target buffer overflow");
679
+ }
680
+ }
681
+ };
682
+ function measureGeometry(geometryWriter, options) {
683
+ const builder = new WKBBuilder({ mode: "measure", ...options });
684
+ geometryWriter(builder);
685
+ return builder.finishGeometry();
686
+ }
687
+ function getTargetDataView(target) {
688
+ return ArrayBuffer.isView(target) ? new DataView(target.buffer, target.byteOffset, target.byteLength) : new DataView(target);
689
+ }
690
+ function getWKBTypeCode(geometryType, dimension, hasSrid) {
691
+ const geometryCode = GEOMETRY_TYPE_CODES[geometryType];
692
+ if (hasSrid) {
693
+ const dimensionFlags = dimension === "xyz" ? 2147483648 : dimension === "xym" ? 1073741824 : dimension === "xyzm" ? 3221225472 : 0;
694
+ return (geometryCode | dimensionFlags | 536870912) >>> 0;
695
+ }
696
+ const dimensionOffset = dimension === "xyz" ? 1e3 : dimension === "xym" ? 2e3 : dimension === "xyzm" ? 3e3 : 0;
697
+ return geometryCode + dimensionOffset;
698
+ }
699
+ function makeCoordinate(dimension, x, y, z, m) {
700
+ switch (dimension) {
701
+ case "xy":
702
+ return [x, y];
703
+ case "xyz":
704
+ return [x, y, z ?? Number.NaN];
705
+ case "xym":
706
+ return [x, y, m ?? Number.NaN];
707
+ case "xyzm":
708
+ return [x, y, z ?? Number.NaN, m ?? Number.NaN];
709
+ }
710
+ }
711
+ function getDimensionSize(dimension) {
712
+ return dimension === "xy" ? 2 : dimension === "xyzm" ? 4 : 3;
713
+ }
714
+ function validateSrid(srid) {
715
+ if (srid !== void 0 && (!Number.isSafeInteger(srid) || srid < 0 || srid > 4294967295)) {
716
+ throw new Error("WKBBuilder srid must be an unsigned 32-bit integer");
717
+ }
718
+ }
719
+ function makeNullBitmap(geometryWriters) {
720
+ const nullBitmap = new Uint8Array(Math.ceil(geometryWriters.length / 8));
721
+ let nullCount = 0;
722
+ for (let geometryIndex = 0; geometryIndex < geometryWriters.length; geometryIndex++) {
723
+ if (geometryWriters[geometryIndex]) {
724
+ nullBitmap[geometryIndex >> 3] |= 1 << (geometryIndex & 7);
725
+ } else {
726
+ nullCount++;
727
+ }
728
+ }
729
+ return { nullBitmap, nullCount };
730
+ }
731
+
732
+ // dist/wkt.js
733
+ function parseWKT(text) {
734
+ const parser = new WKTParser(text);
735
+ const geometry = parser.parseGeometry(2);
736
+ parser.assertComplete();
737
+ return geometry;
738
+ }
739
+ function formatWKT(geometry, dimension = inferWellKnownGeometryDimension(geometry)) {
740
+ const dimensionToken = dimension === "xy" ? "" : ` ${dimension.slice(2).toUpperCase()}`;
741
+ if (geometry.type === "GeometryCollection") {
742
+ if (geometry.geometries.length === 0)
743
+ return `GEOMETRYCOLLECTION${dimensionToken} EMPTY`;
744
+ return `GEOMETRYCOLLECTION${dimensionToken} (${geometry.geometries.map((child) => formatWKT(child, dimension)).join(", ")})`;
745
+ }
746
+ const type = geometry.type.toUpperCase();
747
+ if (isEmptyCoordinates(geometry.coordinates))
748
+ return `${type}${dimensionToken} EMPTY`;
749
+ return `${type}${dimensionToken} ${formatCoordinateNesting(geometry.coordinates, getGeometryDepth(geometry.type))}`;
750
+ }
751
+ var WKTParser = class {
752
+ constructor(text) {
753
+ this.index = 0;
754
+ this.tokens = tokenizeWKT(text);
755
+ }
756
+ parseGeometry(inheritedDimensionSize) {
757
+ const type = this.takeWord().toUpperCase();
758
+ let dimensionSize = inheritedDimensionSize;
759
+ if (["Z", "M", "ZM"].includes(this.peek().toUpperCase())) {
760
+ const dimension = this.take().toUpperCase();
761
+ dimensionSize = dimension === "ZM" ? 4 : 3;
762
+ }
763
+ if (this.peek().toUpperCase() === "EMPTY") {
764
+ this.take();
765
+ return makeEmptyGeometry(type, dimensionSize);
766
+ }
767
+ if (type === "GEOMETRYCOLLECTION") {
768
+ this.expect("(");
769
+ const geometries = [];
770
+ if (this.peek() !== ")") {
771
+ do
772
+ geometries.push(this.parseGeometry(dimensionSize));
773
+ while (this.takeIf(","));
774
+ }
775
+ this.expect(")");
776
+ return { type: "GeometryCollection", geometries };
777
+ }
778
+ const coordinates = this.parseCoordinateNesting(getWKTDepth(type), dimensionSize);
779
+ return makeGeometry(type, coordinates);
780
+ }
781
+ assertComplete() {
782
+ if (this.index !== this.tokens.length)
783
+ throw new Error(`Unexpected WKT token ${this.peek()}`);
784
+ }
785
+ parseCoordinateNesting(depth, dimensionSize) {
786
+ this.expect("(");
787
+ if (depth === 0) {
788
+ const coordinate = this.readCoordinate(dimensionSize);
789
+ this.expect(")");
790
+ return coordinate;
791
+ }
792
+ const values = [];
793
+ if (this.peek() !== ")") {
794
+ do {
795
+ if (depth === 1 && this.peek() !== "(") {
796
+ values.push(this.readCoordinate(dimensionSize));
797
+ } else {
798
+ values.push(this.parseCoordinateNesting(depth - 1, dimensionSize));
799
+ }
800
+ } while (this.takeIf(","));
801
+ }
802
+ this.expect(")");
803
+ return values;
804
+ }
805
+ readCoordinate(dimensionSize) {
806
+ const values = [];
807
+ while (values.length < dimensionSize && isNumberToken(this.peek())) {
808
+ values.push(Number(this.take()));
809
+ }
810
+ if (values.length < 2)
811
+ throw new Error("WKT coordinate requires at least two numbers");
812
+ return values;
813
+ }
814
+ peek() {
815
+ return this.tokens[this.index] || "";
816
+ }
817
+ take() {
818
+ if (this.index >= this.tokens.length)
819
+ throw new Error("Unexpected end of WKT");
820
+ return this.tokens[this.index++];
821
+ }
822
+ takeWord() {
823
+ const token = this.take();
824
+ if (!/^[A-Za-z_]+$/.test(token))
825
+ throw new Error(`Expected WKT geometry type, found ${token}`);
826
+ return token;
827
+ }
828
+ takeIf(token) {
829
+ if (this.peek() !== token)
830
+ return false;
831
+ this.index++;
832
+ return true;
833
+ }
834
+ expect(token) {
835
+ const actual = this.take();
836
+ if (actual !== token)
837
+ throw new Error(`Expected WKT token ${token}, found ${actual}`);
838
+ }
839
+ };
840
+ function tokenizeWKT(text) {
841
+ const tokens = [];
842
+ const tokenPattern = /[A-Za-z_]+|[(),]|[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/gy;
843
+ let index = 0;
844
+ while (index < text.length) {
845
+ while (index < text.length && /\s/.test(text[index]))
846
+ index++;
847
+ if (index === text.length)
848
+ break;
849
+ tokenPattern.lastIndex = index;
850
+ const match = tokenPattern.exec(text);
851
+ if (!match) {
852
+ throw new Error(`Unexpected WKT character ${JSON.stringify(text[index])} at ${index}`);
853
+ }
854
+ tokens.push(match[0]);
855
+ index = tokenPattern.lastIndex;
856
+ }
857
+ return tokens;
858
+ }
859
+ function formatCoordinateNesting(value, depth) {
860
+ if (depth === 0)
861
+ return `(${value.map(formatNumber).join(" ")})`;
862
+ return `(${value.map((child) => {
863
+ if (depth === 1)
864
+ return child.map(formatNumber).join(" ");
865
+ return formatCoordinateNesting(child, depth - 1);
866
+ }).join(", ")})`;
867
+ }
868
+ function formatNumber(value) {
869
+ if (!Number.isFinite(value))
870
+ return "NaN";
871
+ return String(value);
872
+ }
873
+ function getGeometryDepth(type) {
874
+ switch (type) {
875
+ case "Point":
876
+ return 0;
877
+ case "LineString":
878
+ case "MultiPoint":
879
+ return 1;
880
+ case "Polygon":
881
+ case "MultiLineString":
882
+ return 2;
883
+ case "MultiPolygon":
884
+ return 3;
885
+ }
886
+ }
887
+ function getWKTDepth(type) {
888
+ switch (type) {
889
+ case "POINT":
890
+ return 0;
891
+ case "LINESTRING":
892
+ return 1;
893
+ case "POLYGON":
894
+ return 2;
895
+ case "MULTIPOINT":
896
+ return 1;
897
+ case "MULTILINESTRING":
898
+ return 2;
899
+ case "MULTIPOLYGON":
900
+ return 3;
901
+ default:
902
+ throw new Error(`Unsupported WKT geometry type ${type}`);
903
+ }
904
+ }
905
+ function makeGeometry(type, coordinates) {
906
+ const canonical = type[0] + type.slice(1).toLowerCase();
907
+ const names = {
908
+ Point: "Point",
909
+ Linestring: "LineString",
910
+ Polygon: "Polygon",
911
+ Multipoint: "MultiPoint",
912
+ Multilinestring: "MultiLineString",
913
+ Multipolygon: "MultiPolygon"
914
+ };
915
+ const geometryType = names[canonical];
916
+ if (!geometryType)
917
+ throw new Error(`Unsupported WKT geometry type ${type}`);
918
+ return { type: geometryType, coordinates };
919
+ }
920
+ function makeEmptyGeometry(type, dimensionSize) {
921
+ if (type === "GEOMETRYCOLLECTION")
922
+ return { type: "GeometryCollection", geometries: [] };
923
+ if (type === "POINT") {
924
+ return {
925
+ type: "Point",
926
+ coordinates: new Array(getValidDimensionSize(dimensionSize)).fill(Number.NaN)
927
+ };
928
+ }
929
+ return makeGeometry(type, []);
930
+ }
931
+ function getValidDimensionSize(size) {
932
+ if (size === 2 || size === 3 || size === 4)
933
+ return size;
934
+ return getWellKnownDimensionSize("xy");
935
+ }
936
+ function isEmptyCoordinates(value) {
937
+ if (value.length === 0)
938
+ return true;
939
+ if (typeof value[0] === "number") {
940
+ return value.every((component) => !Number.isFinite(component));
941
+ }
942
+ return value.every((child) => isEmptyCoordinates(child));
943
+ }
944
+ function isNumberToken(token) {
945
+ return token !== "" && Number.isFinite(Number(token));
946
+ }
947
+ //# sourceMappingURL=index.cjs.map