maplibre-gl-raster 0.2.0 → 0.2.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.
@@ -5,2132 +5,2184 @@ import { CompositeLayer, _GlobeViewport, assert } from "@deck.gl/core";
5
5
  import { SimpleMeshLayer } from "@deck.gl/mesh-layers";
6
6
  import { TileLayer, _Tileset2D } from "@deck.gl/geo-layers";
7
7
  import { Popup } from "maplibre-gl";
8
- //#region node_modules/@developmentseed/deck.gl-raster/dist/layer-utils.js
9
- function renderDebugTileOutline(id, tile, forwardTo4326) {
10
- const { projectedCorners } = tile;
11
- const { topLeft, topRight, bottomRight, bottomLeft } = projectedCorners;
12
- const topLeftWgs84 = forwardTo4326(topLeft[0], topLeft[1]);
13
- const topRightWgs84 = forwardTo4326(topRight[0], topRight[1]);
14
- const bottomRightWgs84 = forwardTo4326(bottomRight[0], bottomRight[1]);
15
- const path = [
16
- topLeftWgs84,
17
- topRightWgs84,
18
- bottomRightWgs84,
19
- forwardTo4326(bottomLeft[0], bottomLeft[1]),
20
- topLeftWgs84
21
- ];
22
- const center = [(topLeftWgs84[0] + bottomRightWgs84[0]) / 2, (topLeftWgs84[1] + bottomRightWgs84[1]) / 2];
23
- const labelLayer = new TextLayer({
24
- id: `${id}-label`,
25
- data: [{
26
- position: center,
27
- text: `x=${tile.index.x} y=${tile.index.y} z=${tile.index.z}`
28
- }],
29
- getColor: [
30
- 255,
31
- 255,
32
- 255,
33
- 255
34
- ],
35
- getSize: 24,
36
- sizeUnits: "pixels",
37
- outlineWidth: 3,
38
- outlineColor: [
39
- 0,
40
- 0,
41
- 0,
42
- 255
43
- ],
44
- fontSettings: { sdf: true }
45
- });
46
- return [new PathLayer({
47
- id,
48
- data: [path],
49
- getPath: (d) => d,
50
- getColor: [
51
- 255,
52
- 0,
53
- 0,
54
- 255
55
- ],
56
- getWidth: 2,
57
- widthUnits: "pixels",
58
- pickable: false
59
- }), labelLayer];
60
- }
61
- //#endregion
62
- //#region node_modules/@developmentseed/raster-reproject/dist/delatin.js
8
+ //#region node_modules/@developmentseed/proj/dist/meters-per-unit.js
63
9
  /**
64
- * Define [**uv coordinates**](https://en.wikipedia.org/wiki/UV_mapping) as a float-valued image-local coordinate space where the top left is `(0, 0)` and the bottom right is `(1, 1)`.
65
- *
66
- * Define [**Barycentric coordinates**](https://en.wikipedia.org/wiki/Barycentric_coordinate_system) as float-valued triangle-local coordinates, represented as a 3-tuple of floats, where the tuple must add up to 1. The coordinate represents "how close to each vertex" a point in the interior of a triangle is. I.e. `(0, 0, 1)`, `(0, 1, 0)`, and `(1, 0, 0)` are all valid barycentric coordinates that define one of the three vertices. `(1/3, 1/3, 1/3)` represents the centroid of a triangle. `(1/2, 1/2, 0)` represents a point that is halfway between vertices `a` and `b` and has "none" of vertex `c`.
67
- *
68
- *
69
- * ## Changes
10
+ * Coefficient to convert the coordinate reference system (CRS)
11
+ * units into meters (metersPerUnit).
70
12
  *
71
- * - Delatin coordinates are in terms of pixel space whereas here we use uv space.
13
+ * From note g in http://docs.opengeospatial.org/is/17-083r2/17-083r2.html#table_2:
72
14
  *
73
- * Originally copied from https://github.com/mapbox/delatin under the ISC
74
- * license, then subject to further modifications.
75
- */
76
- /**
77
- * Barycentric sample points in uv space for where to sample reprojection
78
- * errors.
79
- */
80
- var SAMPLE_POINTS = [
81
- [
82
- 1 / 3,
83
- 1 / 3,
84
- 1 / 3
85
- ],
86
- [
87
- .5,
88
- .5,
89
- 0
90
- ],
91
- [
92
- .5,
93
- 0,
94
- .5
95
- ],
96
- [
97
- 0,
98
- .5,
99
- .5
100
- ]
101
- ];
102
- var DEFAULT_MAX_ERROR$1 = .125;
103
- /**
104
- * RasterReprojector performs a Delaunay triangulation-based reprojection of a
105
- * raster image.
15
+ * > If the CRS uses meters as units of measure for the horizontal dimensions,
16
+ * > then metersPerUnit=1; if it has degrees, then metersPerUnit=2pa/360
17
+ * > (a is the Earth maximum radius of the ellipsoid).
106
18
  *
107
- * It takes as input a set of functions to associate pixel positions with
108
- * coordinates in the input and output CRS, as well as the dimensions of the
109
- * output image, and it produces a triangulated mesh that can be used to
110
- * reproject the input raster onto the output raster with bounded error.
19
+ * @param unit - The unit of the CRS.
20
+ * @param semiMajorAxis - The semi-major axis of the ellipsoid, required if unit is 'degree'.
21
+ * @returns The meters per unit conversion factor.
111
22
  */
112
- var RasterReprojector = class {
113
- reprojectors;
114
- /** Width of the image in pixels */
115
- width;
116
- /** Height of the image in pixels */
117
- height;
118
- /**
119
- * UV vertex coordinates (x, y), i.e.
120
- * [x0, y0, x1, y1, ...]
121
- *
122
- * These coordinates are floats that range from [0, 1] in both X and Y.
123
- */
124
- uvs;
125
- /**
126
- * XY Positions in output CRS, computed via exact forward reprojection.
127
- */
128
- exactOutputPositions;
129
- /**
130
- * triangle vertex indices
131
- */
132
- triangles;
133
- _halfedges;
134
- /**
135
- * The UV texture coordinates of candidates found from
136
- * `findReprojectionCandidate`.
137
- *
138
- * Maybe in the future we'll want to store the barycentric coordinates instead
139
- * of just the uv coordinates?
140
- */
141
- _candidatesUV;
142
- _queueIndices;
143
- _queue;
144
- _errors;
145
- _pending;
146
- _pendingLen;
147
- constructor(reprojectors, width, height = width) {
148
- this.reprojectors = reprojectors;
149
- this.width = width;
150
- this.height = height;
151
- this.uvs = [];
152
- this.exactOutputPositions = [];
153
- this.triangles = [];
154
- this._halfedges = [];
155
- this._candidatesUV = [];
156
- this._queueIndices = [];
157
- this._queue = [];
158
- this._errors = [];
159
- this._pending = [];
160
- this._pendingLen = 0;
161
- const u1 = 1;
162
- const v1 = 1;
163
- const p0 = this._addPoint(0, 0);
164
- const p1 = this._addPoint(u1, 0);
165
- const p2 = this._addPoint(0, v1);
166
- const p3 = this._addPoint(u1, v1);
167
- const t0 = this._addTriangle(p3, p0, p2, -1, -1, -1);
168
- this._addTriangle(p0, p3, p1, t0, -1, -1);
169
- this._flush();
170
- }
171
- /**
172
- * Refine the mesh until its maximum error gets below the given one
173
- *
174
- * @param maxError The maximum reprojection error in input pixels that the mesh should achieve.
175
- * @param maxIterations Optional safeguard to prevent infinite loops in case of non-convergence. If the mesh fails to converge within this number of iterations, a warning will be logged and the function will return early.
176
- *
177
- * @return {[type]} [return description]
178
- */
179
- run(maxError = DEFAULT_MAX_ERROR$1, { maxIterations = 1e4 } = {}) {
180
- if (maxError <= 0) throw new Error("maxError must be positive");
181
- let iterations = 0;
182
- while (this.getMaxError() > maxError) {
183
- this.refine();
184
- if (++iterations > maxIterations) {
185
- console.warn(`RasterReprojector: mesh refinement did not converge after ${iterations} iterations (maxError=${maxError}, currentError=${this.getMaxError()})`);
186
- break;
187
- }
188
- }
23
+ function metersPerUnit(unit, { semiMajorAxis } = {}) {
24
+ unit = unit.toLowerCase();
25
+ switch (unit) {
26
+ case "m":
27
+ case "metre":
28
+ case "meter":
29
+ case "meters": return 1;
30
+ case "foot": return .3048;
31
+ case "us survey foot": return 1200 / 3937;
189
32
  }
190
- refine() {
191
- this._step();
192
- this._flush();
33
+ if (unit === "degree") {
34
+ if (semiMajorAxis === void 0) throw new Error("CRS with degrees unit requires ellipsoid semi-major-axis");
35
+ return 2 * Math.PI * semiMajorAxis / 360;
193
36
  }
194
- getMaxError() {
195
- return this._errors[0];
37
+ throw new Error(`Unsupported CRS units: ${unit} when computing metersPerUnit.`);
38
+ }
39
+ //#endregion
40
+ //#region node_modules/wkt-parser/PROJJSONBuilderBase.js
41
+ var PROJJSONBuilderBase = class {
42
+ static getId(node) {
43
+ const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
44
+ if (idNode && idNode.length >= 3) return {
45
+ authority: idNode[1],
46
+ code: parseInt(idNode[2], 10)
47
+ };
48
+ return null;
196
49
  }
197
- _flush() {
198
- for (let i = 0; i < this._pendingLen; i++) {
199
- const t = this._pending[i];
200
- this._findReprojectionCandidate(t);
201
- }
202
- this._pendingLen = 0;
50
+ static convertUnit(node, type = "unit") {
51
+ if (!node || node.length < 3) return {
52
+ type,
53
+ name: "unknown",
54
+ conversion_factor: null
55
+ };
56
+ const name = node[1];
57
+ const conversionFactor = parseFloat(node[2]) || null;
58
+ const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
59
+ return {
60
+ type,
61
+ name,
62
+ conversion_factor: conversionFactor,
63
+ id: idNode ? {
64
+ authority: idNode[1],
65
+ code: parseInt(idNode[2], 10)
66
+ } : null
67
+ };
203
68
  }
204
- /**
205
- * Conversion of upstream's `_findCandidate` for reprojection error handling.
206
- *
207
- * @param t The index (into `this.triangles`) of the pending triangle to process.
208
- *
209
- * @return Doesn't return; instead modifies internal state.
210
- */
211
- _findReprojectionCandidate(t) {
212
- const a = 2 * this.triangles[t * 3 + 0];
213
- const b = 2 * this.triangles[t * 3 + 1];
214
- const c = 2 * this.triangles[t * 3 + 2];
215
- const p0u = this.uvs[a];
216
- const p0v = this.uvs[a + 1];
217
- const p1u = this.uvs[b];
218
- const p1v = this.uvs[b + 1];
219
- const p2u = this.uvs[c];
220
- const p2v = this.uvs[c + 1];
221
- const out0x = this.exactOutputPositions[a];
222
- const out0y = this.exactOutputPositions[a + 1];
223
- const out1x = this.exactOutputPositions[b];
224
- const out1y = this.exactOutputPositions[b + 1];
225
- const out2x = this.exactOutputPositions[c];
226
- const out2y = this.exactOutputPositions[c + 1];
227
- let maxError = 0;
228
- let maxErrorU = 0;
229
- let maxErrorV = 0;
230
- for (const samplePoint of SAMPLE_POINTS) {
231
- const uvSampleU = barycentricMix(p0u, p1u, p2u, samplePoint[0], samplePoint[1], samplePoint[2]);
232
- const uvSampleV = barycentricMix(p0v, p1v, p2v, samplePoint[0], samplePoint[1], samplePoint[2]);
233
- const outSampleX = barycentricMix(out0x, out1x, out2x, samplePoint[0], samplePoint[1], samplePoint[2]);
234
- const outSampleY = barycentricMix(out0y, out1y, out2y, samplePoint[0], samplePoint[1], samplePoint[2]);
235
- const pixelExactX = uvSampleU * (this.width - 1);
236
- const pixelExactY = uvSampleV * (this.height - 1);
237
- const inputCRSSampled = this.reprojectors.inverseReproject(outSampleX, outSampleY);
238
- const pixelSampled = this.reprojectors.inverseTransform(inputCRSSampled[0], inputCRSSampled[1]);
239
- const dx = pixelExactX - pixelSampled[0];
240
- const dy = pixelExactY - pixelSampled[1];
241
- const err = Math.hypot(dx, dy);
242
- if (err > maxError) {
243
- maxError = err;
244
- maxErrorU = uvSampleU;
245
- maxErrorV = uvSampleV;
246
- }
247
- }
248
- if (maxErrorU === p0u && maxErrorV === p0v || maxErrorU === p1u && maxErrorV === p1v || maxErrorU === p2u && maxErrorV === p2v) maxError = 0;
249
- this._candidatesUV[2 * t] = maxErrorU;
250
- this._candidatesUV[2 * t + 1] = maxErrorV;
251
- this._queuePush(t, maxError);
252
- }
253
- _step() {
254
- const t = this._queuePop();
255
- const e0 = t * 3 + 0;
256
- const e1 = t * 3 + 1;
257
- const e2 = t * 3 + 2;
258
- const p0 = this.triangles[e0];
259
- const p1 = this.triangles[e1];
260
- const p2 = this.triangles[e2];
261
- const au = this.uvs[2 * p0];
262
- const av = this.uvs[2 * p0 + 1];
263
- const bu = this.uvs[2 * p1];
264
- const bv = this.uvs[2 * p1 + 1];
265
- const cu = this.uvs[2 * p2];
266
- const cv = this.uvs[2 * p2 + 1];
267
- const pu = this._candidatesUV[2 * t];
268
- const pv = this._candidatesUV[2 * t + 1];
269
- const pn = this._addPoint(pu, pv);
270
- if (orient(au, av, bu, bv, pu, pv) === 0) this._handleCollinear(pn, e0);
271
- else if (orient(bu, bv, cu, cv, pu, pv) === 0) this._handleCollinear(pn, e1);
272
- else if (orient(cu, cv, au, av, pu, pv) === 0) this._handleCollinear(pn, e2);
273
- else {
274
- const h0 = this._halfedges[e0];
275
- const h1 = this._halfedges[e1];
276
- const h2 = this._halfedges[e2];
277
- const t0 = this._addTriangle(p0, p1, pn, h0, -1, -1, e0);
278
- const t1 = this._addTriangle(p1, p2, pn, h1, -1, t0 + 1);
279
- const t2 = this._addTriangle(p2, p0, pn, h2, t0 + 2, t1 + 1);
280
- this._legalize(t0);
281
- this._legalize(t1);
282
- this._legalize(t2);
283
- }
284
- }
285
- _addPoint(u, v) {
286
- const i = this.uvs.length >> 1;
287
- this.uvs.push(u, v);
288
- const pixelX = u * (this.width - 1);
289
- const pixelY = v * (this.height - 1);
290
- const inputPosition = this.reprojectors.forwardTransform(pixelX, pixelY);
291
- const exactOutputPosition = this.reprojectors.forwardReproject(inputPosition[0], inputPosition[1]);
292
- this.exactOutputPositions.push(exactOutputPosition[0], exactOutputPosition[1]);
293
- return i;
294
- }
295
- _addTriangle(a, b, c, ab, bc, ca, e = this.triangles.length) {
296
- const t = e / 3;
297
- this.triangles[e + 0] = a;
298
- this.triangles[e + 1] = b;
299
- this.triangles[e + 2] = c;
300
- this._halfedges[e + 0] = ab;
301
- this._halfedges[e + 1] = bc;
302
- this._halfedges[e + 2] = ca;
303
- if (ab >= 0) this._halfedges[ab] = e + 0;
304
- if (bc >= 0) this._halfedges[bc] = e + 1;
305
- if (ca >= 0) this._halfedges[ca] = e + 2;
306
- this._candidatesUV[2 * t + 0] = 0;
307
- this._candidatesUV[2 * t + 1] = 0;
308
- this._queueIndices[t] = -1;
309
- this._pending[this._pendingLen++] = t;
310
- return e;
311
- }
312
- _legalize(a) {
313
- const b = this._halfedges[a];
314
- if (b < 0) return;
315
- const a0 = a - a % 3;
316
- const b0 = b - b % 3;
317
- const al = a0 + (a + 1) % 3;
318
- const ar = a0 + (a + 2) % 3;
319
- const bl = b0 + (b + 2) % 3;
320
- const br = b0 + (b + 1) % 3;
321
- const p0 = this.triangles[ar];
322
- const pr = this.triangles[a];
323
- const pl = this.triangles[al];
324
- const p1 = this.triangles[bl];
325
- const uvs = this.uvs;
326
- if (!inCircle(uvs[2 * p0], uvs[2 * p0 + 1], uvs[2 * pr], uvs[2 * pr + 1], uvs[2 * pl], uvs[2 * pl + 1], uvs[2 * p1], uvs[2 * p1 + 1])) return;
327
- const hal = this._halfedges[al];
328
- const har = this._halfedges[ar];
329
- const hbl = this._halfedges[bl];
330
- const hbr = this._halfedges[br];
331
- this._queueRemove(a0 / 3);
332
- this._queueRemove(b0 / 3);
333
- const t0 = this._addTriangle(p0, p1, pl, -1, hbl, hal, a0);
334
- const t1 = this._addTriangle(p1, p0, pr, t0, har, hbr, b0);
335
- this._legalize(t0 + 1);
336
- this._legalize(t1 + 2);
337
- }
338
- _handleCollinear(pn, a) {
339
- const a0 = a - a % 3;
340
- const al = a0 + (a + 1) % 3;
341
- const ar = a0 + (a + 2) % 3;
342
- const p0 = this.triangles[ar];
343
- const pr = this.triangles[a];
344
- const pl = this.triangles[al];
345
- const hal = this._halfedges[al];
346
- const har = this._halfedges[ar];
347
- const b = this._halfedges[a];
348
- if (b < 0) {
349
- const t0 = this._addTriangle(pn, p0, pr, -1, har, -1, a0);
350
- const t1 = this._addTriangle(p0, pn, pl, t0, -1, hal);
351
- this._legalize(t0 + 1);
352
- this._legalize(t1 + 2);
353
- return;
354
- }
355
- const b0 = b - b % 3;
356
- const bl = b0 + (b + 2) % 3;
357
- const br = b0 + (b + 1) % 3;
358
- const p1 = this.triangles[bl];
359
- const hbl = this._halfedges[bl];
360
- const hbr = this._halfedges[br];
361
- this._queueRemove(b0 / 3);
362
- const t0 = this._addTriangle(p0, pr, pn, har, -1, -1, a0);
363
- const t1 = this._addTriangle(pr, p1, pn, hbr, -1, t0 + 1, b0);
364
- const t2 = this._addTriangle(p1, pl, pn, hbl, -1, t1 + 1);
365
- const t3 = this._addTriangle(pl, p0, pn, hal, t0 + 2, t2 + 1);
366
- this._legalize(t0);
367
- this._legalize(t1);
368
- this._legalize(t2);
369
- this._legalize(t3);
370
- }
371
- _queuePush(t, error) {
372
- const i = this._queue.length;
373
- this._queueIndices[t] = i;
374
- this._queue.push(t);
375
- this._errors.push(error);
376
- this._queueUp(i);
377
- }
378
- _queuePop() {
379
- const n = this._queue.length - 1;
380
- this._queueSwap(0, n);
381
- this._queueDown(0, n);
382
- return this._queuePopBack();
383
- }
384
- _queuePopBack() {
385
- const t = this._queue.pop();
386
- this._errors.pop();
387
- this._queueIndices[t] = -1;
388
- return t;
389
- }
390
- _queueRemove(t) {
391
- const i = this._queueIndices[t];
392
- if (i < 0) {
393
- const it = this._pending.indexOf(t);
394
- if (it !== -1) this._pending[it] = this._pending[--this._pendingLen];
395
- else throw new Error("Broken triangulation (something went wrong).");
396
- return;
397
- }
398
- const n = this._queue.length - 1;
399
- if (n !== i) {
400
- this._queueSwap(i, n);
401
- if (!this._queueDown(i, n)) this._queueUp(i);
402
- }
403
- this._queuePopBack();
404
- }
405
- _queueLess(i, j) {
406
- return this._errors[i] > this._errors[j];
407
- }
408
- _queueSwap(i, j) {
409
- const pi = this._queue[i];
410
- const pj = this._queue[j];
411
- this._queue[i] = pj;
412
- this._queue[j] = pi;
413
- this._queueIndices[pi] = j;
414
- this._queueIndices[pj] = i;
415
- const e = this._errors[i];
416
- this._errors[i] = this._errors[j];
417
- this._errors[j] = e;
418
- }
419
- _queueUp(j0) {
420
- let j = j0;
421
- while (true) {
422
- const i = j - 1 >> 1;
423
- if (i === j || !this._queueLess(j, i)) break;
424
- this._queueSwap(i, j);
425
- j = i;
426
- }
427
- }
428
- _queueDown(i0, n) {
429
- let i = i0;
430
- while (true) {
431
- const j1 = 2 * i + 1;
432
- if (j1 >= n || j1 < 0) break;
433
- const j2 = j1 + 1;
434
- let j = j1;
435
- if (j2 < n && this._queueLess(j2, j1)) j = j2;
436
- if (!this._queueLess(j, i)) break;
437
- this._queueSwap(i, j);
438
- i = j;
439
- }
440
- return i > i0;
441
- }
442
- };
443
- function orient(ax, ay, bx, by, cx, cy) {
444
- return (bx - cx) * (ay - cy) - (by - cy) * (ax - cx);
445
- }
446
- function inCircle(ax, ay, bx, by, cx, cy, px, py) {
447
- const dx = ax - px;
448
- const dy = ay - py;
449
- const ex = bx - px;
450
- const ey = by - py;
451
- const fx = cx - px;
452
- const fy = cy - py;
453
- const ap = dx * dx + dy * dy;
454
- const bp = ex * ex + ey * ey;
455
- const cp = fx * fx + fy * fy;
456
- return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) < 0;
457
- }
458
- /**
459
- * Interpolate the value at a given barycentric coordinate within a triangle.
460
- *
461
- * I've seen the name "mix" used before in graphics programming to refer to
462
- * barycentric linear interpolation.
463
- *
464
- * Note: the caller must call this method twice: once for u and once again for
465
- * v. We do this because we want to avoid allocating an array for the return
466
- * value.
467
- */
468
- function barycentricMix(a, b, c, t0, t1, t2) {
469
- return t0 * a + t1 * b + t2 * c;
470
- }
471
- //#endregion
472
- //#region node_modules/@developmentseed/deck.gl-raster/dist/gpu-modules/create-texture.js
473
- /**
474
- * The base shader module for a render pipeline: samples a single input
475
- * texture into `color` so subsequent modules can transform it. Use this
476
- * when no decoding step (e.g. {@link CompositeBands}) is needed.
477
- */
478
- var CreateTexture = {
479
- name: "create-texture-unorm",
480
- inject: {
481
- "fs:#decl": `uniform sampler2D textureName;`,
482
- "fs:DECKGL_FILTER_COLOR": `
483
- color = texture(textureName, geometry.uv);
484
- `
485
- },
486
- getUniforms: (props) => {
487
- return { textureName: props.textureName };
488
- }
489
- };
490
- //#endregion
491
- //#region node_modules/@developmentseed/deck.gl-raster/dist/mesh-layer/mesh-layer-fragment.glsl.js
492
- /**
493
- * This is a vendored copy of the SimpleMeshLayer's fragment shader:
494
- * https://github.com/visgl/deck.gl/blob/a15c8cea047993c8a861bf542835c1988f30165c/modules/mesh-layers/src/simple-mesh-layer/simple-mesh-layer-fragment.glsl.ts
495
- * under the MIT license.
496
- *
497
- * We edited this to remove the hard-coded texture uniform because we want to
498
- * support integer and signed integer textures, not only normalized unsigned
499
- * textures.
500
- */
501
- var mesh_layer_fragment_glsl_default = `#version 300 es
502
- #define SHADER_NAME simple-mesh-layer-fs
503
-
504
- precision highp float;
505
-
506
- in vec2 vTexCoord;
507
- in vec3 cameraPosition;
508
- in vec3 normals_commonspace;
509
- in vec4 position_commonspace;
510
- in vec4 vColor;
511
-
512
- out vec4 fragColor;
513
-
514
- void main(void) {
515
- geometry.uv = vTexCoord;
516
-
517
- vec3 normal;
518
- if (simpleMesh.flatShading) {
519
-
520
- normal = normalize(cross(dFdx(position_commonspace.xyz), dFdy(position_commonspace.xyz)));
521
- } else {
522
- normal = normals_commonspace;
523
- }
524
-
525
- // We initialize color here before passing into DECKGL_FILTER_COLOR
526
- vec4 color;
527
- DECKGL_FILTER_COLOR(color, geometry);
528
-
529
- vec3 lightColor = lighting_getLightColor(color.rgb, cameraPosition, position_commonspace.xyz, normal);
530
- fragColor = vec4(lightColor, color.a * layer.opacity);
531
- }
532
- `;
533
- //#endregion
534
- //#region node_modules/@developmentseed/deck.gl-raster/dist/mesh-layer/mesh-layer.js
535
- var defaultProps$2 = {
536
- ...SimpleMeshLayer.defaultProps,
537
- renderPipeline: {
538
- type: "array",
539
- value: [],
540
- compare: true
541
- },
542
- material: {
543
- ambient: 1,
544
- diffuse: 0,
545
- shininess: 0,
546
- specularColor: [
547
- 0,
548
- 0,
549
- 0
550
- ]
551
- }
552
- };
553
- /**
554
- * A small subclass of the SimpleMeshLayer to allow dynamic shader injections.
555
- *
556
- * In the future this may expand to diverge more from the SimpleMeshLayer, such
557
- * as allowing the texture to be a 2D _array_.
558
- */
559
- var MeshTextureLayer = class extends SimpleMeshLayer {
560
- static layerName = "mesh-texture-layer";
561
- static defaultProps = defaultProps$2;
562
- _resolveRenderPipeline() {
563
- const { image, renderPipeline } = this.props;
564
- return [...image ? [{
565
- module: CreateTexture,
566
- props: { textureName: image }
567
- }] : [], ...renderPipeline ?? []];
568
- }
569
- updateState(params) {
570
- if (this.hasRenderPipelineChanged(params)) params.changeFlags.extensionsChanged = true;
571
- super.updateState(params);
572
- }
573
- /** Returns true if the render pipeline has changed between the old and new props. */
574
- hasRenderPipelineChanged(params) {
575
- const { oldProps, props: newProps } = params;
576
- if (Boolean(oldProps.image) !== Boolean(newProps.image)) return true;
577
- const oldPipeline = oldProps.renderPipeline ?? [];
578
- const newPipeline = newProps.renderPipeline ?? [];
579
- if (oldPipeline.length !== newPipeline.length) return true;
580
- for (let i = 0; i < oldPipeline.length; i++) if (oldPipeline[i]?.module.name !== newPipeline[i]?.module.name) return true;
581
- return false;
582
- }
583
- getShaders() {
584
- const upstreamShaders = super.getShaders();
585
- const modules = upstreamShaders.modules;
586
- for (const m of this._resolveRenderPipeline()) modules.push(m.module);
587
- return {
588
- ...upstreamShaders,
589
- fs: mesh_layer_fragment_glsl_default,
590
- modules
591
- };
592
- }
593
- draw(opts) {
594
- const shaderProps = {};
595
- for (const m of this._resolveRenderPipeline()) shaderProps[m.module.name] = m.props || {};
596
- for (const m of super.getModels()) m.shaderInputs.setProps(shaderProps);
597
- super.draw(opts);
598
- }
599
- };
600
- //#endregion
601
- //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-layer.js
602
- var DEFAULT_MAX_ERROR = .125;
603
- var DEBUG_COLORS = [
604
- [
605
- 252,
606
- 73,
607
- 163
608
- ],
609
- [
610
- 255,
611
- 51,
612
- 204
613
- ],
614
- [
615
- 204,
616
- 102,
617
- 255
618
- ],
619
- [
620
- 153,
621
- 51,
622
- 255
623
- ],
624
- [
625
- 102,
626
- 204,
627
- 255
628
- ],
629
- [
630
- 51,
631
- 153,
632
- 255
633
- ],
634
- [
635
- 102,
636
- 255,
637
- 204
638
- ],
639
- [
640
- 51,
641
- 255,
642
- 170
643
- ],
644
- [
645
- 0,
646
- 255,
647
- 0
648
- ],
649
- [
650
- 51,
651
- 204,
652
- 51
653
- ],
654
- [
655
- 255,
656
- 204,
657
- 102
658
- ],
659
- [
660
- 255,
661
- 179,
662
- 71
663
- ],
664
- [
665
- 255,
666
- 102,
667
- 102
668
- ],
669
- [
670
- 255,
671
- 80,
672
- 80
673
- ],
674
- [
675
- 255,
676
- 0,
677
- 0
678
- ],
679
- [
680
- 204,
681
- 0,
682
- 0
683
- ],
684
- [
685
- 255,
686
- 128,
687
- 0
688
- ],
689
- [
690
- 255,
691
- 153,
692
- 51
693
- ],
694
- [
695
- 255,
696
- 255,
697
- 102
698
- ],
699
- [
700
- 255,
701
- 255,
702
- 51
703
- ],
704
- [
705
- 0,
706
- 255,
707
- 255
708
- ],
709
- [
710
- 0,
711
- 204,
712
- 255
713
- ]
714
- ];
715
- var defaultProps$1 = {
716
- image: {
717
- type: "image",
718
- value: null,
719
- async: true
720
- },
721
- renderPipeline: {
722
- type: "array",
723
- value: [],
724
- compare: true
725
- },
726
- debug: false,
727
- debugOpacity: .5
728
- };
729
- /**
730
- * Generic deck.gl layer for rendering geospatial raster data with client-side,
731
- * GPU-based reprojection and custom processing pipelines.
732
- *
733
- * This is a composite layer that uses {@link RasterReprojector} to generate an adaptive mesh
734
- * that accurately represents the reprojected raster, then renders it using
735
- * {@link MeshTextureLayer} (a small wrapper around a deck.gl
736
- * {@link SimpleMeshLayer}).
737
- */
738
- var RasterLayer = class extends CompositeLayer {
739
- static layerName = "RasterLayer";
740
- static defaultProps = defaultProps$1;
741
- initializeState() {
742
- this.setState({});
69
+ static convertAxis(node) {
70
+ const name = node[1] || "Unknown";
71
+ let direction;
72
+ const abbreviationMatch = name.match(/^\((.)\)$/);
73
+ if (abbreviationMatch) {
74
+ const abbreviation = abbreviationMatch[1].toUpperCase();
75
+ if (abbreviation === "E") direction = "east";
76
+ else if (abbreviation === "N") direction = "north";
77
+ else if (abbreviation === "U") direction = "up";
78
+ else if (node[2]) direction = node[2];
79
+ else throw new Error(`Unknown axis abbreviation: ${abbreviation}`);
80
+ } else direction = node[2] || "unknown";
81
+ const orderNode = node.find((child) => Array.isArray(child) && child[0] === "ORDER");
82
+ const order = orderNode ? parseInt(orderNode[1], 10) : null;
83
+ const unitNode = node.find((child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT"));
84
+ const unit = this.convertUnit(unitNode);
85
+ return {
86
+ name,
87
+ direction,
88
+ unit,
89
+ order
90
+ };
743
91
  }
744
- updateState(params) {
745
- super.updateState(params);
746
- const { props, oldProps, changeFlags } = params;
747
- const reprojectionFnsChanged = props.reprojectionFns.forwardTransform !== oldProps.reprojectionFns?.forwardTransform || props.reprojectionFns.inverseTransform !== oldProps.reprojectionFns?.inverseTransform || props.reprojectionFns.forwardReproject !== oldProps.reprojectionFns?.forwardReproject || props.reprojectionFns.inverseReproject !== oldProps.reprojectionFns?.inverseReproject;
748
- if (Boolean(changeFlags.dataChanged) || props.width !== oldProps.width || props.height !== oldProps.height || reprojectionFnsChanged || props.maxError !== oldProps.maxError) this._generateMesh();
92
+ static extractAxes(node) {
93
+ return node.filter((child) => Array.isArray(child) && child[0] === "AXIS").map((axis) => this.convertAxis(axis)).sort((a, b) => (a.order || 0) - (b.order || 0));
749
94
  }
750
- _generateMesh() {
751
- const { width, height, reprojectionFns, maxError = DEFAULT_MAX_ERROR } = this.props;
752
- const reprojector = new RasterReprojector(reprojectionFns, width + 1, height + 1);
753
- reprojector.run(maxError);
754
- const { indices, positions, texCoords } = reprojectorToMesh(reprojector);
755
- this.setState({
756
- reprojector,
757
- mesh: {
758
- indices: {
759
- value: indices,
760
- size: 1
761
- },
762
- attributes: {
763
- POSITION: {
764
- value: positions,
765
- size: 3
766
- },
767
- TEXCOORD_0: {
768
- value: texCoords,
769
- size: 2
770
- }
95
+ static convert(node, result = {}) {
96
+ switch (node[0]) {
97
+ case "PROJCRS":
98
+ result.type = "ProjectedCRS";
99
+ result.name = node[1];
100
+ result.base_crs = node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS")) : null;
101
+ result.conversion = node.find((child) => Array.isArray(child) && child[0] === "CONVERSION") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "CONVERSION")) : null;
102
+ const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
103
+ if (csNode) result.coordinate_system = {
104
+ type: csNode[1],
105
+ axis: this.extractAxes(node)
106
+ };
107
+ const lengthUnitNode = node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT");
108
+ if (lengthUnitNode) {
109
+ const unit = this.convertUnit(lengthUnitNode);
110
+ result.coordinate_system.unit = unit;
111
+ }
112
+ result.id = this.getId(node);
113
+ break;
114
+ case "BASEGEOGCRS":
115
+ case "GEOGCRS":
116
+ case "GEODCRS":
117
+ result.type = node[0] === "GEODCRS" ? "GeodeticCRS" : "GeographicCRS";
118
+ result.name = node[1];
119
+ const datumOrEnsembleNode = node.find((child) => Array.isArray(child) && (child[0] === "DATUM" || child[0] === "ENSEMBLE"));
120
+ if (datumOrEnsembleNode) {
121
+ const datumOrEnsemble = this.convert(datumOrEnsembleNode);
122
+ if (datumOrEnsembleNode[0] === "ENSEMBLE") result.datum_ensemble = datumOrEnsemble;
123
+ else result.datum = datumOrEnsemble;
124
+ const primem = node.find((child) => Array.isArray(child) && child[0] === "PRIMEM");
125
+ if (primem && primem[1] !== "Greenwich") datumOrEnsemble.prime_meridian = {
126
+ name: primem[1],
127
+ longitude: parseFloat(primem[2])
128
+ };
129
+ }
130
+ result.coordinate_system = {
131
+ type: "ellipsoidal",
132
+ axis: this.extractAxes(node)
133
+ };
134
+ result.id = this.getId(node);
135
+ break;
136
+ case "DATUM":
137
+ result.type = "GeodeticReferenceFrame";
138
+ result.name = node[1];
139
+ result.ellipsoid = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID")) : null;
140
+ break;
141
+ case "ENSEMBLE":
142
+ result.type = "DatumEnsemble";
143
+ result.name = node[1];
144
+ result.members = node.filter((child) => Array.isArray(child) && child[0] === "MEMBER").map((member) => ({
145
+ type: "DatumEnsembleMember",
146
+ name: member[1],
147
+ id: this.getId(member)
148
+ }));
149
+ const accuracyNode = node.find((child) => Array.isArray(child) && child[0] === "ENSEMBLEACCURACY");
150
+ if (accuracyNode) result.accuracy = parseFloat(accuracyNode[1]);
151
+ const ellipsoidNode = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID");
152
+ if (ellipsoidNode) result.ellipsoid = this.convert(ellipsoidNode);
153
+ result.id = this.getId(node);
154
+ break;
155
+ case "ELLIPSOID":
156
+ result.type = "Ellipsoid";
157
+ result.name = node[1];
158
+ result.semi_major_axis = parseFloat(node[2]);
159
+ result.inverse_flattening = parseFloat(node[3]);
160
+ node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT") && this.convert(node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT"), result);
161
+ break;
162
+ case "CONVERSION":
163
+ result.type = "Conversion";
164
+ result.name = node[1];
165
+ result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
166
+ result.parameters = node.filter((child) => Array.isArray(child) && child[0] === "PARAMETER").map((param) => this.convert(param));
167
+ break;
168
+ case "METHOD":
169
+ result.type = "Method";
170
+ result.name = node[1];
171
+ result.id = this.getId(node);
172
+ break;
173
+ case "PARAMETER":
174
+ result.type = "Parameter";
175
+ result.name = node[1];
176
+ result.value = parseFloat(node[2]);
177
+ result.unit = this.convertUnit(node.find((child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT")));
178
+ result.id = this.getId(node);
179
+ break;
180
+ case "BOUNDCRS":
181
+ result.type = "BoundCRS";
182
+ const sourceCrsNode = node.find((child) => Array.isArray(child) && child[0] === "SOURCECRS");
183
+ if (sourceCrsNode) {
184
+ const sourceCrsContent = sourceCrsNode.find((child) => Array.isArray(child));
185
+ result.source_crs = sourceCrsContent ? this.convert(sourceCrsContent) : null;
186
+ }
187
+ const targetCrsNode = node.find((child) => Array.isArray(child) && child[0] === "TARGETCRS");
188
+ if (targetCrsNode) {
189
+ const targetCrsContent = targetCrsNode.find((child) => Array.isArray(child));
190
+ result.target_crs = targetCrsContent ? this.convert(targetCrsContent) : null;
191
+ }
192
+ const transformationNode = node.find((child) => Array.isArray(child) && child[0] === "ABRIDGEDTRANSFORMATION");
193
+ if (transformationNode) result.transformation = this.convert(transformationNode);
194
+ else result.transformation = null;
195
+ break;
196
+ case "ABRIDGEDTRANSFORMATION":
197
+ result.type = "Transformation";
198
+ result.name = node[1];
199
+ result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
200
+ result.parameters = node.filter((child) => Array.isArray(child) && (child[0] === "PARAMETER" || child[0] === "PARAMETERFILE")).map((param) => {
201
+ if (param[0] === "PARAMETER") return this.convert(param);
202
+ else if (param[0] === "PARAMETERFILE") return {
203
+ name: param[1],
204
+ value: param[2],
205
+ id: {
206
+ "authority": "EPSG",
207
+ "code": 8656
208
+ }
209
+ };
210
+ });
211
+ if (result.parameters.length === 7) {
212
+ const scaleDifference = result.parameters[6];
213
+ if (scaleDifference.name === "Scale difference") scaleDifference.value = Math.round((scaleDifference.value - 1) * 0xe8d4a51000) / 1e6;
771
214
  }
772
- }
773
- });
774
- }
775
- renderDebugLayer() {
776
- const { reprojector } = this.state;
777
- const { debugOpacity } = this.props;
778
- if (!reprojector) return null;
779
- return new PolygonLayer(this.getSubLayerProps({
780
- id: "polygon",
781
- data: {
782
- reprojector,
783
- length: reprojector.triangles.length / 3
784
- },
785
- getPolygon: (_, { index, data }) => {
786
- const triangles = data.reprojector.triangles;
787
- const positions = reprojector.exactOutputPositions;
788
- const a = triangles[index * 3];
789
- const b = triangles[index * 3 + 1];
790
- const c = triangles[index * 3 + 2];
791
- return [
792
- [positions[a * 2], positions[a * 2 + 1]],
793
- [positions[b * 2], positions[b * 2 + 1]],
794
- [positions[c * 2], positions[c * 2 + 1]],
795
- [positions[a * 2], positions[a * 2 + 1]]
796
- ];
797
- },
798
- getFillColor: (_, { index, target }) => {
799
- const color = DEBUG_COLORS[index % DEBUG_COLORS.length];
800
- target[0] = color[0];
801
- target[1] = color[1];
802
- target[2] = color[2];
803
- target[3] = 255;
804
- return target;
805
- },
806
- getLineColor: [
807
- 0,
808
- 0,
809
- 0
810
- ],
811
- getLineWidth: 1,
812
- lineWidthUnits: "pixels",
813
- opacity: debugOpacity !== void 0 && Number.isFinite(debugOpacity) ? Math.max(0, Math.min(1, debugOpacity)) : 1,
814
- pickable: false
815
- }));
816
- }
817
- renderLayers() {
818
- const { mesh } = this.state;
819
- const { debug, image, renderPipeline } = this.props;
820
- if (!mesh || !image && (renderPipeline?.length ?? 0) === 0) return null;
821
- const layers = [new MeshTextureLayer(this.getSubLayerProps({
822
- id: "raster",
823
- image,
824
- renderPipeline,
825
- data: [1],
826
- mesh,
827
- _instanced: false,
828
- getPosition: [
829
- 0,
830
- 0,
831
- 0
832
- ],
833
- getColor: [
834
- 255,
835
- 255,
836
- 255
837
- ]
838
- }))];
839
- if (debug) {
840
- const debugLayer = this.renderDebugLayer();
841
- if (debugLayer) layers.push(debugLayer);
215
+ result.id = this.getId(node);
216
+ break;
217
+ case "AXIS":
218
+ if (!result.coordinate_system) result.coordinate_system = {
219
+ type: "unspecified",
220
+ axis: []
221
+ };
222
+ result.coordinate_system.axis.push(this.convertAxis(node));
223
+ break;
224
+ case "LENGTHUNIT":
225
+ const unit = this.convertUnit(node, "LinearUnit");
226
+ if (result.coordinate_system && result.coordinate_system.axis) result.coordinate_system.axis.forEach((axis) => {
227
+ if (!axis.unit) axis.unit = unit;
228
+ });
229
+ if (unit.conversion_factor && unit.conversion_factor !== 1) {
230
+ if (result.semi_major_axis) result.semi_major_axis = {
231
+ value: result.semi_major_axis,
232
+ unit
233
+ };
234
+ }
235
+ break;
236
+ default:
237
+ result.keyword = node[0];
238
+ break;
842
239
  }
843
- return layers;
240
+ return result;
844
241
  }
845
242
  };
846
- function reprojectorToMesh(reprojector) {
847
- const numVertices = reprojector.uvs.length / 2;
848
- const positions = new Float32Array(numVertices * 3);
849
- const texCoords = new Float32Array(reprojector.uvs);
850
- for (let i = 0; i < numVertices; i++) {
851
- positions[i * 3] = reprojector.exactOutputPositions[i * 2];
852
- positions[i * 3 + 1] = reprojector.exactOutputPositions[i * 2 + 1];
853
- positions[i * 3 + 2] = 0;
243
+ //#endregion
244
+ //#region node_modules/wkt-parser/PROJJSONBuilder2015.js
245
+ var PROJJSONBuilder2015 = class extends PROJJSONBuilderBase {
246
+ static convert(node, result = {}) {
247
+ super.convert(node, result);
248
+ if (result.coordinate_system && result.coordinate_system.subtype === "Cartesian") delete result.coordinate_system;
249
+ if (result.usage) delete result.usage;
250
+ return result;
854
251
  }
855
- return {
856
- indices: new Uint32Array(reprojector.triangles),
857
- positions,
858
- texCoords
859
- };
860
- }
252
+ };
861
253
  //#endregion
862
- //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/affine-tileset.js
863
- /**
864
- * A {@link RasterTilesetDescriptor} backed by per-level affine transforms.
865
- *
866
- * Derives `projectedBounds` from the coarsest level's array. Everything else
867
- * is passed through from the constructor options.
868
- */
869
- var AffineTileset = class {
870
- levels;
871
- projectTo3857;
872
- projectFrom3857;
873
- projectTo4326;
874
- projectFrom4326;
875
- projectedBounds;
876
- constructor(options) {
877
- if (options.levels.length === 0) throw new Error("AffineTileset requires at least one level");
878
- this.levels = options.levels;
879
- this.projectTo3857 = options.projectTo3857;
880
- this.projectFrom3857 = options.projectFrom3857;
881
- this.projectTo4326 = options.projectTo4326;
882
- this.projectFrom4326 = options.projectFrom4326;
883
- this.projectedBounds = options.levels[0].projectedBounds;
254
+ //#region node_modules/wkt-parser/PROJJSONBuilder2019.js
255
+ var PROJJSONBuilder2019 = class extends PROJJSONBuilderBase {
256
+ static convert(node, result = {}) {
257
+ super.convert(node, result);
258
+ const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
259
+ if (csNode) result.coordinate_system = {
260
+ subtype: csNode[1],
261
+ axis: this.extractAxes(node)
262
+ };
263
+ const usageNode = node.find((child) => Array.isArray(child) && child[0] === "USAGE");
264
+ if (usageNode) {
265
+ const scope = usageNode.find((child) => Array.isArray(child) && child[0] === "SCOPE");
266
+ const area = usageNode.find((child) => Array.isArray(child) && child[0] === "AREA");
267
+ const bbox = usageNode.find((child) => Array.isArray(child) && child[0] === "BBOX");
268
+ result.usage = {};
269
+ if (scope) result.usage.scope = scope[1];
270
+ if (area) result.usage.area = area[1];
271
+ if (bbox) result.usage.bbox = bbox.slice(1);
272
+ }
273
+ return result;
884
274
  }
885
275
  };
886
276
  //#endregion
887
- //#region node_modules/@developmentseed/affine/dist/affine.js
888
- /**
889
- * Create a translation transform from an offset vector.
890
- *
891
- * @param xoff Translation offset in x direction.
892
- * @param yoff Translation offset in y direction.
893
- *
894
- * @return Transform that applies the given translation.
895
- */
896
- function translation(xoff, yoff) {
897
- return [
898
- 1,
899
- 0,
900
- xoff,
901
- 0,
902
- 1,
903
- yoff
904
- ];
905
- }
906
- /**
907
- * Create a scaling transform from a scalar or vector.
908
- *
909
- * You can pass either one or two scaling factors. Passing only a single scalar
910
- * value will scale in both dimensions equally. A vector scaling value scales
911
- * the dimensions independently.
912
- *
913
- * @param sx Scaling factor in x direction.
914
- * @param sy Scaling factor in y direction (defaults to sx if not provided).
915
- *
916
- * @return Transform that applies the given scaling.
917
- */
918
- function scale$3(sx, sy = sx) {
919
- return [
920
- sx,
921
- 0,
922
- 0,
923
- 0,
924
- sy,
925
- 0
926
- ];
927
- }
928
- /**
929
- * Apply a geotransform to a coordinate.
930
- *
931
- * That is, we apply this series of equations:
932
- *
933
- * ```
934
- * x_out = a * x + b * y + c
935
- * y_out = d * x + e * y + f
936
- * ```
937
- *
938
- * @param affine The affine transform to apply.
939
- * @param x The x coordinate.
940
- * @param y The y coordinate.
941
- *
942
- * @return The transformed coordinates.
943
- */
944
- function apply([a, b, c, d, e, f], x, y) {
945
- return [a * x + b * y + c, d * x + e * y + f];
946
- }
277
+ //#region node_modules/wkt-parser/buildPROJJSON.js
947
278
  /**
948
- * Compose two affine transforms: A×B (apply B **first**, then A).
949
- *
950
- * This is equivalent to `a @ b` in Python's `affine` library, and is equivalent
951
- * to multiplying the 3×3 matrices:
952
- * ```
953
- * | a1 b1 c1 | | a2 b2 c2 |
954
- * | d1 e1 f1 | × | d2 e2 f2 |
955
- * | 0 0 1 | | 0 0 1 |
956
- * ```
957
- *
958
- * @param A The first affine transform to apply.
959
- * @param B The second affine transform to apply.
960
- *
961
- * @return The composed affine transform.
279
+ * Detects the WKT2 version based on the structure of the WKT.
280
+ * @param {Array} root The root WKT array node.
281
+ * @returns {string} The detected version ("2015" or "2019").
962
282
  */
963
- function compose([a1, b1, c1, d1, e1, f1], [a2, b2, c2, d2, e2, f2]) {
964
- return [
965
- a1 * a2 + b1 * d2,
966
- a1 * b2 + b1 * e2,
967
- a1 * c2 + b1 * f2 + c1,
968
- d1 * a2 + e1 * d2,
969
- d1 * b2 + e1 * e2,
970
- d1 * c2 + e1 * f2 + f1
971
- ];
283
+ function detectWKT2Version(root) {
284
+ if (root.find((child) => Array.isArray(child) && child[0] === "USAGE")) return "2019";
285
+ if (root.find((child) => Array.isArray(child) && child[0] === "CS")) return "2015";
286
+ if (root[0] === "BOUNDCRS" || root[0] === "PROJCRS" || root[0] === "GEOGCRS") return "2015";
287
+ return "2015";
972
288
  }
973
289
  /**
974
- * Compute the inverse of an Affine.
975
- *
976
- * @param affine The affine transform to invert.
977
- * @return The inverted affine transform.
978
- * @throws If the transform is degenerate and cannot be inverted.
290
+ * Builds a PROJJSON object from a WKT array structure.
291
+ * @param {Array} root The root WKT array node.
292
+ * @returns {Object} The PROJJSON object.
979
293
  */
980
- function invert$2([sa, sb, sc, sd, se, sf]) {
981
- const det = sa * se - sb * sd;
982
- if (det === 0) throw new Error("Cannot invert degenerate transform");
983
- const idet = 1 / det;
984
- const ra = se * idet;
985
- const rb = -sb * idet;
986
- const rd = -sd * idet;
987
- const re = sa * idet;
988
- return [
989
- ra,
990
- rb,
991
- -sc * ra - sf * rb,
992
- rd,
993
- re,
994
- -sc * rd - sf * re
995
- ];
996
- }
997
- /** Get the 'a' component of an Affine transform. */
998
- function a(affine) {
999
- return affine[0];
1000
- }
1001
- /** Get the 'e' component of an Affine transform. */
1002
- function e(affine) {
1003
- return affine[4];
294
+ function buildPROJJSON(root) {
295
+ return (detectWKT2Version(root) === "2019" ? PROJJSONBuilder2019 : PROJJSONBuilder2015).convert(root);
1004
296
  }
1005
297
  //#endregion
1006
- //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/affine-tileset-level.js
298
+ //#region node_modules/wkt-parser/detectWKTVersion.js
1007
299
  /**
1008
- * A {@link RasterTilesetLevel} described by a single affine transform plus tile and
1009
- * array sizes.
1010
- *
1011
- * This handles axis-aligned, rotated, skewed, and non-square-pixel grids
1012
- * uniformly. Sources that fit this shape (tiled GeoTIFF overviews, GeoZarr
1013
- * multiscales) can construct one of these per resolution level instead of
1014
- * implementing {@link RasterTilesetLevel} manually.
300
+ * Detects whether the WKT string is WKT1 or WKT2.
301
+ * @param {string} wkt The WKT string.
302
+ * @returns {string} The detected version ("WKT1" or "WKT2").
1015
303
  */
1016
- var AffineTilesetLevel = class {
1017
- tileWidth;
1018
- tileHeight;
1019
- matrixWidth;
1020
- matrixHeight;
1021
- metersPerPixel;
1022
- /**
1023
- * Source-CRS bounding box of the level's array `[minX, minY, maxX, maxY]`.
1024
- * Computed from the affine applied to the four array corners.
1025
- */
1026
- projectedBounds;
1027
- _affine;
1028
- _invAffine;
1029
- constructor(options) {
1030
- this._affine = options.affine;
1031
- this._invAffine = invert$2(options.affine);
1032
- this.tileWidth = options.tileWidth;
1033
- this.tileHeight = options.tileHeight;
1034
- this.matrixWidth = Math.ceil(options.arrayWidth / options.tileWidth);
1035
- this.matrixHeight = Math.ceil(options.arrayHeight / options.tileHeight);
1036
- const a$1 = a(options.affine);
1037
- const e$1 = e(options.affine);
1038
- this.metersPerPixel = Math.sqrt(Math.abs(a$1 * e$1)) * options.mpu;
1039
- const corners = [
1040
- apply(options.affine, 0, 0),
1041
- apply(options.affine, options.arrayWidth, 0),
1042
- apply(options.affine, 0, options.arrayHeight),
1043
- apply(options.affine, options.arrayWidth, options.arrayHeight)
1044
- ];
1045
- const xs = corners.map(([x]) => x);
1046
- const ys = corners.map(([, y]) => y);
1047
- this.projectedBounds = [
1048
- Math.min(...xs),
1049
- Math.min(...ys),
1050
- Math.max(...xs),
1051
- Math.max(...ys)
1052
- ];
304
+ function detectWKTVersion(wkt) {
305
+ const normalizedWKT = wkt.toUpperCase();
306
+ if (normalizedWKT.includes("PROJCRS") || normalizedWKT.includes("GEOGCRS") || normalizedWKT.includes("BOUNDCRS") || normalizedWKT.includes("VERTCRS") || normalizedWKT.includes("LENGTHUNIT") || normalizedWKT.includes("ANGLEUNIT") || normalizedWKT.includes("SCALEUNIT")) return "WKT2";
307
+ if (normalizedWKT.includes("PROJCS") || normalizedWKT.includes("GEOGCS") || normalizedWKT.includes("LOCAL_CS") || normalizedWKT.includes("VERT_CS") || normalizedWKT.includes("UNIT")) return "WKT1";
308
+ return "WKT1";
309
+ }
310
+ //#endregion
311
+ //#region node_modules/wkt-parser/parser.js
312
+ var parser_default = parseString;
313
+ var NEUTRAL = 1;
314
+ var KEYWORD = 2;
315
+ var NUMBER = 3;
316
+ var QUOTED = 4;
317
+ var AFTERQUOTE = 5;
318
+ var ENDED = -1;
319
+ var whitespace = /\s/;
320
+ var latin = /[A-Za-z]/;
321
+ var keyword = /[A-Za-z84_]/;
322
+ var endThings = /[,\]]/;
323
+ var digets = /[\d\.E\-\+]/;
324
+ function Parser(text) {
325
+ if (typeof text !== "string") throw new Error("not a string");
326
+ this.text = text.trim();
327
+ this.level = 0;
328
+ this.place = 0;
329
+ this.root = null;
330
+ this.stack = [];
331
+ this.currentObject = null;
332
+ this.state = NEUTRAL;
333
+ }
334
+ Parser.prototype.readCharicter = function() {
335
+ var char = this.text[this.place++];
336
+ if (this.state !== QUOTED) while (whitespace.test(char)) {
337
+ if (this.place >= this.text.length) return;
338
+ char = this.text[this.place++];
339
+ }
340
+ switch (this.state) {
341
+ case NEUTRAL: return this.neutral(char);
342
+ case KEYWORD: return this.keyword(char);
343
+ case QUOTED: return this.quoted(char);
344
+ case AFTERQUOTE: return this.afterquote(char);
345
+ case NUMBER: return this.number(char);
346
+ case ENDED: return;
347
+ }
348
+ };
349
+ Parser.prototype.afterquote = function(char) {
350
+ if (char === "\"") {
351
+ this.word += "\"";
352
+ this.state = QUOTED;
353
+ return;
354
+ }
355
+ if (endThings.test(char)) {
356
+ this.word = this.word.trim();
357
+ this.afterItem(char);
358
+ return;
359
+ }
360
+ throw new Error("havn't handled \"" + char + "\" in afterquote yet, index " + this.place);
361
+ };
362
+ Parser.prototype.afterItem = function(char) {
363
+ if (char === ",") {
364
+ if (this.word !== null) this.currentObject.push(this.word);
365
+ this.word = null;
366
+ this.state = NEUTRAL;
367
+ return;
368
+ }
369
+ if (char === "]") {
370
+ this.level--;
371
+ if (this.word !== null) {
372
+ this.currentObject.push(this.word);
373
+ this.word = null;
374
+ }
375
+ this.state = NEUTRAL;
376
+ this.currentObject = this.stack.pop();
377
+ if (!this.currentObject) this.state = ENDED;
378
+ return;
379
+ }
380
+ };
381
+ Parser.prototype.number = function(char) {
382
+ if (digets.test(char)) {
383
+ this.word += char;
384
+ return;
385
+ }
386
+ if (endThings.test(char)) {
387
+ this.word = parseFloat(this.word);
388
+ this.afterItem(char);
389
+ return;
390
+ }
391
+ throw new Error("havn't handled \"" + char + "\" in number yet, index " + this.place);
392
+ };
393
+ Parser.prototype.quoted = function(char) {
394
+ if (char === "\"") {
395
+ this.state = AFTERQUOTE;
396
+ return;
397
+ }
398
+ this.word += char;
399
+ };
400
+ Parser.prototype.keyword = function(char) {
401
+ if (keyword.test(char)) {
402
+ this.word += char;
403
+ return;
404
+ }
405
+ if (char === "[") {
406
+ var newObjects = [];
407
+ newObjects.push(this.word);
408
+ this.level++;
409
+ if (this.root === null) this.root = newObjects;
410
+ else this.currentObject.push(newObjects);
411
+ this.stack.push(this.currentObject);
412
+ this.currentObject = newObjects;
413
+ this.state = NEUTRAL;
414
+ return;
415
+ }
416
+ if (endThings.test(char)) {
417
+ this.afterItem(char);
418
+ return;
419
+ }
420
+ throw new Error("havn't handled \"" + char + "\" in keyword yet, index " + this.place);
421
+ };
422
+ Parser.prototype.neutral = function(char) {
423
+ if (latin.test(char)) {
424
+ this.word = char;
425
+ this.state = KEYWORD;
426
+ return;
427
+ }
428
+ if (char === "\"") {
429
+ this.word = "";
430
+ this.state = QUOTED;
431
+ return;
432
+ }
433
+ if (digets.test(char)) {
434
+ this.word = char;
435
+ this.state = NUMBER;
436
+ return;
437
+ }
438
+ if (endThings.test(char)) {
439
+ this.afterItem(char);
440
+ return;
441
+ }
442
+ throw new Error("havn't handled \"" + char + "\" in neutral yet, index " + this.place);
443
+ };
444
+ Parser.prototype.output = function() {
445
+ while (this.place < this.text.length) this.readCharicter();
446
+ if (this.state === ENDED) return this.root;
447
+ throw new Error("unable to parse string \"" + this.text + "\". State is " + this.state);
448
+ };
449
+ function parseString(txt) {
450
+ return new Parser(txt).output();
451
+ }
452
+ //#endregion
453
+ //#region node_modules/wkt-parser/process.js
454
+ function mapit(obj, key, value) {
455
+ if (Array.isArray(key)) {
456
+ value.unshift(key);
457
+ key = null;
458
+ }
459
+ var thing = key ? {} : obj;
460
+ var out = value.reduce(function(newObj, item) {
461
+ sExpr(item, newObj);
462
+ return newObj;
463
+ }, thing);
464
+ if (key) obj[key] = out;
465
+ }
466
+ function sExpr(v, obj) {
467
+ if (!Array.isArray(v)) {
468
+ obj[v] = true;
469
+ return;
1053
470
  }
1054
- projectedTileCorners(col, row) {
1055
- const tw = this.tileWidth;
1056
- const th = this.tileHeight;
1057
- const af = this._affine;
1058
- return {
1059
- topLeft: apply(af, col * tw, row * th),
1060
- topRight: apply(af, (col + 1) * tw, row * th),
1061
- bottomLeft: apply(af, col * tw, (row + 1) * th),
1062
- bottomRight: apply(af, (col + 1) * tw, (row + 1) * th)
1063
- };
471
+ var key = v.shift();
472
+ if (key === "PARAMETER") key = v.shift();
473
+ if (v.length === 1) {
474
+ if (Array.isArray(v[0])) {
475
+ obj[key] = {};
476
+ sExpr(v[0], obj[key]);
477
+ return;
478
+ }
479
+ obj[key] = v[0];
480
+ return;
1064
481
  }
1065
- tileTransform(col, row) {
1066
- const tileOffset = translation(col * this.tileWidth, row * this.tileHeight);
1067
- const tileAffine = compose(this._affine, tileOffset);
1068
- const invTileAffine = invert$2(tileAffine);
1069
- return {
1070
- forwardTransform: (x, y) => apply(tileAffine, x, y),
1071
- inverseTransform: (x, y) => apply(invTileAffine, x, y)
1072
- };
482
+ if (!v.length) {
483
+ obj[key] = true;
484
+ return;
1073
485
  }
1074
- crsBoundsToTileRange(projectedMinX, projectedMinY, projectedMaxX, projectedMaxY) {
1075
- const inv = this._invAffine;
1076
- const pixelCorners = [
1077
- apply(inv, projectedMinX, projectedMinY),
1078
- apply(inv, projectedMaxX, projectedMinY),
1079
- apply(inv, projectedMinX, projectedMaxY),
1080
- apply(inv, projectedMaxX, projectedMaxY)
1081
- ];
1082
- const xs = pixelCorners.map(([px]) => px);
1083
- const ys = pixelCorners.map(([, py]) => py);
1084
- const pixMinX = Math.min(...xs);
1085
- const pixMaxX = Math.max(...xs);
1086
- const pixMinY = Math.min(...ys);
1087
- const pixMaxY = Math.max(...ys);
1088
- const tw = this.tileWidth;
1089
- const th = this.tileHeight;
1090
- const maxColIdx = this.matrixWidth - 1;
1091
- const maxRowIdx = this.matrixHeight - 1;
1092
- return {
1093
- minCol: Math.max(0, Math.floor(pixMinX / tw)),
1094
- maxCol: Math.min(maxColIdx, Math.floor(pixMaxX / tw)),
1095
- minRow: Math.max(0, Math.floor(pixMinY / th)),
1096
- maxRow: Math.min(maxRowIdx, Math.floor(pixMaxY / th))
1097
- };
486
+ if (key === "TOWGS84") {
487
+ obj[key] = v;
488
+ return;
1098
489
  }
1099
- };
1100
- //#endregion
1101
- //#region node_modules/@developmentseed/proj/dist/meters-per-unit.js
1102
- /**
1103
- * Coefficient to convert the coordinate reference system (CRS)
1104
- * units into meters (metersPerUnit).
1105
- *
1106
- * From note g in http://docs.opengeospatial.org/is/17-083r2/17-083r2.html#table_2:
1107
- *
1108
- * > If the CRS uses meters as units of measure for the horizontal dimensions,
1109
- * > then metersPerUnit=1; if it has degrees, then metersPerUnit=2pa/360
1110
- * > (a is the Earth maximum radius of the ellipsoid).
1111
- *
1112
- * @param unit - The unit of the CRS.
1113
- * @param semiMajorAxis - The semi-major axis of the ellipsoid, required if unit is 'degree'.
1114
- * @returns The meters per unit conversion factor.
1115
- */
1116
- function metersPerUnit(unit, { semiMajorAxis } = {}) {
1117
- unit = unit.toLowerCase();
1118
- switch (unit) {
1119
- case "m":
1120
- case "metre":
1121
- case "meter":
1122
- case "meters": return 1;
1123
- case "foot": return .3048;
1124
- case "us survey foot": return 1200 / 3937;
490
+ if (key === "AXIS") {
491
+ if (!(key in obj)) obj[key] = [];
492
+ obj[key].push(v);
493
+ return;
1125
494
  }
1126
- if (unit === "degree") {
1127
- if (semiMajorAxis === void 0) throw new Error("CRS with degrees unit requires ellipsoid semi-major-axis");
1128
- return 2 * Math.PI * semiMajorAxis / 360;
495
+ if (!Array.isArray(key)) obj[key] = {};
496
+ var i;
497
+ switch (key) {
498
+ case "UNIT":
499
+ case "PRIMEM":
500
+ case "VERT_DATUM":
501
+ obj[key] = {
502
+ name: v[0].toLowerCase(),
503
+ convert: v[1]
504
+ };
505
+ if (v.length === 3) sExpr(v[2], obj[key]);
506
+ return;
507
+ case "SPHEROID":
508
+ case "ELLIPSOID":
509
+ obj[key] = {
510
+ name: v[0],
511
+ a: v[1],
512
+ rf: v[2]
513
+ };
514
+ if (v.length === 4) sExpr(v[3], obj[key]);
515
+ return;
516
+ case "EDATUM":
517
+ case "ENGINEERINGDATUM":
518
+ case "LOCAL_DATUM":
519
+ case "DATUM":
520
+ case "VERT_CS":
521
+ case "VERTCRS":
522
+ case "VERTICALCRS":
523
+ v[0] = ["name", v[0]];
524
+ mapit(obj, key, v);
525
+ return;
526
+ case "COMPD_CS":
527
+ case "COMPOUNDCRS":
528
+ case "FITTED_CS":
529
+ case "PROJECTEDCRS":
530
+ case "PROJCRS":
531
+ case "GEOGCS":
532
+ case "GEOCCS":
533
+ case "PROJCS":
534
+ case "LOCAL_CS":
535
+ case "GEODCRS":
536
+ case "GEODETICCRS":
537
+ case "GEODETICDATUM":
538
+ case "ENGCRS":
539
+ case "ENGINEERINGCRS":
540
+ v[0] = ["name", v[0]];
541
+ mapit(obj, key, v);
542
+ obj[key].type = key;
543
+ return;
544
+ default:
545
+ i = -1;
546
+ while (++i < v.length) if (!Array.isArray(v[i])) return sExpr(v, obj[key]);
547
+ return mapit(obj, key, v);
1129
548
  }
1130
- throw new Error(`Unsupported CRS units: ${unit} when computing metersPerUnit.`);
1131
549
  }
1132
550
  //#endregion
1133
- //#region node_modules/wkt-parser/PROJJSONBuilderBase.js
1134
- var PROJJSONBuilderBase = class {
1135
- static getId(node) {
1136
- const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
1137
- if (idNode && idNode.length >= 3) return {
1138
- authority: idNode[1],
1139
- code: parseInt(idNode[2], 10)
1140
- };
1141
- return null;
551
+ //#region node_modules/wkt-parser/util.js
552
+ var D2R$1 = .017453292519943295;
553
+ function d2r(input) {
554
+ return input * D2R$1;
555
+ }
556
+ function applyProjectionDefaults(wkt) {
557
+ const normalizedProjName = (wkt.projName || "").toLowerCase().replace(/_/g, " ");
558
+ if (wkt.long0 === void 0 && wkt.longc !== void 0) wkt.long0 = wkt.longc;
559
+ if (!wkt.lat_ts && wkt.lat1 && (normalizedProjName === "stereographic south pole" || normalizedProjName === "polar stereographic (variant b)")) {
560
+ wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90);
561
+ wkt.lat_ts = wkt.lat1;
562
+ delete wkt.lat1;
563
+ } else if (!wkt.lat_ts && wkt.lat0 && (normalizedProjName === "polar stereographic" || normalizedProjName === "polar stereographic (variant a)")) {
564
+ wkt.lat_ts = wkt.lat0;
565
+ wkt.lat0 = d2r(wkt.lat0 > 0 ? 90 : -90);
566
+ delete wkt.lat1;
1142
567
  }
1143
- static convertUnit(node, type = "unit") {
1144
- if (!node || node.length < 3) return {
1145
- type,
1146
- name: "unknown",
1147
- conversion_factor: null
1148
- };
1149
- const name = node[1];
1150
- const conversionFactor = parseFloat(node[2]) || null;
1151
- const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
1152
- return {
1153
- type,
1154
- name,
1155
- conversion_factor: conversionFactor,
1156
- id: idNode ? {
1157
- authority: idNode[1],
1158
- code: parseInt(idNode[2], 10)
1159
- } : null
1160
- };
568
+ }
569
+ //#endregion
570
+ //#region node_modules/wkt-parser/transformPROJJSON.js
571
+ function processUnit(unit) {
572
+ let result = {
573
+ units: null,
574
+ to_meter: void 0
575
+ };
576
+ if (typeof unit === "string") {
577
+ result.units = unit.toLowerCase();
578
+ if (result.units === "metre") result.units = "meter";
579
+ if (result.units === "meter") result.to_meter = 1;
580
+ } else if (unit && unit.name) {
581
+ result.units = unit.name.toLowerCase();
582
+ if (result.units === "metre") result.units = "meter";
583
+ result.to_meter = unit.conversion_factor;
1161
584
  }
1162
- static convertAxis(node) {
1163
- const name = node[1] || "Unknown";
1164
- let direction;
1165
- const abbreviationMatch = name.match(/^\((.)\)$/);
1166
- if (abbreviationMatch) {
1167
- const abbreviation = abbreviationMatch[1].toUpperCase();
1168
- if (abbreviation === "E") direction = "east";
1169
- else if (abbreviation === "N") direction = "north";
1170
- else if (abbreviation === "U") direction = "up";
1171
- else if (node[2]) direction = node[2];
1172
- else throw new Error(`Unknown axis abbreviation: ${abbreviation}`);
1173
- } else direction = node[2] || "unknown";
1174
- const orderNode = node.find((child) => Array.isArray(child) && child[0] === "ORDER");
1175
- const order = orderNode ? parseInt(orderNode[1], 10) : null;
1176
- const unitNode = node.find((child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT"));
1177
- const unit = this.convertUnit(unitNode);
1178
- return {
1179
- name,
1180
- direction,
1181
- unit,
1182
- order
1183
- };
585
+ return result;
586
+ }
587
+ function toValue(valueOrObject) {
588
+ if (typeof valueOrObject === "object") return valueOrObject.value * valueOrObject.unit.conversion_factor;
589
+ return valueOrObject;
590
+ }
591
+ function calculateEllipsoid(value, result) {
592
+ if (value.ellipsoid.radius) {
593
+ result.a = value.ellipsoid.radius;
594
+ result.rf = 0;
595
+ } else {
596
+ result.a = toValue(value.ellipsoid.semi_major_axis);
597
+ if (value.ellipsoid.inverse_flattening !== void 0) result.rf = value.ellipsoid.inverse_flattening;
598
+ else if (value.ellipsoid.semi_major_axis !== void 0 && value.ellipsoid.semi_minor_axis !== void 0) result.rf = result.a / (result.a - toValue(value.ellipsoid.semi_minor_axis));
1184
599
  }
1185
- static extractAxes(node) {
1186
- return node.filter((child) => Array.isArray(child) && child[0] === "AXIS").map((axis) => this.convertAxis(axis)).sort((a, b) => (a.order || 0) - (b.order || 0));
600
+ }
601
+ function transformPROJJSON(projjson, result = {}) {
602
+ if (!projjson || typeof projjson !== "object") return projjson;
603
+ if (projjson.type === "BoundCRS") {
604
+ transformPROJJSON(projjson.source_crs, result);
605
+ if (projjson.transformation) if (projjson.transformation.method && projjson.transformation.method.name === "NTv2") result.nadgrids = projjson.transformation.parameters[0].value;
606
+ else result.datum_params = projjson.transformation.parameters.map((param) => param.value);
607
+ return result;
1187
608
  }
1188
- static convert(node, result = {}) {
1189
- switch (node[0]) {
1190
- case "PROJCRS":
1191
- result.type = "ProjectedCRS";
1192
- result.name = node[1];
1193
- result.base_crs = node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS")) : null;
1194
- result.conversion = node.find((child) => Array.isArray(child) && child[0] === "CONVERSION") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "CONVERSION")) : null;
1195
- const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
1196
- if (csNode) result.coordinate_system = {
1197
- type: csNode[1],
1198
- axis: this.extractAxes(node)
1199
- };
1200
- const lengthUnitNode = node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT");
1201
- if (lengthUnitNode) {
1202
- const unit = this.convertUnit(lengthUnitNode);
1203
- result.coordinate_system.unit = unit;
1204
- }
1205
- result.id = this.getId(node);
1206
- break;
1207
- case "BASEGEOGCRS":
1208
- case "GEOGCRS":
1209
- case "GEODCRS":
1210
- result.type = node[0] === "GEODCRS" ? "GeodeticCRS" : "GeographicCRS";
1211
- result.name = node[1];
1212
- const datumOrEnsembleNode = node.find((child) => Array.isArray(child) && (child[0] === "DATUM" || child[0] === "ENSEMBLE"));
1213
- if (datumOrEnsembleNode) {
1214
- const datumOrEnsemble = this.convert(datumOrEnsembleNode);
1215
- if (datumOrEnsembleNode[0] === "ENSEMBLE") result.datum_ensemble = datumOrEnsemble;
1216
- else result.datum = datumOrEnsemble;
1217
- const primem = node.find((child) => Array.isArray(child) && child[0] === "PRIMEM");
1218
- if (primem && primem[1] !== "Greenwich") datumOrEnsemble.prime_meridian = {
1219
- name: primem[1],
1220
- longitude: parseFloat(primem[2])
1221
- };
1222
- }
1223
- result.coordinate_system = {
1224
- type: "ellipsoidal",
1225
- axis: this.extractAxes(node)
1226
- };
1227
- result.id = this.getId(node);
1228
- break;
1229
- case "DATUM":
1230
- result.type = "GeodeticReferenceFrame";
1231
- result.name = node[1];
1232
- result.ellipsoid = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID")) : null;
1233
- break;
1234
- case "ENSEMBLE":
1235
- result.type = "DatumEnsemble";
1236
- result.name = node[1];
1237
- result.members = node.filter((child) => Array.isArray(child) && child[0] === "MEMBER").map((member) => ({
1238
- type: "DatumEnsembleMember",
1239
- name: member[1],
1240
- id: this.getId(member)
1241
- }));
1242
- const accuracyNode = node.find((child) => Array.isArray(child) && child[0] === "ENSEMBLEACCURACY");
1243
- if (accuracyNode) result.accuracy = parseFloat(accuracyNode[1]);
1244
- const ellipsoidNode = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID");
1245
- if (ellipsoidNode) result.ellipsoid = this.convert(ellipsoidNode);
1246
- result.id = this.getId(node);
1247
- break;
1248
- case "ELLIPSOID":
1249
- result.type = "Ellipsoid";
1250
- result.name = node[1];
1251
- result.semi_major_axis = parseFloat(node[2]);
1252
- result.inverse_flattening = parseFloat(node[3]);
1253
- node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT") && this.convert(node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT"), result);
609
+ Object.keys(projjson).forEach((key) => {
610
+ const value = projjson[key];
611
+ if (value === null) return;
612
+ switch (key) {
613
+ case "name":
614
+ if (result.srsCode) break;
615
+ result.name = value;
616
+ result.srsCode = value;
1254
617
  break;
1255
- case "CONVERSION":
1256
- result.type = "Conversion";
1257
- result.name = node[1];
1258
- result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
1259
- result.parameters = node.filter((child) => Array.isArray(child) && child[0] === "PARAMETER").map((param) => this.convert(param));
618
+ case "type":
619
+ if (value === "GeographicCRS") result.projName = "longlat";
620
+ else if (value === "GeodeticCRS") if (projjson.coordinate_system && projjson.coordinate_system.subtype === "Cartesian") result.projName = "geocent";
621
+ else result.projName = "longlat";
622
+ else if (value === "ProjectedCRS" && projjson.conversion && projjson.conversion.method) result.projName = projjson.conversion.method.name;
1260
623
  break;
1261
- case "METHOD":
1262
- result.type = "Method";
1263
- result.name = node[1];
1264
- result.id = this.getId(node);
624
+ case "datum":
625
+ case "datum_ensemble":
626
+ if (value.ellipsoid) {
627
+ result.ellps = value.ellipsoid.name;
628
+ calculateEllipsoid(value, result);
629
+ }
630
+ if (value.prime_meridian) result.from_greenwich = value.prime_meridian.longitude * Math.PI / 180;
1265
631
  break;
1266
- case "PARAMETER":
1267
- result.type = "Parameter";
1268
- result.name = node[1];
1269
- result.value = parseFloat(node[2]);
1270
- result.unit = this.convertUnit(node.find((child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT")));
1271
- result.id = this.getId(node);
632
+ case "ellipsoid":
633
+ result.ellps = value.name;
634
+ calculateEllipsoid(value, result);
1272
635
  break;
1273
- case "BOUNDCRS":
1274
- result.type = "BoundCRS";
1275
- const sourceCrsNode = node.find((child) => Array.isArray(child) && child[0] === "SOURCECRS");
1276
- if (sourceCrsNode) {
1277
- const sourceCrsContent = sourceCrsNode.find((child) => Array.isArray(child));
1278
- result.source_crs = sourceCrsContent ? this.convert(sourceCrsContent) : null;
1279
- }
1280
- const targetCrsNode = node.find((child) => Array.isArray(child) && child[0] === "TARGETCRS");
1281
- if (targetCrsNode) {
1282
- const targetCrsContent = targetCrsNode.find((child) => Array.isArray(child));
1283
- result.target_crs = targetCrsContent ? this.convert(targetCrsContent) : null;
1284
- }
1285
- const transformationNode = node.find((child) => Array.isArray(child) && child[0] === "ABRIDGEDTRANSFORMATION");
1286
- if (transformationNode) result.transformation = this.convert(transformationNode);
1287
- else result.transformation = null;
636
+ case "prime_meridian":
637
+ result.long0 = (value.longitude || 0) * Math.PI / 180;
1288
638
  break;
1289
- case "ABRIDGEDTRANSFORMATION":
1290
- result.type = "Transformation";
1291
- result.name = node[1];
1292
- result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
1293
- result.parameters = node.filter((child) => Array.isArray(child) && (child[0] === "PARAMETER" || child[0] === "PARAMETERFILE")).map((param) => {
1294
- if (param[0] === "PARAMETER") return this.convert(param);
1295
- else if (param[0] === "PARAMETERFILE") return {
1296
- name: param[1],
1297
- value: param[2],
1298
- id: {
1299
- "authority": "EPSG",
1300
- "code": 8656
1301
- }
639
+ case "coordinate_system":
640
+ if (value.axis) {
641
+ const directionMap = {
642
+ "east": "e",
643
+ "north": "n",
644
+ "west": "w",
645
+ "south": "s",
646
+ "up": "u",
647
+ "down": "d",
648
+ "geocentricx": "e",
649
+ "geocentricy": "n",
650
+ "geocentricz": "u"
1302
651
  };
1303
- });
1304
- if (result.parameters.length === 7) {
1305
- const scaleDifference = result.parameters[6];
1306
- if (scaleDifference.name === "Scale difference") scaleDifference.value = Math.round((scaleDifference.value - 1) * 0xe8d4a51000) / 1e6;
652
+ const mapped = value.axis.map((axis) => directionMap[axis.direction.toLowerCase()]);
653
+ if (mapped.every(Boolean)) {
654
+ result.axis = mapped.join("");
655
+ if (result.axis.length === 2) result.axis += "u";
656
+ }
657
+ if (value.unit) {
658
+ const { units, to_meter } = processUnit(value.unit);
659
+ result.units = units;
660
+ result.to_meter = to_meter;
661
+ } else if (value.axis[0] && value.axis[0].unit) {
662
+ const { units, to_meter } = processUnit(value.axis[0].unit);
663
+ result.units = units;
664
+ result.to_meter = to_meter;
665
+ }
1307
666
  }
1308
- result.id = this.getId(node);
1309
667
  break;
1310
- case "AXIS":
1311
- if (!result.coordinate_system) result.coordinate_system = {
1312
- type: "unspecified",
1313
- axis: []
1314
- };
1315
- result.coordinate_system.axis.push(this.convertAxis(node));
668
+ case "id":
669
+ if (value.authority && value.code) result.title = value.authority + ":" + value.code;
1316
670
  break;
1317
- case "LENGTHUNIT":
1318
- const unit = this.convertUnit(node, "LinearUnit");
1319
- if (result.coordinate_system && result.coordinate_system.axis) result.coordinate_system.axis.forEach((axis) => {
1320
- if (!axis.unit) axis.unit = unit;
671
+ case "conversion":
672
+ if (value.method && value.method.name) result.projName = value.method.name;
673
+ if (value.parameters) value.parameters.forEach((param) => {
674
+ const paramName = param.name.toLowerCase().replace(/\s+/g, "_");
675
+ const paramValue = param.value;
676
+ if (param.unit && param.unit.conversion_factor) result[paramName] = paramValue * param.unit.conversion_factor;
677
+ else if (param.unit === "degree") result[paramName] = paramValue * Math.PI / 180;
678
+ else result[paramName] = paramValue;
1321
679
  });
1322
- if (unit.conversion_factor && unit.conversion_factor !== 1) {
1323
- if (result.semi_major_axis) result.semi_major_axis = {
1324
- value: result.semi_major_axis,
1325
- unit
1326
- };
680
+ break;
681
+ case "unit":
682
+ if (value.name) {
683
+ result.units = value.name.toLowerCase();
684
+ if (result.units === "metre") result.units = "meter";
1327
685
  }
686
+ if (value.conversion_factor) result.to_meter = value.conversion_factor;
1328
687
  break;
1329
- default:
1330
- result.keyword = node[0];
688
+ case "base_crs":
689
+ transformPROJJSON(value, result);
690
+ result.datumCode = value.id ? value.id.authority + "_" + value.id.code : value.name;
1331
691
  break;
692
+ default: break;
693
+ }
694
+ });
695
+ if (result.latitude_of_false_origin !== void 0) result.lat0 = result.latitude_of_false_origin;
696
+ if (result.longitude_of_false_origin !== void 0) result.long0 = result.longitude_of_false_origin;
697
+ if (result.latitude_of_standard_parallel !== void 0) {
698
+ result.lat0 = result.latitude_of_standard_parallel;
699
+ result.lat1 = result.latitude_of_standard_parallel;
700
+ }
701
+ if (result.latitude_of_1st_standard_parallel !== void 0) result.lat1 = result.latitude_of_1st_standard_parallel;
702
+ if (result.latitude_of_2nd_standard_parallel !== void 0) result.lat2 = result.latitude_of_2nd_standard_parallel;
703
+ if (result.latitude_of_projection_centre !== void 0) result.lat0 = result.latitude_of_projection_centre;
704
+ if (result.longitude_of_projection_centre !== void 0) result.longc = result.longitude_of_projection_centre;
705
+ if (result.easting_at_false_origin !== void 0) result.x0 = result.easting_at_false_origin;
706
+ if (result.northing_at_false_origin !== void 0) result.y0 = result.northing_at_false_origin;
707
+ if (result.latitude_of_natural_origin !== void 0) result.lat0 = result.latitude_of_natural_origin;
708
+ if (result.longitude_of_natural_origin !== void 0) result.long0 = result.longitude_of_natural_origin;
709
+ if (result.longitude_of_origin !== void 0) result.long0 = result.longitude_of_origin;
710
+ if (result.false_easting !== void 0) result.x0 = result.false_easting;
711
+ if (result.easting_at_projection_centre) result.x0 = result.easting_at_projection_centre;
712
+ if (result.false_northing !== void 0) result.y0 = result.false_northing;
713
+ if (result.northing_at_projection_centre) result.y0 = result.northing_at_projection_centre;
714
+ if (result.standard_parallel_1 !== void 0) result.lat1 = result.standard_parallel_1;
715
+ if (result.standard_parallel_2 !== void 0) result.lat2 = result.standard_parallel_2;
716
+ if (result.scale_factor_at_natural_origin !== void 0) result.k0 = result.scale_factor_at_natural_origin;
717
+ if (result.scale_factor_at_projection_centre !== void 0) result.k0 = result.scale_factor_at_projection_centre;
718
+ if (result.scale_factor_on_pseudo_standard_parallel !== void 0) result.k0 = result.scale_factor_on_pseudo_standard_parallel;
719
+ if (result.azimuth !== void 0) result.alpha = result.azimuth;
720
+ if (result.azimuth_at_projection_centre !== void 0) result.alpha = result.azimuth_at_projection_centre;
721
+ if (result.angle_from_rectified_to_skew_grid) result.rectified_grid_angle = result.angle_from_rectified_to_skew_grid;
722
+ applyProjectionDefaults(result);
723
+ return result;
724
+ }
725
+ //#endregion
726
+ //#region node_modules/wkt-parser/index.js
727
+ var knownTypes = [
728
+ "PROJECTEDCRS",
729
+ "PROJCRS",
730
+ "GEOGCS",
731
+ "GEOCCS",
732
+ "PROJCS",
733
+ "LOCAL_CS",
734
+ "GEODCRS",
735
+ "GEODETICCRS",
736
+ "GEODETICDATUM",
737
+ "ENGCRS",
738
+ "ENGINEERINGCRS"
739
+ ];
740
+ function rename(obj, params) {
741
+ var outName = params[0];
742
+ var inName = params[1];
743
+ if (!(outName in obj) && inName in obj) {
744
+ obj[outName] = obj[inName];
745
+ if (params.length === 3) obj[outName] = params[2](obj[outName]);
746
+ }
747
+ }
748
+ function cleanWKT(wkt) {
749
+ var keys = Object.keys(wkt);
750
+ for (var i = 0, ii = keys.length; i < ii; ++i) {
751
+ var key = keys[i];
752
+ if (knownTypes.indexOf(key) !== -1) setPropertiesFromWkt(wkt[key]);
753
+ if (typeof wkt[key] === "object") cleanWKT(wkt[key]);
754
+ }
755
+ }
756
+ function setPropertiesFromWkt(wkt) {
757
+ if (wkt.AUTHORITY) {
758
+ var authority = Object.keys(wkt.AUTHORITY)[0];
759
+ if (authority && authority in wkt.AUTHORITY) wkt.title = authority + ":" + wkt.AUTHORITY[authority];
760
+ }
761
+ if (wkt.type === "GEOGCS") wkt.projName = "longlat";
762
+ else if (wkt.type === "LOCAL_CS") {
763
+ wkt.projName = "identity";
764
+ wkt.local = true;
765
+ } else if (typeof wkt.PROJECTION === "object") wkt.projName = Object.keys(wkt.PROJECTION)[0];
766
+ else wkt.projName = wkt.PROJECTION;
767
+ if (wkt.AXIS) {
768
+ var axisOrder = "";
769
+ for (var i = 0, ii = wkt.AXIS.length; i < ii; ++i) {
770
+ var axis = [wkt.AXIS[i][0].toLowerCase(), wkt.AXIS[i][1].toLowerCase()];
771
+ if (axis[0].indexOf("north") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "north") axisOrder += "n";
772
+ else if (axis[0].indexOf("south") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "south") axisOrder += "s";
773
+ else if (axis[0].indexOf("east") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "east") axisOrder += "e";
774
+ else if (axis[0].indexOf("west") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "west") axisOrder += "w";
1332
775
  }
1333
- return result;
776
+ if (axisOrder.length === 2) axisOrder += "u";
777
+ if (axisOrder.length === 3) wkt.axis = axisOrder;
1334
778
  }
1335
- };
779
+ if (wkt.UNIT) {
780
+ wkt.units = wkt.UNIT.name.toLowerCase();
781
+ if (wkt.units === "metre") wkt.units = "meter";
782
+ if (wkt.UNIT.convert) if (wkt.type === "GEOGCS") {
783
+ if (wkt.DATUM && wkt.DATUM.SPHEROID) wkt.to_meter = wkt.UNIT.convert * wkt.DATUM.SPHEROID.a;
784
+ } else wkt.to_meter = wkt.UNIT.convert;
785
+ }
786
+ var geogcs = wkt.GEOGCS;
787
+ if (wkt.type === "GEOGCS") geogcs = wkt;
788
+ if (geogcs) {
789
+ if (geogcs.PRIMEM && geogcs.PRIMEM.convert) wkt.from_greenwich = d2r(geogcs.PRIMEM.convert);
790
+ if (geogcs.DATUM) wkt.datumCode = geogcs.DATUM.name.toLowerCase();
791
+ else wkt.datumCode = geogcs.name.toLowerCase();
792
+ if (wkt.datumCode.slice(0, 2) === "d_") wkt.datumCode = wkt.datumCode.slice(2);
793
+ if (wkt.datumCode === "new_zealand_1949") wkt.datumCode = "nzgd49";
794
+ if (wkt.datumCode === "wgs_1984" || wkt.datumCode === "world_geodetic_system_1984") {
795
+ if (wkt.PROJECTION === "Mercator_Auxiliary_Sphere") wkt.sphere = true;
796
+ wkt.datumCode = "wgs84";
797
+ }
798
+ if (wkt.datumCode === "belge_1972") wkt.datumCode = "rnb72";
799
+ if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
800
+ wkt.ellps = geogcs.DATUM.SPHEROID.name.replace("_19", "").replace(/[Cc]larke\_18/, "clrk");
801
+ if (wkt.ellps.toLowerCase().slice(0, 13) === "international") wkt.ellps = "intl";
802
+ wkt.a = geogcs.DATUM.SPHEROID.a;
803
+ wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf);
804
+ }
805
+ if (geogcs.DATUM && geogcs.DATUM.TOWGS84) wkt.datum_params = geogcs.DATUM.TOWGS84;
806
+ if (~wkt.datumCode.indexOf("osgb_1936")) wkt.datumCode = "osgb36";
807
+ if (~wkt.datumCode.indexOf("osni_1952")) wkt.datumCode = "osni52";
808
+ if (~wkt.datumCode.indexOf("tm65") || ~wkt.datumCode.indexOf("geodetic_datum_of_1965")) wkt.datumCode = "ire65";
809
+ if (wkt.datumCode === "ch1903+") wkt.datumCode = "ch1903";
810
+ if (~wkt.datumCode.indexOf("israel")) wkt.datumCode = "isr93";
811
+ }
812
+ if (wkt.b && !isFinite(wkt.b)) wkt.b = wkt.a;
813
+ if (wkt.rectified_grid_angle) wkt.rectified_grid_angle = d2r(wkt.rectified_grid_angle);
814
+ function toMeter(input) {
815
+ return input * (wkt.to_meter || 1);
816
+ }
817
+ var renamer = function(a) {
818
+ return rename(wkt, a);
819
+ };
820
+ [
821
+ ["standard_parallel_1", "Standard_Parallel_1"],
822
+ ["standard_parallel_1", "Latitude of 1st standard parallel"],
823
+ ["standard_parallel_2", "Standard_Parallel_2"],
824
+ ["standard_parallel_2", "Latitude of 2nd standard parallel"],
825
+ ["false_easting", "False_Easting"],
826
+ ["false_easting", "False easting"],
827
+ ["false-easting", "Easting at false origin"],
828
+ ["false_northing", "False_Northing"],
829
+ ["false_northing", "False northing"],
830
+ ["false_northing", "Northing at false origin"],
831
+ ["central_meridian", "Central_Meridian"],
832
+ ["central_meridian", "Longitude of natural origin"],
833
+ ["central_meridian", "Longitude of false origin"],
834
+ ["latitude_of_origin", "Latitude_Of_Origin"],
835
+ ["latitude_of_origin", "Central_Parallel"],
836
+ ["latitude_of_origin", "Latitude of natural origin"],
837
+ ["latitude_of_origin", "Latitude of false origin"],
838
+ ["scale_factor", "Scale_Factor"],
839
+ ["k0", "scale_factor"],
840
+ ["latitude_of_center", "Latitude_Of_Center"],
841
+ ["latitude_of_center", "Latitude_of_center"],
842
+ [
843
+ "lat0",
844
+ "latitude_of_center",
845
+ d2r
846
+ ],
847
+ ["longitude_of_center", "Longitude_Of_Center"],
848
+ ["longitude_of_center", "Longitude_of_center"],
849
+ [
850
+ "longc",
851
+ "longitude_of_center",
852
+ d2r
853
+ ],
854
+ [
855
+ "x0",
856
+ "false_easting",
857
+ toMeter
858
+ ],
859
+ [
860
+ "y0",
861
+ "false_northing",
862
+ toMeter
863
+ ],
864
+ [
865
+ "long0",
866
+ "central_meridian",
867
+ d2r
868
+ ],
869
+ [
870
+ "lat0",
871
+ "latitude_of_origin",
872
+ d2r
873
+ ],
874
+ [
875
+ "lat0",
876
+ "standard_parallel_1",
877
+ d2r
878
+ ],
879
+ [
880
+ "lat1",
881
+ "standard_parallel_1",
882
+ d2r
883
+ ],
884
+ [
885
+ "lat2",
886
+ "standard_parallel_2",
887
+ d2r
888
+ ],
889
+ ["azimuth", "Azimuth"],
890
+ [
891
+ "alpha",
892
+ "azimuth",
893
+ d2r
894
+ ],
895
+ ["srsCode", "name"]
896
+ ].forEach(renamer);
897
+ applyProjectionDefaults(wkt);
898
+ }
899
+ function wkt_parser_default(wkt) {
900
+ if (typeof wkt === "object") return transformPROJJSON(wkt);
901
+ const version = detectWKTVersion(wkt);
902
+ var lisp = parser_default(wkt);
903
+ if (version === "WKT2") return transformPROJJSON(buildPROJJSON(lisp));
904
+ var type = lisp[0];
905
+ var obj = {};
906
+ sExpr(lisp, obj);
907
+ cleanWKT(obj);
908
+ return obj[type];
909
+ }
1336
910
  //#endregion
1337
- //#region node_modules/wkt-parser/PROJJSONBuilder2015.js
1338
- var PROJJSONBuilder2015 = class extends PROJJSONBuilderBase {
1339
- static convert(node, result = {}) {
1340
- super.convert(node, result);
1341
- if (result.coordinate_system && result.coordinate_system.subtype === "Cartesian") delete result.coordinate_system;
1342
- if (result.usage) delete result.usage;
1343
- return result;
911
+ //#region node_modules/@developmentseed/proj/dist/parse-wkt.js
912
+ /**
913
+ * Parse a WKT string or PROJJSON object into a proj4-compatible projection
914
+ * definition.
915
+ *
916
+ * This is a typed wrapper around the `wkt-parser` package.
917
+ */
918
+ function parseWkt(input) {
919
+ const def = wkt_parser_default(input);
920
+ if (def.projName === "longlat" && (!def.units || def.units === "unknown")) {
921
+ def.units = "degree";
922
+ def.to_meter = void 0;
1344
923
  }
1345
- };
924
+ return def;
925
+ }
1346
926
  //#endregion
1347
- //#region node_modules/wkt-parser/PROJJSONBuilder2019.js
1348
- var PROJJSONBuilder2019 = class extends PROJJSONBuilderBase {
1349
- static convert(node, result = {}) {
1350
- super.convert(node, result);
1351
- const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
1352
- if (csNode) result.coordinate_system = {
1353
- subtype: csNode[1],
1354
- axis: this.extractAxes(node)
1355
- };
1356
- const usageNode = node.find((child) => Array.isArray(child) && child[0] === "USAGE");
1357
- if (usageNode) {
1358
- const scope = usageNode.find((child) => Array.isArray(child) && child[0] === "SCOPE");
1359
- const area = usageNode.find((child) => Array.isArray(child) && child[0] === "AREA");
1360
- const bbox = usageNode.find((child) => Array.isArray(child) && child[0] === "BBOX");
1361
- result.usage = {};
1362
- if (scope) result.usage.scope = scope[1];
1363
- if (area) result.usage.area = area[1];
1364
- if (bbox) result.usage.bbox = bbox.slice(1);
927
+ //#region node_modules/@developmentseed/proj/dist/registry.js
928
+ /**
929
+ * A global registry holding parsed projection definitions.
930
+ */
931
+ var PROJECTION_REGISTRY = /* @__PURE__ */ new Map();
932
+ async function epsgResolver(epsg) {
933
+ const key = `EPSG:${epsg}`;
934
+ const cachedProj = PROJECTION_REGISTRY.get(key);
935
+ if (cachedProj !== void 0) return cachedProj;
936
+ const proj = parseWkt(await getProjjson(epsg));
937
+ PROJECTION_REGISTRY.set(key, proj);
938
+ return proj;
939
+ }
940
+ /** Query epsg.io for the PROJJSON corresponding to the given EPSG code. */
941
+ async function getProjjson(epsg) {
942
+ const url = `https://epsg.io/${epsg}.json`;
943
+ const resp = await fetch(url);
944
+ if (!resp.ok) throw new Error(`Failed to fetch PROJJSON from ${url}`);
945
+ return await resp.json();
946
+ }
947
+ //#endregion
948
+ //#region node_modules/@developmentseed/proj/dist/transform-bounds.js
949
+ /**
950
+ * Transform boundary densifying the edges to account for nonlinear
951
+ * transformations along these edges and extracting the outermost bounds.
952
+ *
953
+ * @param project - function that maps (x, y) in source CRS to (x, y) in target CRS
954
+ * @param left - min X in source CRS
955
+ * @param bottom - min Y in source CRS
956
+ * @param right - max X in source CRS
957
+ * @param top - max Y in source CRS
958
+ * @param options.densifyPts - number of intermediate points along each edge (default 21)
959
+ * @returns [minX, minY, maxX, maxY] in the target CRS
960
+ */
961
+ function transformBounds(project, left, bottom, right, top, options = {}) {
962
+ const { densifyPts = 21 } = options;
963
+ const cx = [
964
+ left,
965
+ right,
966
+ right,
967
+ left
968
+ ];
969
+ const cy = [
970
+ bottom,
971
+ bottom,
972
+ top,
973
+ top
974
+ ];
975
+ let outMinX = Infinity;
976
+ let outMinY = Infinity;
977
+ let outMaxX = -Infinity;
978
+ let outMaxY = -Infinity;
979
+ for (let i = 0; i < 4; i++) {
980
+ const fromX = cx[i];
981
+ const fromY = cy[i];
982
+ const toX = cx[(i + 1) % 4];
983
+ const toY = cy[(i + 1) % 4];
984
+ for (let j = 0; j <= densifyPts; j++) {
985
+ const t = j / (densifyPts + 1);
986
+ const [px, py] = project(fromX + (toX - fromX) * t, fromY + (toY - fromY) * t);
987
+ if (px < outMinX) outMinX = px;
988
+ if (py < outMinY) outMinY = py;
989
+ if (px > outMaxX) outMaxX = px;
990
+ if (py > outMaxY) outMaxY = py;
1365
991
  }
1366
- return result;
1367
992
  }
1368
- };
993
+ return [
994
+ outMinX,
995
+ outMinY,
996
+ outMaxX,
997
+ outMaxY
998
+ ];
999
+ }
1369
1000
  //#endregion
1370
- //#region node_modules/wkt-parser/buildPROJJSON.js
1001
+ //#region node_modules/@developmentseed/proj/dist/web-mercator.js
1002
+ var WGS84_ELLIPSOID_A$1 = 6378137;
1003
+ var MAX_WEB_MERCATOR_LAT$1 = 85.05112877980659;
1371
1004
  /**
1372
- * Detects the WKT2 version based on the structure of the WKT.
1373
- * @param {Array} root The root WKT array node.
1374
- * @returns {string} The detected version ("2015" or "2019").
1005
+ * Convert a WGS84 longitude/latitude to EPSG:3857 meters analytically.
1006
+ * Valid for latitudes in [-MAX_WEB_MERCATOR_LAT, MAX_WEB_MERCATOR_LAT].
1375
1007
  */
1376
- function detectWKT2Version(root) {
1377
- if (root.find((child) => Array.isArray(child) && child[0] === "USAGE")) return "2019";
1378
- if (root.find((child) => Array.isArray(child) && child[0] === "CS")) return "2015";
1379
- if (root[0] === "BOUNDCRS" || root[0] === "PROJCRS" || root[0] === "GEOGCRS") return "2015";
1380
- return "2015";
1008
+ function wgs84To3857(lon, lat) {
1009
+ const x = lon * Math.PI * WGS84_ELLIPSOID_A$1 / 180;
1010
+ const latRad = lat * Math.PI / 180;
1011
+ return [x, Math.log(Math.tan(Math.PI / 4 + latRad / 2)) * WGS84_ELLIPSOID_A$1];
1381
1012
  }
1382
1013
  /**
1383
- * Builds a PROJJSON object from a WKT array structure.
1384
- * @param {Array} root The root WKT array node.
1385
- * @returns {Object} The PROJJSON object.
1014
+ * Wrap a proj4 forward projection to EPSG:3857 so that it never returns NaN.
1015
+ *
1016
+ * proj4 returns [NaN, NaN] for points at the poles (lat = ±90°) because the
1017
+ * Mercator projection is undefined there. The wrapper falls back to:
1018
+ * 1. Project the input to WGS84 via `forwardTo4326`
1019
+ * 2. Clamp the latitude to the Web Mercator limit (±85.05°)
1020
+ * 3. Convert analytically from WGS84 to EPSG:3857
1021
+ *
1022
+ * This correctly handles any input CRS, not just EPSG:4326.
1023
+ *
1024
+ * NOTE: An identical copy of this function lives in `raster-tile-traversal.ts`.
1025
+ * The two packages cannot share code due to their dependency relationship
1026
+ * (deck.gl-geotiff depends on deck.gl-raster, not vice versa). If this logic
1027
+ * changes, update both copies.
1028
+ *
1029
+ * Perhaps in the future we'll make a `@developmentseed/projections` package to
1030
+ * hold shared projection utilities like this. *
1386
1031
  */
1387
- function buildPROJJSON(root) {
1388
- return (detectWKT2Version(root) === "2019" ? PROJJSONBuilder2019 : PROJJSONBuilder2015).convert(root);
1032
+ function makeClampedForwardTo3857$1(forwardTo3857, forwardTo4326) {
1033
+ return (x, y) => {
1034
+ const [px, py] = forwardTo3857(x, y);
1035
+ if (Number.isFinite(px) && Number.isFinite(py)) return [px, py];
1036
+ const [lon, lat] = forwardTo4326(x, y);
1037
+ return wgs84To3857(lon, Math.max(-85.05112877980659, Math.min(MAX_WEB_MERCATOR_LAT$1, lat)));
1038
+ };
1389
1039
  }
1390
1040
  //#endregion
1391
- //#region node_modules/wkt-parser/detectWKTVersion.js
1041
+ //#region src/lib/raster/epsg-resolver.ts
1042
+ var OFFLINE_DEFS = new Map([[4326, parseWkt({
1043
+ type: "GeographicCRS",
1044
+ name: "WGS 84",
1045
+ datum: {
1046
+ type: "GeodeticReferenceFrame",
1047
+ name: "World Geodetic System 1984",
1048
+ ellipsoid: {
1049
+ name: "WGS 84",
1050
+ semi_major_axis: 6378137,
1051
+ inverse_flattening: 298.257223563
1052
+ }
1053
+ },
1054
+ coordinate_system: {
1055
+ subtype: "ellipsoidal",
1056
+ axis: [{
1057
+ name: "Geodetic latitude",
1058
+ abbreviation: "Lat",
1059
+ direction: "north",
1060
+ unit: "degree"
1061
+ }, {
1062
+ name: "Geodetic longitude",
1063
+ abbreviation: "Lon",
1064
+ direction: "east",
1065
+ unit: "degree"
1066
+ }]
1067
+ }
1068
+ })]]);
1392
1069
  /**
1393
- * Detects whether the WKT string is WKT1 or WKT2.
1394
- * @param {string} wkt The WKT string.
1395
- * @returns {string} The detected version ("WKT1" or "WKT2").
1070
+ * Builds an {@link EpsgResolver} that resolves common CRS offline, delegates
1071
+ * the rest to {@link ResilientEpsgResolverOptions.fallback} (epsg.io by
1072
+ * default), and rethrows failures with a clear, actionable message.
1073
+ *
1074
+ * @param options - Optional fallback resolver override.
1075
+ * @returns A resolver suitable for the COGLayer `epsgResolver` prop.
1396
1076
  */
1397
- function detectWKTVersion(wkt) {
1398
- const normalizedWKT = wkt.toUpperCase();
1399
- if (normalizedWKT.includes("PROJCRS") || normalizedWKT.includes("GEOGCRS") || normalizedWKT.includes("BOUNDCRS") || normalizedWKT.includes("VERTCRS") || normalizedWKT.includes("LENGTHUNIT") || normalizedWKT.includes("ANGLEUNIT") || normalizedWKT.includes("SCALEUNIT")) return "WKT2";
1400
- if (normalizedWKT.includes("PROJCS") || normalizedWKT.includes("GEOGCS") || normalizedWKT.includes("LOCAL_CS") || normalizedWKT.includes("VERT_CS") || normalizedWKT.includes("UNIT")) return "WKT1";
1401
- return "WKT1";
1077
+ function createResilientEpsgResolver(options = {}) {
1078
+ const fallback = options.fallback ?? epsgResolver;
1079
+ return async (epsg) => {
1080
+ const offline = OFFLINE_DEFS.get(epsg);
1081
+ if (offline) return offline;
1082
+ try {
1083
+ return await fallback(epsg);
1084
+ } catch (cause) {
1085
+ const detail = cause instanceof Error ? cause.message : String(cause);
1086
+ const error = /* @__PURE__ */ new Error(`Could not resolve coordinate system EPSG:${epsg}. Coordinate systems are looked up from epsg.io; check your network connection or that the code is valid, then re-add the layer. (${detail})`);
1087
+ if (cause instanceof Error) error.cause = cause;
1088
+ throw error;
1089
+ }
1090
+ };
1402
1091
  }
1403
1092
  //#endregion
1404
- //#region node_modules/wkt-parser/parser.js
1405
- var parser_default = parseString;
1406
- var NEUTRAL = 1;
1407
- var KEYWORD = 2;
1408
- var NUMBER = 3;
1409
- var QUOTED = 4;
1410
- var AFTERQUOTE = 5;
1411
- var ENDED = -1;
1412
- var whitespace = /\s/;
1413
- var latin = /[A-Za-z]/;
1414
- var keyword = /[A-Za-z84_]/;
1415
- var endThings = /[,\]]/;
1416
- var digets = /[\d\.E\-\+]/;
1417
- function Parser(text) {
1418
- if (typeof text !== "string") throw new Error("not a string");
1419
- this.text = text.trim();
1420
- this.level = 0;
1421
- this.place = 0;
1422
- this.root = null;
1423
- this.stack = [];
1424
- this.currentObject = null;
1425
- this.state = NEUTRAL;
1093
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/layer-utils.js
1094
+ function renderDebugTileOutline(id, tile, forwardTo4326) {
1095
+ const { projectedCorners } = tile;
1096
+ const { topLeft, topRight, bottomRight, bottomLeft } = projectedCorners;
1097
+ const topLeftWgs84 = forwardTo4326(topLeft[0], topLeft[1]);
1098
+ const topRightWgs84 = forwardTo4326(topRight[0], topRight[1]);
1099
+ const bottomRightWgs84 = forwardTo4326(bottomRight[0], bottomRight[1]);
1100
+ const path = [
1101
+ topLeftWgs84,
1102
+ topRightWgs84,
1103
+ bottomRightWgs84,
1104
+ forwardTo4326(bottomLeft[0], bottomLeft[1]),
1105
+ topLeftWgs84
1106
+ ];
1107
+ const center = [(topLeftWgs84[0] + bottomRightWgs84[0]) / 2, (topLeftWgs84[1] + bottomRightWgs84[1]) / 2];
1108
+ const labelLayer = new TextLayer({
1109
+ id: `${id}-label`,
1110
+ data: [{
1111
+ position: center,
1112
+ text: `x=${tile.index.x} y=${tile.index.y} z=${tile.index.z}`
1113
+ }],
1114
+ getColor: [
1115
+ 255,
1116
+ 255,
1117
+ 255,
1118
+ 255
1119
+ ],
1120
+ getSize: 24,
1121
+ sizeUnits: "pixels",
1122
+ outlineWidth: 3,
1123
+ outlineColor: [
1124
+ 0,
1125
+ 0,
1126
+ 0,
1127
+ 255
1128
+ ],
1129
+ fontSettings: { sdf: true }
1130
+ });
1131
+ return [new PathLayer({
1132
+ id,
1133
+ data: [path],
1134
+ getPath: (d) => d,
1135
+ getColor: [
1136
+ 255,
1137
+ 0,
1138
+ 0,
1139
+ 255
1140
+ ],
1141
+ getWidth: 2,
1142
+ widthUnits: "pixels",
1143
+ pickable: false
1144
+ }), labelLayer];
1426
1145
  }
1427
- Parser.prototype.readCharicter = function() {
1428
- var char = this.text[this.place++];
1429
- if (this.state !== QUOTED) while (whitespace.test(char)) {
1430
- if (this.place >= this.text.length) return;
1431
- char = this.text[this.place++];
1432
- }
1433
- switch (this.state) {
1434
- case NEUTRAL: return this.neutral(char);
1435
- case KEYWORD: return this.keyword(char);
1436
- case QUOTED: return this.quoted(char);
1437
- case AFTERQUOTE: return this.afterquote(char);
1438
- case NUMBER: return this.number(char);
1439
- case ENDED: return;
1440
- }
1441
- };
1442
- Parser.prototype.afterquote = function(char) {
1443
- if (char === "\"") {
1444
- this.word += "\"";
1445
- this.state = QUOTED;
1446
- return;
1447
- }
1448
- if (endThings.test(char)) {
1449
- this.word = this.word.trim();
1450
- this.afterItem(char);
1451
- return;
1452
- }
1453
- throw new Error("havn't handled \"" + char + "\" in afterquote yet, index " + this.place);
1454
- };
1455
- Parser.prototype.afterItem = function(char) {
1456
- if (char === ",") {
1457
- if (this.word !== null) this.currentObject.push(this.word);
1458
- this.word = null;
1459
- this.state = NEUTRAL;
1460
- return;
1146
+ //#endregion
1147
+ //#region node_modules/@developmentseed/raster-reproject/dist/delatin.js
1148
+ /**
1149
+ * Define [**uv coordinates**](https://en.wikipedia.org/wiki/UV_mapping) as a float-valued image-local coordinate space where the top left is `(0, 0)` and the bottom right is `(1, 1)`.
1150
+ *
1151
+ * Define [**Barycentric coordinates**](https://en.wikipedia.org/wiki/Barycentric_coordinate_system) as float-valued triangle-local coordinates, represented as a 3-tuple of floats, where the tuple must add up to 1. The coordinate represents "how close to each vertex" a point in the interior of a triangle is. I.e. `(0, 0, 1)`, `(0, 1, 0)`, and `(1, 0, 0)` are all valid barycentric coordinates that define one of the three vertices. `(1/3, 1/3, 1/3)` represents the centroid of a triangle. `(1/2, 1/2, 0)` represents a point that is halfway between vertices `a` and `b` and has "none" of vertex `c`.
1152
+ *
1153
+ *
1154
+ * ## Changes
1155
+ *
1156
+ * - Delatin coordinates are in terms of pixel space whereas here we use uv space.
1157
+ *
1158
+ * Originally copied from https://github.com/mapbox/delatin under the ISC
1159
+ * license, then subject to further modifications.
1160
+ */
1161
+ /**
1162
+ * Barycentric sample points in uv space for where to sample reprojection
1163
+ * errors.
1164
+ */
1165
+ var SAMPLE_POINTS = [
1166
+ [
1167
+ 1 / 3,
1168
+ 1 / 3,
1169
+ 1 / 3
1170
+ ],
1171
+ [
1172
+ .5,
1173
+ .5,
1174
+ 0
1175
+ ],
1176
+ [
1177
+ .5,
1178
+ 0,
1179
+ .5
1180
+ ],
1181
+ [
1182
+ 0,
1183
+ .5,
1184
+ .5
1185
+ ]
1186
+ ];
1187
+ var DEFAULT_MAX_ERROR$1 = .125;
1188
+ /**
1189
+ * RasterReprojector performs a Delaunay triangulation-based reprojection of a
1190
+ * raster image.
1191
+ *
1192
+ * It takes as input a set of functions to associate pixel positions with
1193
+ * coordinates in the input and output CRS, as well as the dimensions of the
1194
+ * output image, and it produces a triangulated mesh that can be used to
1195
+ * reproject the input raster onto the output raster with bounded error.
1196
+ */
1197
+ var RasterReprojector = class {
1198
+ reprojectors;
1199
+ /** Width of the image in pixels */
1200
+ width;
1201
+ /** Height of the image in pixels */
1202
+ height;
1203
+ /**
1204
+ * UV vertex coordinates (x, y), i.e.
1205
+ * [x0, y0, x1, y1, ...]
1206
+ *
1207
+ * These coordinates are floats that range from [0, 1] in both X and Y.
1208
+ */
1209
+ uvs;
1210
+ /**
1211
+ * XY Positions in output CRS, computed via exact forward reprojection.
1212
+ */
1213
+ exactOutputPositions;
1214
+ /**
1215
+ * triangle vertex indices
1216
+ */
1217
+ triangles;
1218
+ _halfedges;
1219
+ /**
1220
+ * The UV texture coordinates of candidates found from
1221
+ * `findReprojectionCandidate`.
1222
+ *
1223
+ * Maybe in the future we'll want to store the barycentric coordinates instead
1224
+ * of just the uv coordinates?
1225
+ */
1226
+ _candidatesUV;
1227
+ _queueIndices;
1228
+ _queue;
1229
+ _errors;
1230
+ _pending;
1231
+ _pendingLen;
1232
+ constructor(reprojectors, width, height = width) {
1233
+ this.reprojectors = reprojectors;
1234
+ this.width = width;
1235
+ this.height = height;
1236
+ this.uvs = [];
1237
+ this.exactOutputPositions = [];
1238
+ this.triangles = [];
1239
+ this._halfedges = [];
1240
+ this._candidatesUV = [];
1241
+ this._queueIndices = [];
1242
+ this._queue = [];
1243
+ this._errors = [];
1244
+ this._pending = [];
1245
+ this._pendingLen = 0;
1246
+ const u1 = 1;
1247
+ const v1 = 1;
1248
+ const p0 = this._addPoint(0, 0);
1249
+ const p1 = this._addPoint(u1, 0);
1250
+ const p2 = this._addPoint(0, v1);
1251
+ const p3 = this._addPoint(u1, v1);
1252
+ const t0 = this._addTriangle(p3, p0, p2, -1, -1, -1);
1253
+ this._addTriangle(p0, p3, p1, t0, -1, -1);
1254
+ this._flush();
1461
1255
  }
1462
- if (char === "]") {
1463
- this.level--;
1464
- if (this.word !== null) {
1465
- this.currentObject.push(this.word);
1466
- this.word = null;
1256
+ /**
1257
+ * Refine the mesh until its maximum error gets below the given one
1258
+ *
1259
+ * @param maxError The maximum reprojection error in input pixels that the mesh should achieve.
1260
+ * @param maxIterations Optional safeguard to prevent infinite loops in case of non-convergence. If the mesh fails to converge within this number of iterations, a warning will be logged and the function will return early.
1261
+ *
1262
+ * @return {[type]} [return description]
1263
+ */
1264
+ run(maxError = DEFAULT_MAX_ERROR$1, { maxIterations = 1e4 } = {}) {
1265
+ if (maxError <= 0) throw new Error("maxError must be positive");
1266
+ let iterations = 0;
1267
+ while (this.getMaxError() > maxError) {
1268
+ this.refine();
1269
+ if (++iterations > maxIterations) {
1270
+ console.warn(`RasterReprojector: mesh refinement did not converge after ${iterations} iterations (maxError=${maxError}, currentError=${this.getMaxError()})`);
1271
+ break;
1272
+ }
1467
1273
  }
1468
- this.state = NEUTRAL;
1469
- this.currentObject = this.stack.pop();
1470
- if (!this.currentObject) this.state = ENDED;
1471
- return;
1472
1274
  }
1473
- };
1474
- Parser.prototype.number = function(char) {
1475
- if (digets.test(char)) {
1476
- this.word += char;
1477
- return;
1275
+ refine() {
1276
+ this._step();
1277
+ this._flush();
1478
1278
  }
1479
- if (endThings.test(char)) {
1480
- this.word = parseFloat(this.word);
1481
- this.afterItem(char);
1482
- return;
1279
+ getMaxError() {
1280
+ return this._errors[0];
1483
1281
  }
1484
- throw new Error("havn't handled \"" + char + "\" in number yet, index " + this.place);
1485
- };
1486
- Parser.prototype.quoted = function(char) {
1487
- if (char === "\"") {
1488
- this.state = AFTERQUOTE;
1489
- return;
1282
+ _flush() {
1283
+ for (let i = 0; i < this._pendingLen; i++) {
1284
+ const t = this._pending[i];
1285
+ this._findReprojectionCandidate(t);
1286
+ }
1287
+ this._pendingLen = 0;
1490
1288
  }
1491
- this.word += char;
1492
- };
1493
- Parser.prototype.keyword = function(char) {
1494
- if (keyword.test(char)) {
1495
- this.word += char;
1496
- return;
1289
+ /**
1290
+ * Conversion of upstream's `_findCandidate` for reprojection error handling.
1291
+ *
1292
+ * @param t The index (into `this.triangles`) of the pending triangle to process.
1293
+ *
1294
+ * @return Doesn't return; instead modifies internal state.
1295
+ */
1296
+ _findReprojectionCandidate(t) {
1297
+ const a = 2 * this.triangles[t * 3 + 0];
1298
+ const b = 2 * this.triangles[t * 3 + 1];
1299
+ const c = 2 * this.triangles[t * 3 + 2];
1300
+ const p0u = this.uvs[a];
1301
+ const p0v = this.uvs[a + 1];
1302
+ const p1u = this.uvs[b];
1303
+ const p1v = this.uvs[b + 1];
1304
+ const p2u = this.uvs[c];
1305
+ const p2v = this.uvs[c + 1];
1306
+ const out0x = this.exactOutputPositions[a];
1307
+ const out0y = this.exactOutputPositions[a + 1];
1308
+ const out1x = this.exactOutputPositions[b];
1309
+ const out1y = this.exactOutputPositions[b + 1];
1310
+ const out2x = this.exactOutputPositions[c];
1311
+ const out2y = this.exactOutputPositions[c + 1];
1312
+ let maxError = 0;
1313
+ let maxErrorU = 0;
1314
+ let maxErrorV = 0;
1315
+ for (const samplePoint of SAMPLE_POINTS) {
1316
+ const uvSampleU = barycentricMix(p0u, p1u, p2u, samplePoint[0], samplePoint[1], samplePoint[2]);
1317
+ const uvSampleV = barycentricMix(p0v, p1v, p2v, samplePoint[0], samplePoint[1], samplePoint[2]);
1318
+ const outSampleX = barycentricMix(out0x, out1x, out2x, samplePoint[0], samplePoint[1], samplePoint[2]);
1319
+ const outSampleY = barycentricMix(out0y, out1y, out2y, samplePoint[0], samplePoint[1], samplePoint[2]);
1320
+ const pixelExactX = uvSampleU * (this.width - 1);
1321
+ const pixelExactY = uvSampleV * (this.height - 1);
1322
+ const inputCRSSampled = this.reprojectors.inverseReproject(outSampleX, outSampleY);
1323
+ const pixelSampled = this.reprojectors.inverseTransform(inputCRSSampled[0], inputCRSSampled[1]);
1324
+ const dx = pixelExactX - pixelSampled[0];
1325
+ const dy = pixelExactY - pixelSampled[1];
1326
+ const err = Math.hypot(dx, dy);
1327
+ if (err > maxError) {
1328
+ maxError = err;
1329
+ maxErrorU = uvSampleU;
1330
+ maxErrorV = uvSampleV;
1331
+ }
1332
+ }
1333
+ if (maxErrorU === p0u && maxErrorV === p0v || maxErrorU === p1u && maxErrorV === p1v || maxErrorU === p2u && maxErrorV === p2v) maxError = 0;
1334
+ this._candidatesUV[2 * t] = maxErrorU;
1335
+ this._candidatesUV[2 * t + 1] = maxErrorV;
1336
+ this._queuePush(t, maxError);
1497
1337
  }
1498
- if (char === "[") {
1499
- var newObjects = [];
1500
- newObjects.push(this.word);
1501
- this.level++;
1502
- if (this.root === null) this.root = newObjects;
1503
- else this.currentObject.push(newObjects);
1504
- this.stack.push(this.currentObject);
1505
- this.currentObject = newObjects;
1506
- this.state = NEUTRAL;
1507
- return;
1338
+ _step() {
1339
+ const t = this._queuePop();
1340
+ const e0 = t * 3 + 0;
1341
+ const e1 = t * 3 + 1;
1342
+ const e2 = t * 3 + 2;
1343
+ const p0 = this.triangles[e0];
1344
+ const p1 = this.triangles[e1];
1345
+ const p2 = this.triangles[e2];
1346
+ const au = this.uvs[2 * p0];
1347
+ const av = this.uvs[2 * p0 + 1];
1348
+ const bu = this.uvs[2 * p1];
1349
+ const bv = this.uvs[2 * p1 + 1];
1350
+ const cu = this.uvs[2 * p2];
1351
+ const cv = this.uvs[2 * p2 + 1];
1352
+ const pu = this._candidatesUV[2 * t];
1353
+ const pv = this._candidatesUV[2 * t + 1];
1354
+ const pn = this._addPoint(pu, pv);
1355
+ if (orient(au, av, bu, bv, pu, pv) === 0) this._handleCollinear(pn, e0);
1356
+ else if (orient(bu, bv, cu, cv, pu, pv) === 0) this._handleCollinear(pn, e1);
1357
+ else if (orient(cu, cv, au, av, pu, pv) === 0) this._handleCollinear(pn, e2);
1358
+ else {
1359
+ const h0 = this._halfedges[e0];
1360
+ const h1 = this._halfedges[e1];
1361
+ const h2 = this._halfedges[e2];
1362
+ const t0 = this._addTriangle(p0, p1, pn, h0, -1, -1, e0);
1363
+ const t1 = this._addTriangle(p1, p2, pn, h1, -1, t0 + 1);
1364
+ const t2 = this._addTriangle(p2, p0, pn, h2, t0 + 2, t1 + 1);
1365
+ this._legalize(t0);
1366
+ this._legalize(t1);
1367
+ this._legalize(t2);
1368
+ }
1508
1369
  }
1509
- if (endThings.test(char)) {
1510
- this.afterItem(char);
1511
- return;
1370
+ _addPoint(u, v) {
1371
+ const i = this.uvs.length >> 1;
1372
+ this.uvs.push(u, v);
1373
+ const pixelX = u * (this.width - 1);
1374
+ const pixelY = v * (this.height - 1);
1375
+ const inputPosition = this.reprojectors.forwardTransform(pixelX, pixelY);
1376
+ const exactOutputPosition = this.reprojectors.forwardReproject(inputPosition[0], inputPosition[1]);
1377
+ this.exactOutputPositions.push(exactOutputPosition[0], exactOutputPosition[1]);
1378
+ return i;
1512
1379
  }
1513
- throw new Error("havn't handled \"" + char + "\" in keyword yet, index " + this.place);
1514
- };
1515
- Parser.prototype.neutral = function(char) {
1516
- if (latin.test(char)) {
1517
- this.word = char;
1518
- this.state = KEYWORD;
1519
- return;
1380
+ _addTriangle(a, b, c, ab, bc, ca, e = this.triangles.length) {
1381
+ const t = e / 3;
1382
+ this.triangles[e + 0] = a;
1383
+ this.triangles[e + 1] = b;
1384
+ this.triangles[e + 2] = c;
1385
+ this._halfedges[e + 0] = ab;
1386
+ this._halfedges[e + 1] = bc;
1387
+ this._halfedges[e + 2] = ca;
1388
+ if (ab >= 0) this._halfedges[ab] = e + 0;
1389
+ if (bc >= 0) this._halfedges[bc] = e + 1;
1390
+ if (ca >= 0) this._halfedges[ca] = e + 2;
1391
+ this._candidatesUV[2 * t + 0] = 0;
1392
+ this._candidatesUV[2 * t + 1] = 0;
1393
+ this._queueIndices[t] = -1;
1394
+ this._pending[this._pendingLen++] = t;
1395
+ return e;
1520
1396
  }
1521
- if (char === "\"") {
1522
- this.word = "";
1523
- this.state = QUOTED;
1524
- return;
1397
+ _legalize(a) {
1398
+ const b = this._halfedges[a];
1399
+ if (b < 0) return;
1400
+ const a0 = a - a % 3;
1401
+ const b0 = b - b % 3;
1402
+ const al = a0 + (a + 1) % 3;
1403
+ const ar = a0 + (a + 2) % 3;
1404
+ const bl = b0 + (b + 2) % 3;
1405
+ const br = b0 + (b + 1) % 3;
1406
+ const p0 = this.triangles[ar];
1407
+ const pr = this.triangles[a];
1408
+ const pl = this.triangles[al];
1409
+ const p1 = this.triangles[bl];
1410
+ const uvs = this.uvs;
1411
+ if (!inCircle(uvs[2 * p0], uvs[2 * p0 + 1], uvs[2 * pr], uvs[2 * pr + 1], uvs[2 * pl], uvs[2 * pl + 1], uvs[2 * p1], uvs[2 * p1 + 1])) return;
1412
+ const hal = this._halfedges[al];
1413
+ const har = this._halfedges[ar];
1414
+ const hbl = this._halfedges[bl];
1415
+ const hbr = this._halfedges[br];
1416
+ this._queueRemove(a0 / 3);
1417
+ this._queueRemove(b0 / 3);
1418
+ const t0 = this._addTriangle(p0, p1, pl, -1, hbl, hal, a0);
1419
+ const t1 = this._addTriangle(p1, p0, pr, t0, har, hbr, b0);
1420
+ this._legalize(t0 + 1);
1421
+ this._legalize(t1 + 2);
1525
1422
  }
1526
- if (digets.test(char)) {
1527
- this.word = char;
1528
- this.state = NUMBER;
1529
- return;
1423
+ _handleCollinear(pn, a) {
1424
+ const a0 = a - a % 3;
1425
+ const al = a0 + (a + 1) % 3;
1426
+ const ar = a0 + (a + 2) % 3;
1427
+ const p0 = this.triangles[ar];
1428
+ const pr = this.triangles[a];
1429
+ const pl = this.triangles[al];
1430
+ const hal = this._halfedges[al];
1431
+ const har = this._halfedges[ar];
1432
+ const b = this._halfedges[a];
1433
+ if (b < 0) {
1434
+ const t0 = this._addTriangle(pn, p0, pr, -1, har, -1, a0);
1435
+ const t1 = this._addTriangle(p0, pn, pl, t0, -1, hal);
1436
+ this._legalize(t0 + 1);
1437
+ this._legalize(t1 + 2);
1438
+ return;
1439
+ }
1440
+ const b0 = b - b % 3;
1441
+ const bl = b0 + (b + 2) % 3;
1442
+ const br = b0 + (b + 1) % 3;
1443
+ const p1 = this.triangles[bl];
1444
+ const hbl = this._halfedges[bl];
1445
+ const hbr = this._halfedges[br];
1446
+ this._queueRemove(b0 / 3);
1447
+ const t0 = this._addTriangle(p0, pr, pn, har, -1, -1, a0);
1448
+ const t1 = this._addTriangle(pr, p1, pn, hbr, -1, t0 + 1, b0);
1449
+ const t2 = this._addTriangle(p1, pl, pn, hbl, -1, t1 + 1);
1450
+ const t3 = this._addTriangle(pl, p0, pn, hal, t0 + 2, t2 + 1);
1451
+ this._legalize(t0);
1452
+ this._legalize(t1);
1453
+ this._legalize(t2);
1454
+ this._legalize(t3);
1530
1455
  }
1531
- if (endThings.test(char)) {
1532
- this.afterItem(char);
1533
- return;
1456
+ _queuePush(t, error) {
1457
+ const i = this._queue.length;
1458
+ this._queueIndices[t] = i;
1459
+ this._queue.push(t);
1460
+ this._errors.push(error);
1461
+ this._queueUp(i);
1534
1462
  }
1535
- throw new Error("havn't handled \"" + char + "\" in neutral yet, index " + this.place);
1536
- };
1537
- Parser.prototype.output = function() {
1538
- while (this.place < this.text.length) this.readCharicter();
1539
- if (this.state === ENDED) return this.root;
1540
- throw new Error("unable to parse string \"" + this.text + "\". State is " + this.state);
1541
- };
1542
- function parseString(txt) {
1543
- return new Parser(txt).output();
1544
- }
1545
- //#endregion
1546
- //#region node_modules/wkt-parser/process.js
1547
- function mapit(obj, key, value) {
1548
- if (Array.isArray(key)) {
1549
- value.unshift(key);
1550
- key = null;
1463
+ _queuePop() {
1464
+ const n = this._queue.length - 1;
1465
+ this._queueSwap(0, n);
1466
+ this._queueDown(0, n);
1467
+ return this._queuePopBack();
1551
1468
  }
1552
- var thing = key ? {} : obj;
1553
- var out = value.reduce(function(newObj, item) {
1554
- sExpr(item, newObj);
1555
- return newObj;
1556
- }, thing);
1557
- if (key) obj[key] = out;
1558
- }
1559
- function sExpr(v, obj) {
1560
- if (!Array.isArray(v)) {
1561
- obj[v] = true;
1562
- return;
1469
+ _queuePopBack() {
1470
+ const t = this._queue.pop();
1471
+ this._errors.pop();
1472
+ this._queueIndices[t] = -1;
1473
+ return t;
1563
1474
  }
1564
- var key = v.shift();
1565
- if (key === "PARAMETER") key = v.shift();
1566
- if (v.length === 1) {
1567
- if (Array.isArray(v[0])) {
1568
- obj[key] = {};
1569
- sExpr(v[0], obj[key]);
1475
+ _queueRemove(t) {
1476
+ const i = this._queueIndices[t];
1477
+ if (i < 0) {
1478
+ const it = this._pending.indexOf(t);
1479
+ if (it !== -1) this._pending[it] = this._pending[--this._pendingLen];
1480
+ else throw new Error("Broken triangulation (something went wrong).");
1570
1481
  return;
1571
1482
  }
1572
- obj[key] = v[0];
1573
- return;
1483
+ const n = this._queue.length - 1;
1484
+ if (n !== i) {
1485
+ this._queueSwap(i, n);
1486
+ if (!this._queueDown(i, n)) this._queueUp(i);
1487
+ }
1488
+ this._queuePopBack();
1574
1489
  }
1575
- if (!v.length) {
1576
- obj[key] = true;
1577
- return;
1490
+ _queueLess(i, j) {
1491
+ return this._errors[i] > this._errors[j];
1578
1492
  }
1579
- if (key === "TOWGS84") {
1580
- obj[key] = v;
1581
- return;
1493
+ _queueSwap(i, j) {
1494
+ const pi = this._queue[i];
1495
+ const pj = this._queue[j];
1496
+ this._queue[i] = pj;
1497
+ this._queue[j] = pi;
1498
+ this._queueIndices[pi] = j;
1499
+ this._queueIndices[pj] = i;
1500
+ const e = this._errors[i];
1501
+ this._errors[i] = this._errors[j];
1502
+ this._errors[j] = e;
1582
1503
  }
1583
- if (key === "AXIS") {
1584
- if (!(key in obj)) obj[key] = [];
1585
- obj[key].push(v);
1586
- return;
1504
+ _queueUp(j0) {
1505
+ let j = j0;
1506
+ while (true) {
1507
+ const i = j - 1 >> 1;
1508
+ if (i === j || !this._queueLess(j, i)) break;
1509
+ this._queueSwap(i, j);
1510
+ j = i;
1511
+ }
1587
1512
  }
1588
- if (!Array.isArray(key)) obj[key] = {};
1589
- var i;
1590
- switch (key) {
1591
- case "UNIT":
1592
- case "PRIMEM":
1593
- case "VERT_DATUM":
1594
- obj[key] = {
1595
- name: v[0].toLowerCase(),
1596
- convert: v[1]
1597
- };
1598
- if (v.length === 3) sExpr(v[2], obj[key]);
1599
- return;
1600
- case "SPHEROID":
1601
- case "ELLIPSOID":
1602
- obj[key] = {
1603
- name: v[0],
1604
- a: v[1],
1605
- rf: v[2]
1606
- };
1607
- if (v.length === 4) sExpr(v[3], obj[key]);
1608
- return;
1609
- case "EDATUM":
1610
- case "ENGINEERINGDATUM":
1611
- case "LOCAL_DATUM":
1612
- case "DATUM":
1613
- case "VERT_CS":
1614
- case "VERTCRS":
1615
- case "VERTICALCRS":
1616
- v[0] = ["name", v[0]];
1617
- mapit(obj, key, v);
1618
- return;
1619
- case "COMPD_CS":
1620
- case "COMPOUNDCRS":
1621
- case "FITTED_CS":
1622
- case "PROJECTEDCRS":
1623
- case "PROJCRS":
1624
- case "GEOGCS":
1625
- case "GEOCCS":
1626
- case "PROJCS":
1627
- case "LOCAL_CS":
1628
- case "GEODCRS":
1629
- case "GEODETICCRS":
1630
- case "GEODETICDATUM":
1631
- case "ENGCRS":
1632
- case "ENGINEERINGCRS":
1633
- v[0] = ["name", v[0]];
1634
- mapit(obj, key, v);
1635
- obj[key].type = key;
1636
- return;
1637
- default:
1638
- i = -1;
1639
- while (++i < v.length) if (!Array.isArray(v[i])) return sExpr(v, obj[key]);
1640
- return mapit(obj, key, v);
1513
+ _queueDown(i0, n) {
1514
+ let i = i0;
1515
+ while (true) {
1516
+ const j1 = 2 * i + 1;
1517
+ if (j1 >= n || j1 < 0) break;
1518
+ const j2 = j1 + 1;
1519
+ let j = j1;
1520
+ if (j2 < n && this._queueLess(j2, j1)) j = j2;
1521
+ if (!this._queueLess(j, i)) break;
1522
+ this._queueSwap(i, j);
1523
+ i = j;
1524
+ }
1525
+ return i > i0;
1641
1526
  }
1527
+ };
1528
+ function orient(ax, ay, bx, by, cx, cy) {
1529
+ return (bx - cx) * (ay - cy) - (by - cy) * (ax - cx);
1642
1530
  }
1643
- //#endregion
1644
- //#region node_modules/wkt-parser/util.js
1645
- var D2R$1 = .017453292519943295;
1646
- function d2r(input) {
1647
- return input * D2R$1;
1531
+ function inCircle(ax, ay, bx, by, cx, cy, px, py) {
1532
+ const dx = ax - px;
1533
+ const dy = ay - py;
1534
+ const ex = bx - px;
1535
+ const ey = by - py;
1536
+ const fx = cx - px;
1537
+ const fy = cy - py;
1538
+ const ap = dx * dx + dy * dy;
1539
+ const bp = ex * ex + ey * ey;
1540
+ const cp = fx * fx + fy * fy;
1541
+ return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) < 0;
1648
1542
  }
1649
- function applyProjectionDefaults(wkt) {
1650
- const normalizedProjName = (wkt.projName || "").toLowerCase().replace(/_/g, " ");
1651
- if (wkt.long0 === void 0 && wkt.longc !== void 0) wkt.long0 = wkt.longc;
1652
- if (!wkt.lat_ts && wkt.lat1 && (normalizedProjName === "stereographic south pole" || normalizedProjName === "polar stereographic (variant b)")) {
1653
- wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90);
1654
- wkt.lat_ts = wkt.lat1;
1655
- delete wkt.lat1;
1656
- } else if (!wkt.lat_ts && wkt.lat0 && (normalizedProjName === "polar stereographic" || normalizedProjName === "polar stereographic (variant a)")) {
1657
- wkt.lat_ts = wkt.lat0;
1658
- wkt.lat0 = d2r(wkt.lat0 > 0 ? 90 : -90);
1659
- delete wkt.lat1;
1543
+ /**
1544
+ * Interpolate the value at a given barycentric coordinate within a triangle.
1545
+ *
1546
+ * I've seen the name "mix" used before in graphics programming to refer to
1547
+ * barycentric linear interpolation.
1548
+ *
1549
+ * Note: the caller must call this method twice: once for u and once again for
1550
+ * v. We do this because we want to avoid allocating an array for the return
1551
+ * value.
1552
+ */
1553
+ function barycentricMix(a, b, c, t0, t1, t2) {
1554
+ return t0 * a + t1 * b + t2 * c;
1555
+ }
1556
+ //#endregion
1557
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/gpu-modules/create-texture.js
1558
+ /**
1559
+ * The base shader module for a render pipeline: samples a single input
1560
+ * texture into `color` so subsequent modules can transform it. Use this
1561
+ * when no decoding step (e.g. {@link CompositeBands}) is needed.
1562
+ */
1563
+ var CreateTexture = {
1564
+ name: "create-texture-unorm",
1565
+ inject: {
1566
+ "fs:#decl": `uniform sampler2D textureName;`,
1567
+ "fs:DECKGL_FILTER_COLOR": `
1568
+ color = texture(textureName, geometry.uv);
1569
+ `
1570
+ },
1571
+ getUniforms: (props) => {
1572
+ return { textureName: props.textureName };
1660
1573
  }
1574
+ };
1575
+ //#endregion
1576
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/mesh-layer/mesh-layer-fragment.glsl.js
1577
+ /**
1578
+ * This is a vendored copy of the SimpleMeshLayer's fragment shader:
1579
+ * https://github.com/visgl/deck.gl/blob/a15c8cea047993c8a861bf542835c1988f30165c/modules/mesh-layers/src/simple-mesh-layer/simple-mesh-layer-fragment.glsl.ts
1580
+ * under the MIT license.
1581
+ *
1582
+ * We edited this to remove the hard-coded texture uniform because we want to
1583
+ * support integer and signed integer textures, not only normalized unsigned
1584
+ * textures.
1585
+ */
1586
+ var mesh_layer_fragment_glsl_default = `#version 300 es
1587
+ #define SHADER_NAME simple-mesh-layer-fs
1588
+
1589
+ precision highp float;
1590
+
1591
+ in vec2 vTexCoord;
1592
+ in vec3 cameraPosition;
1593
+ in vec3 normals_commonspace;
1594
+ in vec4 position_commonspace;
1595
+ in vec4 vColor;
1596
+
1597
+ out vec4 fragColor;
1598
+
1599
+ void main(void) {
1600
+ geometry.uv = vTexCoord;
1601
+
1602
+ vec3 normal;
1603
+ if (simpleMesh.flatShading) {
1604
+
1605
+ normal = normalize(cross(dFdx(position_commonspace.xyz), dFdy(position_commonspace.xyz)));
1606
+ } else {
1607
+ normal = normals_commonspace;
1608
+ }
1609
+
1610
+ // We initialize color here before passing into DECKGL_FILTER_COLOR
1611
+ vec4 color;
1612
+ DECKGL_FILTER_COLOR(color, geometry);
1613
+
1614
+ vec3 lightColor = lighting_getLightColor(color.rgb, cameraPosition, position_commonspace.xyz, normal);
1615
+ fragColor = vec4(lightColor, color.a * layer.opacity);
1661
1616
  }
1617
+ `;
1662
1618
  //#endregion
1663
- //#region node_modules/wkt-parser/transformPROJJSON.js
1664
- function processUnit(unit) {
1665
- let result = {
1666
- units: null,
1667
- to_meter: void 0
1668
- };
1669
- if (typeof unit === "string") {
1670
- result.units = unit.toLowerCase();
1671
- if (result.units === "metre") result.units = "meter";
1672
- if (result.units === "meter") result.to_meter = 1;
1673
- } else if (unit && unit.name) {
1674
- result.units = unit.name.toLowerCase();
1675
- if (result.units === "metre") result.units = "meter";
1676
- result.to_meter = unit.conversion_factor;
1619
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/mesh-layer/mesh-layer.js
1620
+ var defaultProps$2 = {
1621
+ ...SimpleMeshLayer.defaultProps,
1622
+ renderPipeline: {
1623
+ type: "array",
1624
+ value: [],
1625
+ compare: true
1626
+ },
1627
+ material: {
1628
+ ambient: 1,
1629
+ diffuse: 0,
1630
+ shininess: 0,
1631
+ specularColor: [
1632
+ 0,
1633
+ 0,
1634
+ 0
1635
+ ]
1677
1636
  }
1678
- return result;
1679
- }
1680
- function toValue(valueOrObject) {
1681
- if (typeof valueOrObject === "object") return valueOrObject.value * valueOrObject.unit.conversion_factor;
1682
- return valueOrObject;
1683
- }
1684
- function calculateEllipsoid(value, result) {
1685
- if (value.ellipsoid.radius) {
1686
- result.a = value.ellipsoid.radius;
1687
- result.rf = 0;
1688
- } else {
1689
- result.a = toValue(value.ellipsoid.semi_major_axis);
1690
- if (value.ellipsoid.inverse_flattening !== void 0) result.rf = value.ellipsoid.inverse_flattening;
1691
- else if (value.ellipsoid.semi_major_axis !== void 0 && value.ellipsoid.semi_minor_axis !== void 0) result.rf = result.a / (result.a - toValue(value.ellipsoid.semi_minor_axis));
1637
+ };
1638
+ /**
1639
+ * A small subclass of the SimpleMeshLayer to allow dynamic shader injections.
1640
+ *
1641
+ * In the future this may expand to diverge more from the SimpleMeshLayer, such
1642
+ * as allowing the texture to be a 2D _array_.
1643
+ */
1644
+ var MeshTextureLayer = class extends SimpleMeshLayer {
1645
+ static layerName = "mesh-texture-layer";
1646
+ static defaultProps = defaultProps$2;
1647
+ _resolveRenderPipeline() {
1648
+ const { image, renderPipeline } = this.props;
1649
+ return [...image ? [{
1650
+ module: CreateTexture,
1651
+ props: { textureName: image }
1652
+ }] : [], ...renderPipeline ?? []];
1692
1653
  }
1693
- }
1694
- function transformPROJJSON(projjson, result = {}) {
1695
- if (!projjson || typeof projjson !== "object") return projjson;
1696
- if (projjson.type === "BoundCRS") {
1697
- transformPROJJSON(projjson.source_crs, result);
1698
- if (projjson.transformation) if (projjson.transformation.method && projjson.transformation.method.name === "NTv2") result.nadgrids = projjson.transformation.parameters[0].value;
1699
- else result.datum_params = projjson.transformation.parameters.map((param) => param.value);
1700
- return result;
1654
+ updateState(params) {
1655
+ if (this.hasRenderPipelineChanged(params)) params.changeFlags.extensionsChanged = true;
1656
+ super.updateState(params);
1701
1657
  }
1702
- Object.keys(projjson).forEach((key) => {
1703
- const value = projjson[key];
1704
- if (value === null) return;
1705
- switch (key) {
1706
- case "name":
1707
- if (result.srsCode) break;
1708
- result.name = value;
1709
- result.srsCode = value;
1710
- break;
1711
- case "type":
1712
- if (value === "GeographicCRS") result.projName = "longlat";
1713
- else if (value === "GeodeticCRS") if (projjson.coordinate_system && projjson.coordinate_system.subtype === "Cartesian") result.projName = "geocent";
1714
- else result.projName = "longlat";
1715
- else if (value === "ProjectedCRS" && projjson.conversion && projjson.conversion.method) result.projName = projjson.conversion.method.name;
1716
- break;
1717
- case "datum":
1718
- case "datum_ensemble":
1719
- if (value.ellipsoid) {
1720
- result.ellps = value.ellipsoid.name;
1721
- calculateEllipsoid(value, result);
1722
- }
1723
- if (value.prime_meridian) result.from_greenwich = value.prime_meridian.longitude * Math.PI / 180;
1724
- break;
1725
- case "ellipsoid":
1726
- result.ellps = value.name;
1727
- calculateEllipsoid(value, result);
1728
- break;
1729
- case "prime_meridian":
1730
- result.long0 = (value.longitude || 0) * Math.PI / 180;
1731
- break;
1732
- case "coordinate_system":
1733
- if (value.axis) {
1734
- const directionMap = {
1735
- "east": "e",
1736
- "north": "n",
1737
- "west": "w",
1738
- "south": "s",
1739
- "up": "u",
1740
- "down": "d",
1741
- "geocentricx": "e",
1742
- "geocentricy": "n",
1743
- "geocentricz": "u"
1744
- };
1745
- const mapped = value.axis.map((axis) => directionMap[axis.direction.toLowerCase()]);
1746
- if (mapped.every(Boolean)) {
1747
- result.axis = mapped.join("");
1748
- if (result.axis.length === 2) result.axis += "u";
1749
- }
1750
- if (value.unit) {
1751
- const { units, to_meter } = processUnit(value.unit);
1752
- result.units = units;
1753
- result.to_meter = to_meter;
1754
- } else if (value.axis[0] && value.axis[0].unit) {
1755
- const { units, to_meter } = processUnit(value.axis[0].unit);
1756
- result.units = units;
1757
- result.to_meter = to_meter;
1758
- }
1759
- }
1760
- break;
1761
- case "id":
1762
- if (value.authority && value.code) result.title = value.authority + ":" + value.code;
1763
- break;
1764
- case "conversion":
1765
- if (value.method && value.method.name) result.projName = value.method.name;
1766
- if (value.parameters) value.parameters.forEach((param) => {
1767
- const paramName = param.name.toLowerCase().replace(/\s+/g, "_");
1768
- const paramValue = param.value;
1769
- if (param.unit && param.unit.conversion_factor) result[paramName] = paramValue * param.unit.conversion_factor;
1770
- else if (param.unit === "degree") result[paramName] = paramValue * Math.PI / 180;
1771
- else result[paramName] = paramValue;
1772
- });
1773
- break;
1774
- case "unit":
1775
- if (value.name) {
1776
- result.units = value.name.toLowerCase();
1777
- if (result.units === "metre") result.units = "meter";
1778
- }
1779
- if (value.conversion_factor) result.to_meter = value.conversion_factor;
1780
- break;
1781
- case "base_crs":
1782
- transformPROJJSON(value, result);
1783
- result.datumCode = value.id ? value.id.authority + "_" + value.id.code : value.name;
1784
- break;
1785
- default: break;
1786
- }
1787
- });
1788
- if (result.latitude_of_false_origin !== void 0) result.lat0 = result.latitude_of_false_origin;
1789
- if (result.longitude_of_false_origin !== void 0) result.long0 = result.longitude_of_false_origin;
1790
- if (result.latitude_of_standard_parallel !== void 0) {
1791
- result.lat0 = result.latitude_of_standard_parallel;
1792
- result.lat1 = result.latitude_of_standard_parallel;
1658
+ /** Returns true if the render pipeline has changed between the old and new props. */
1659
+ hasRenderPipelineChanged(params) {
1660
+ const { oldProps, props: newProps } = params;
1661
+ if (Boolean(oldProps.image) !== Boolean(newProps.image)) return true;
1662
+ const oldPipeline = oldProps.renderPipeline ?? [];
1663
+ const newPipeline = newProps.renderPipeline ?? [];
1664
+ if (oldPipeline.length !== newPipeline.length) return true;
1665
+ for (let i = 0; i < oldPipeline.length; i++) if (oldPipeline[i]?.module.name !== newPipeline[i]?.module.name) return true;
1666
+ return false;
1793
1667
  }
1794
- if (result.latitude_of_1st_standard_parallel !== void 0) result.lat1 = result.latitude_of_1st_standard_parallel;
1795
- if (result.latitude_of_2nd_standard_parallel !== void 0) result.lat2 = result.latitude_of_2nd_standard_parallel;
1796
- if (result.latitude_of_projection_centre !== void 0) result.lat0 = result.latitude_of_projection_centre;
1797
- if (result.longitude_of_projection_centre !== void 0) result.longc = result.longitude_of_projection_centre;
1798
- if (result.easting_at_false_origin !== void 0) result.x0 = result.easting_at_false_origin;
1799
- if (result.northing_at_false_origin !== void 0) result.y0 = result.northing_at_false_origin;
1800
- if (result.latitude_of_natural_origin !== void 0) result.lat0 = result.latitude_of_natural_origin;
1801
- if (result.longitude_of_natural_origin !== void 0) result.long0 = result.longitude_of_natural_origin;
1802
- if (result.longitude_of_origin !== void 0) result.long0 = result.longitude_of_origin;
1803
- if (result.false_easting !== void 0) result.x0 = result.false_easting;
1804
- if (result.easting_at_projection_centre) result.x0 = result.easting_at_projection_centre;
1805
- if (result.false_northing !== void 0) result.y0 = result.false_northing;
1806
- if (result.northing_at_projection_centre) result.y0 = result.northing_at_projection_centre;
1807
- if (result.standard_parallel_1 !== void 0) result.lat1 = result.standard_parallel_1;
1808
- if (result.standard_parallel_2 !== void 0) result.lat2 = result.standard_parallel_2;
1809
- if (result.scale_factor_at_natural_origin !== void 0) result.k0 = result.scale_factor_at_natural_origin;
1810
- if (result.scale_factor_at_projection_centre !== void 0) result.k0 = result.scale_factor_at_projection_centre;
1811
- if (result.scale_factor_on_pseudo_standard_parallel !== void 0) result.k0 = result.scale_factor_on_pseudo_standard_parallel;
1812
- if (result.azimuth !== void 0) result.alpha = result.azimuth;
1813
- if (result.azimuth_at_projection_centre !== void 0) result.alpha = result.azimuth_at_projection_centre;
1814
- if (result.angle_from_rectified_to_skew_grid) result.rectified_grid_angle = result.angle_from_rectified_to_skew_grid;
1815
- applyProjectionDefaults(result);
1816
- return result;
1817
- }
1668
+ getShaders() {
1669
+ const upstreamShaders = super.getShaders();
1670
+ const modules = upstreamShaders.modules;
1671
+ for (const m of this._resolveRenderPipeline()) modules.push(m.module);
1672
+ return {
1673
+ ...upstreamShaders,
1674
+ fs: mesh_layer_fragment_glsl_default,
1675
+ modules
1676
+ };
1677
+ }
1678
+ draw(opts) {
1679
+ const shaderProps = {};
1680
+ for (const m of this._resolveRenderPipeline()) shaderProps[m.module.name] = m.props || {};
1681
+ for (const m of super.getModels()) m.shaderInputs.setProps(shaderProps);
1682
+ super.draw(opts);
1683
+ }
1684
+ };
1818
1685
  //#endregion
1819
- //#region node_modules/wkt-parser/index.js
1820
- var knownTypes = [
1821
- "PROJECTEDCRS",
1822
- "PROJCRS",
1823
- "GEOGCS",
1824
- "GEOCCS",
1825
- "PROJCS",
1826
- "LOCAL_CS",
1827
- "GEODCRS",
1828
- "GEODETICCRS",
1829
- "GEODETICDATUM",
1830
- "ENGCRS",
1831
- "ENGINEERINGCRS"
1686
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-layer.js
1687
+ var DEFAULT_MAX_ERROR = .125;
1688
+ var DEBUG_COLORS = [
1689
+ [
1690
+ 252,
1691
+ 73,
1692
+ 163
1693
+ ],
1694
+ [
1695
+ 255,
1696
+ 51,
1697
+ 204
1698
+ ],
1699
+ [
1700
+ 204,
1701
+ 102,
1702
+ 255
1703
+ ],
1704
+ [
1705
+ 153,
1706
+ 51,
1707
+ 255
1708
+ ],
1709
+ [
1710
+ 102,
1711
+ 204,
1712
+ 255
1713
+ ],
1714
+ [
1715
+ 51,
1716
+ 153,
1717
+ 255
1718
+ ],
1719
+ [
1720
+ 102,
1721
+ 255,
1722
+ 204
1723
+ ],
1724
+ [
1725
+ 51,
1726
+ 255,
1727
+ 170
1728
+ ],
1729
+ [
1730
+ 0,
1731
+ 255,
1732
+ 0
1733
+ ],
1734
+ [
1735
+ 51,
1736
+ 204,
1737
+ 51
1738
+ ],
1739
+ [
1740
+ 255,
1741
+ 204,
1742
+ 102
1743
+ ],
1744
+ [
1745
+ 255,
1746
+ 179,
1747
+ 71
1748
+ ],
1749
+ [
1750
+ 255,
1751
+ 102,
1752
+ 102
1753
+ ],
1754
+ [
1755
+ 255,
1756
+ 80,
1757
+ 80
1758
+ ],
1759
+ [
1760
+ 255,
1761
+ 0,
1762
+ 0
1763
+ ],
1764
+ [
1765
+ 204,
1766
+ 0,
1767
+ 0
1768
+ ],
1769
+ [
1770
+ 255,
1771
+ 128,
1772
+ 0
1773
+ ],
1774
+ [
1775
+ 255,
1776
+ 153,
1777
+ 51
1778
+ ],
1779
+ [
1780
+ 255,
1781
+ 255,
1782
+ 102
1783
+ ],
1784
+ [
1785
+ 255,
1786
+ 255,
1787
+ 51
1788
+ ],
1789
+ [
1790
+ 0,
1791
+ 255,
1792
+ 255
1793
+ ],
1794
+ [
1795
+ 0,
1796
+ 204,
1797
+ 255
1798
+ ]
1832
1799
  ];
1833
- function rename(obj, params) {
1834
- var outName = params[0];
1835
- var inName = params[1];
1836
- if (!(outName in obj) && inName in obj) {
1837
- obj[outName] = obj[inName];
1838
- if (params.length === 3) obj[outName] = params[2](obj[outName]);
1839
- }
1840
- }
1841
- function cleanWKT(wkt) {
1842
- var keys = Object.keys(wkt);
1843
- for (var i = 0, ii = keys.length; i < ii; ++i) {
1844
- var key = keys[i];
1845
- if (knownTypes.indexOf(key) !== -1) setPropertiesFromWkt(wkt[key]);
1846
- if (typeof wkt[key] === "object") cleanWKT(wkt[key]);
1800
+ var defaultProps$1 = {
1801
+ image: {
1802
+ type: "image",
1803
+ value: null,
1804
+ async: true
1805
+ },
1806
+ renderPipeline: {
1807
+ type: "array",
1808
+ value: [],
1809
+ compare: true
1810
+ },
1811
+ debug: false,
1812
+ debugOpacity: .5
1813
+ };
1814
+ /**
1815
+ * Generic deck.gl layer for rendering geospatial raster data with client-side,
1816
+ * GPU-based reprojection and custom processing pipelines.
1817
+ *
1818
+ * This is a composite layer that uses {@link RasterReprojector} to generate an adaptive mesh
1819
+ * that accurately represents the reprojected raster, then renders it using
1820
+ * {@link MeshTextureLayer} (a small wrapper around a deck.gl
1821
+ * {@link SimpleMeshLayer}).
1822
+ */
1823
+ var RasterLayer = class extends CompositeLayer {
1824
+ static layerName = "RasterLayer";
1825
+ static defaultProps = defaultProps$1;
1826
+ initializeState() {
1827
+ this.setState({});
1847
1828
  }
1848
- }
1849
- function setPropertiesFromWkt(wkt) {
1850
- if (wkt.AUTHORITY) {
1851
- var authority = Object.keys(wkt.AUTHORITY)[0];
1852
- if (authority && authority in wkt.AUTHORITY) wkt.title = authority + ":" + wkt.AUTHORITY[authority];
1829
+ updateState(params) {
1830
+ super.updateState(params);
1831
+ const { props, oldProps, changeFlags } = params;
1832
+ const reprojectionFnsChanged = props.reprojectionFns.forwardTransform !== oldProps.reprojectionFns?.forwardTransform || props.reprojectionFns.inverseTransform !== oldProps.reprojectionFns?.inverseTransform || props.reprojectionFns.forwardReproject !== oldProps.reprojectionFns?.forwardReproject || props.reprojectionFns.inverseReproject !== oldProps.reprojectionFns?.inverseReproject;
1833
+ if (Boolean(changeFlags.dataChanged) || props.width !== oldProps.width || props.height !== oldProps.height || reprojectionFnsChanged || props.maxError !== oldProps.maxError) this._generateMesh();
1853
1834
  }
1854
- if (wkt.type === "GEOGCS") wkt.projName = "longlat";
1855
- else if (wkt.type === "LOCAL_CS") {
1856
- wkt.projName = "identity";
1857
- wkt.local = true;
1858
- } else if (typeof wkt.PROJECTION === "object") wkt.projName = Object.keys(wkt.PROJECTION)[0];
1859
- else wkt.projName = wkt.PROJECTION;
1860
- if (wkt.AXIS) {
1861
- var axisOrder = "";
1862
- for (var i = 0, ii = wkt.AXIS.length; i < ii; ++i) {
1863
- var axis = [wkt.AXIS[i][0].toLowerCase(), wkt.AXIS[i][1].toLowerCase()];
1864
- if (axis[0].indexOf("north") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "north") axisOrder += "n";
1865
- else if (axis[0].indexOf("south") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "south") axisOrder += "s";
1866
- else if (axis[0].indexOf("east") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "east") axisOrder += "e";
1867
- else if (axis[0].indexOf("west") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "west") axisOrder += "w";
1868
- }
1869
- if (axisOrder.length === 2) axisOrder += "u";
1870
- if (axisOrder.length === 3) wkt.axis = axisOrder;
1835
+ _generateMesh() {
1836
+ const { width, height, reprojectionFns, maxError = DEFAULT_MAX_ERROR } = this.props;
1837
+ const reprojector = new RasterReprojector(reprojectionFns, width + 1, height + 1);
1838
+ reprojector.run(maxError);
1839
+ const { indices, positions, texCoords } = reprojectorToMesh(reprojector);
1840
+ this.setState({
1841
+ reprojector,
1842
+ mesh: {
1843
+ indices: {
1844
+ value: indices,
1845
+ size: 1
1846
+ },
1847
+ attributes: {
1848
+ POSITION: {
1849
+ value: positions,
1850
+ size: 3
1851
+ },
1852
+ TEXCOORD_0: {
1853
+ value: texCoords,
1854
+ size: 2
1855
+ }
1856
+ }
1857
+ }
1858
+ });
1871
1859
  }
1872
- if (wkt.UNIT) {
1873
- wkt.units = wkt.UNIT.name.toLowerCase();
1874
- if (wkt.units === "metre") wkt.units = "meter";
1875
- if (wkt.UNIT.convert) if (wkt.type === "GEOGCS") {
1876
- if (wkt.DATUM && wkt.DATUM.SPHEROID) wkt.to_meter = wkt.UNIT.convert * wkt.DATUM.SPHEROID.a;
1877
- } else wkt.to_meter = wkt.UNIT.convert;
1860
+ renderDebugLayer() {
1861
+ const { reprojector } = this.state;
1862
+ const { debugOpacity } = this.props;
1863
+ if (!reprojector) return null;
1864
+ return new PolygonLayer(this.getSubLayerProps({
1865
+ id: "polygon",
1866
+ data: {
1867
+ reprojector,
1868
+ length: reprojector.triangles.length / 3
1869
+ },
1870
+ getPolygon: (_, { index, data }) => {
1871
+ const triangles = data.reprojector.triangles;
1872
+ const positions = reprojector.exactOutputPositions;
1873
+ const a = triangles[index * 3];
1874
+ const b = triangles[index * 3 + 1];
1875
+ const c = triangles[index * 3 + 2];
1876
+ return [
1877
+ [positions[a * 2], positions[a * 2 + 1]],
1878
+ [positions[b * 2], positions[b * 2 + 1]],
1879
+ [positions[c * 2], positions[c * 2 + 1]],
1880
+ [positions[a * 2], positions[a * 2 + 1]]
1881
+ ];
1882
+ },
1883
+ getFillColor: (_, { index, target }) => {
1884
+ const color = DEBUG_COLORS[index % DEBUG_COLORS.length];
1885
+ target[0] = color[0];
1886
+ target[1] = color[1];
1887
+ target[2] = color[2];
1888
+ target[3] = 255;
1889
+ return target;
1890
+ },
1891
+ getLineColor: [
1892
+ 0,
1893
+ 0,
1894
+ 0
1895
+ ],
1896
+ getLineWidth: 1,
1897
+ lineWidthUnits: "pixels",
1898
+ opacity: debugOpacity !== void 0 && Number.isFinite(debugOpacity) ? Math.max(0, Math.min(1, debugOpacity)) : 1,
1899
+ pickable: false
1900
+ }));
1878
1901
  }
1879
- var geogcs = wkt.GEOGCS;
1880
- if (wkt.type === "GEOGCS") geogcs = wkt;
1881
- if (geogcs) {
1882
- if (geogcs.PRIMEM && geogcs.PRIMEM.convert) wkt.from_greenwich = d2r(geogcs.PRIMEM.convert);
1883
- if (geogcs.DATUM) wkt.datumCode = geogcs.DATUM.name.toLowerCase();
1884
- else wkt.datumCode = geogcs.name.toLowerCase();
1885
- if (wkt.datumCode.slice(0, 2) === "d_") wkt.datumCode = wkt.datumCode.slice(2);
1886
- if (wkt.datumCode === "new_zealand_1949") wkt.datumCode = "nzgd49";
1887
- if (wkt.datumCode === "wgs_1984" || wkt.datumCode === "world_geodetic_system_1984") {
1888
- if (wkt.PROJECTION === "Mercator_Auxiliary_Sphere") wkt.sphere = true;
1889
- wkt.datumCode = "wgs84";
1890
- }
1891
- if (wkt.datumCode === "belge_1972") wkt.datumCode = "rnb72";
1892
- if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
1893
- wkt.ellps = geogcs.DATUM.SPHEROID.name.replace("_19", "").replace(/[Cc]larke\_18/, "clrk");
1894
- if (wkt.ellps.toLowerCase().slice(0, 13) === "international") wkt.ellps = "intl";
1895
- wkt.a = geogcs.DATUM.SPHEROID.a;
1896
- wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf);
1902
+ renderLayers() {
1903
+ const { mesh } = this.state;
1904
+ const { debug, image, renderPipeline } = this.props;
1905
+ if (!mesh || !image && (renderPipeline?.length ?? 0) === 0) return null;
1906
+ const layers = [new MeshTextureLayer(this.getSubLayerProps({
1907
+ id: "raster",
1908
+ image,
1909
+ renderPipeline,
1910
+ data: [1],
1911
+ mesh,
1912
+ _instanced: false,
1913
+ getPosition: [
1914
+ 0,
1915
+ 0,
1916
+ 0
1917
+ ],
1918
+ getColor: [
1919
+ 255,
1920
+ 255,
1921
+ 255
1922
+ ]
1923
+ }))];
1924
+ if (debug) {
1925
+ const debugLayer = this.renderDebugLayer();
1926
+ if (debugLayer) layers.push(debugLayer);
1897
1927
  }
1898
- if (geogcs.DATUM && geogcs.DATUM.TOWGS84) wkt.datum_params = geogcs.DATUM.TOWGS84;
1899
- if (~wkt.datumCode.indexOf("osgb_1936")) wkt.datumCode = "osgb36";
1900
- if (~wkt.datumCode.indexOf("osni_1952")) wkt.datumCode = "osni52";
1901
- if (~wkt.datumCode.indexOf("tm65") || ~wkt.datumCode.indexOf("geodetic_datum_of_1965")) wkt.datumCode = "ire65";
1902
- if (wkt.datumCode === "ch1903+") wkt.datumCode = "ch1903";
1903
- if (~wkt.datumCode.indexOf("israel")) wkt.datumCode = "isr93";
1928
+ return layers;
1904
1929
  }
1905
- if (wkt.b && !isFinite(wkt.b)) wkt.b = wkt.a;
1906
- if (wkt.rectified_grid_angle) wkt.rectified_grid_angle = d2r(wkt.rectified_grid_angle);
1907
- function toMeter(input) {
1908
- return input * (wkt.to_meter || 1);
1930
+ };
1931
+ function reprojectorToMesh(reprojector) {
1932
+ const numVertices = reprojector.uvs.length / 2;
1933
+ const positions = new Float32Array(numVertices * 3);
1934
+ const texCoords = new Float32Array(reprojector.uvs);
1935
+ for (let i = 0; i < numVertices; i++) {
1936
+ positions[i * 3] = reprojector.exactOutputPositions[i * 2];
1937
+ positions[i * 3 + 1] = reprojector.exactOutputPositions[i * 2 + 1];
1938
+ positions[i * 3 + 2] = 0;
1909
1939
  }
1910
- var renamer = function(a) {
1911
- return rename(wkt, a);
1940
+ return {
1941
+ indices: new Uint32Array(reprojector.triangles),
1942
+ positions,
1943
+ texCoords
1912
1944
  };
1913
- [
1914
- ["standard_parallel_1", "Standard_Parallel_1"],
1915
- ["standard_parallel_1", "Latitude of 1st standard parallel"],
1916
- ["standard_parallel_2", "Standard_Parallel_2"],
1917
- ["standard_parallel_2", "Latitude of 2nd standard parallel"],
1918
- ["false_easting", "False_Easting"],
1919
- ["false_easting", "False easting"],
1920
- ["false-easting", "Easting at false origin"],
1921
- ["false_northing", "False_Northing"],
1922
- ["false_northing", "False northing"],
1923
- ["false_northing", "Northing at false origin"],
1924
- ["central_meridian", "Central_Meridian"],
1925
- ["central_meridian", "Longitude of natural origin"],
1926
- ["central_meridian", "Longitude of false origin"],
1927
- ["latitude_of_origin", "Latitude_Of_Origin"],
1928
- ["latitude_of_origin", "Central_Parallel"],
1929
- ["latitude_of_origin", "Latitude of natural origin"],
1930
- ["latitude_of_origin", "Latitude of false origin"],
1931
- ["scale_factor", "Scale_Factor"],
1932
- ["k0", "scale_factor"],
1933
- ["latitude_of_center", "Latitude_Of_Center"],
1934
- ["latitude_of_center", "Latitude_of_center"],
1935
- [
1936
- "lat0",
1937
- "latitude_of_center",
1938
- d2r
1939
- ],
1940
- ["longitude_of_center", "Longitude_Of_Center"],
1941
- ["longitude_of_center", "Longitude_of_center"],
1942
- [
1943
- "longc",
1944
- "longitude_of_center",
1945
- d2r
1946
- ],
1947
- [
1948
- "x0",
1949
- "false_easting",
1950
- toMeter
1951
- ],
1952
- [
1953
- "y0",
1954
- "false_northing",
1955
- toMeter
1956
- ],
1957
- [
1958
- "long0",
1959
- "central_meridian",
1960
- d2r
1961
- ],
1962
- [
1963
- "lat0",
1964
- "latitude_of_origin",
1965
- d2r
1966
- ],
1967
- [
1968
- "lat0",
1969
- "standard_parallel_1",
1970
- d2r
1971
- ],
1972
- [
1973
- "lat1",
1974
- "standard_parallel_1",
1975
- d2r
1976
- ],
1977
- [
1978
- "lat2",
1979
- "standard_parallel_2",
1980
- d2r
1981
- ],
1982
- ["azimuth", "Azimuth"],
1983
- [
1984
- "alpha",
1985
- "azimuth",
1986
- d2r
1987
- ],
1988
- ["srsCode", "name"]
1989
- ].forEach(renamer);
1990
- applyProjectionDefaults(wkt);
1991
- }
1992
- function wkt_parser_default(wkt) {
1993
- if (typeof wkt === "object") return transformPROJJSON(wkt);
1994
- const version = detectWKTVersion(wkt);
1995
- var lisp = parser_default(wkt);
1996
- if (version === "WKT2") return transformPROJJSON(buildPROJJSON(lisp));
1997
- var type = lisp[0];
1998
- var obj = {};
1999
- sExpr(lisp, obj);
2000
- cleanWKT(obj);
2001
- return obj[type];
2002
1945
  }
2003
1946
  //#endregion
2004
- //#region node_modules/@developmentseed/proj/dist/parse-wkt.js
1947
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/affine-tileset.js
2005
1948
  /**
2006
- * Parse a WKT string or PROJJSON object into a proj4-compatible projection
2007
- * definition.
1949
+ * A {@link RasterTilesetDescriptor} backed by per-level affine transforms.
2008
1950
  *
2009
- * This is a typed wrapper around the `wkt-parser` package.
1951
+ * Derives `projectedBounds` from the coarsest level's array. Everything else
1952
+ * is passed through from the constructor options.
2010
1953
  */
2011
- function parseWkt(input) {
2012
- const def = wkt_parser_default(input);
2013
- if (def.projName === "longlat" && (!def.units || def.units === "unknown")) {
2014
- def.units = "degree";
2015
- def.to_meter = void 0;
1954
+ var AffineTileset = class {
1955
+ levels;
1956
+ projectTo3857;
1957
+ projectFrom3857;
1958
+ projectTo4326;
1959
+ projectFrom4326;
1960
+ projectedBounds;
1961
+ constructor(options) {
1962
+ if (options.levels.length === 0) throw new Error("AffineTileset requires at least one level");
1963
+ this.levels = options.levels;
1964
+ this.projectTo3857 = options.projectTo3857;
1965
+ this.projectFrom3857 = options.projectFrom3857;
1966
+ this.projectTo4326 = options.projectTo4326;
1967
+ this.projectFrom4326 = options.projectFrom4326;
1968
+ this.projectedBounds = options.levels[0].projectedBounds;
2016
1969
  }
2017
- return def;
2018
- }
1970
+ };
2019
1971
  //#endregion
2020
- //#region node_modules/@developmentseed/proj/dist/registry.js
1972
+ //#region node_modules/@developmentseed/affine/dist/affine.js
2021
1973
  /**
2022
- * A global registry holding parsed projection definitions.
1974
+ * Create a translation transform from an offset vector.
1975
+ *
1976
+ * @param xoff Translation offset in x direction.
1977
+ * @param yoff Translation offset in y direction.
1978
+ *
1979
+ * @return Transform that applies the given translation.
2023
1980
  */
2024
- var PROJECTION_REGISTRY = /* @__PURE__ */ new Map();
2025
- async function epsgResolver(epsg) {
2026
- const key = `EPSG:${epsg}`;
2027
- const cachedProj = PROJECTION_REGISTRY.get(key);
2028
- if (cachedProj !== void 0) return cachedProj;
2029
- const proj = parseWkt(await getProjjson(epsg));
2030
- PROJECTION_REGISTRY.set(key, proj);
2031
- return proj;
2032
- }
2033
- /** Query epsg.io for the PROJJSON corresponding to the given EPSG code. */
2034
- async function getProjjson(epsg) {
2035
- const url = `https://epsg.io/${epsg}.json`;
2036
- const resp = await fetch(url);
2037
- if (!resp.ok) throw new Error(`Failed to fetch PROJJSON from ${url}`);
2038
- return await resp.json();
1981
+ function translation(xoff, yoff) {
1982
+ return [
1983
+ 1,
1984
+ 0,
1985
+ xoff,
1986
+ 0,
1987
+ 1,
1988
+ yoff
1989
+ ];
2039
1990
  }
2040
- //#endregion
2041
- //#region node_modules/@developmentseed/proj/dist/transform-bounds.js
2042
1991
  /**
2043
- * Transform boundary densifying the edges to account for nonlinear
2044
- * transformations along these edges and extracting the outermost bounds.
1992
+ * Create a scaling transform from a scalar or vector.
1993
+ *
1994
+ * You can pass either one or two scaling factors. Passing only a single scalar
1995
+ * value will scale in both dimensions equally. A vector scaling value scales
1996
+ * the dimensions independently.
1997
+ *
1998
+ * @param sx Scaling factor in x direction.
1999
+ * @param sy Scaling factor in y direction (defaults to sx if not provided).
2045
2000
  *
2046
- * @param project - function that maps (x, y) in source CRS to (x, y) in target CRS
2047
- * @param left - min X in source CRS
2048
- * @param bottom - min Y in source CRS
2049
- * @param right - max X in source CRS
2050
- * @param top - max Y in source CRS
2051
- * @param options.densifyPts - number of intermediate points along each edge (default 21)
2052
- * @returns [minX, minY, maxX, maxY] in the target CRS
2001
+ * @return Transform that applies the given scaling.
2053
2002
  */
2054
- function transformBounds(project, left, bottom, right, top, options = {}) {
2055
- const { densifyPts = 21 } = options;
2056
- const cx = [
2057
- left,
2058
- right,
2059
- right,
2060
- left
2061
- ];
2062
- const cy = [
2063
- bottom,
2064
- bottom,
2065
- top,
2066
- top
2067
- ];
2068
- let outMinX = Infinity;
2069
- let outMinY = Infinity;
2070
- let outMaxX = -Infinity;
2071
- let outMaxY = -Infinity;
2072
- for (let i = 0; i < 4; i++) {
2073
- const fromX = cx[i];
2074
- const fromY = cy[i];
2075
- const toX = cx[(i + 1) % 4];
2076
- const toY = cy[(i + 1) % 4];
2077
- for (let j = 0; j <= densifyPts; j++) {
2078
- const t = j / (densifyPts + 1);
2079
- const [px, py] = project(fromX + (toX - fromX) * t, fromY + (toY - fromY) * t);
2080
- if (px < outMinX) outMinX = px;
2081
- if (py < outMinY) outMinY = py;
2082
- if (px > outMaxX) outMaxX = px;
2083
- if (py > outMaxY) outMaxY = py;
2084
- }
2085
- }
2003
+ function scale$3(sx, sy = sx) {
2086
2004
  return [
2087
- outMinX,
2088
- outMinY,
2089
- outMaxX,
2090
- outMaxY
2005
+ sx,
2006
+ 0,
2007
+ 0,
2008
+ 0,
2009
+ sy,
2010
+ 0
2091
2011
  ];
2092
2012
  }
2093
- //#endregion
2094
- //#region node_modules/@developmentseed/proj/dist/web-mercator.js
2095
- var WGS84_ELLIPSOID_A$1 = 6378137;
2096
- var MAX_WEB_MERCATOR_LAT$1 = 85.05112877980659;
2097
2013
  /**
2098
- * Convert a WGS84 longitude/latitude to EPSG:3857 meters analytically.
2099
- * Valid for latitudes in [-MAX_WEB_MERCATOR_LAT, MAX_WEB_MERCATOR_LAT].
2014
+ * Apply a geotransform to a coordinate.
2015
+ *
2016
+ * That is, we apply this series of equations:
2017
+ *
2018
+ * ```
2019
+ * x_out = a * x + b * y + c
2020
+ * y_out = d * x + e * y + f
2021
+ * ```
2022
+ *
2023
+ * @param affine The affine transform to apply.
2024
+ * @param x The x coordinate.
2025
+ * @param y The y coordinate.
2026
+ *
2027
+ * @return The transformed coordinates.
2100
2028
  */
2101
- function wgs84To3857(lon, lat) {
2102
- const x = lon * Math.PI * WGS84_ELLIPSOID_A$1 / 180;
2103
- const latRad = lat * Math.PI / 180;
2104
- return [x, Math.log(Math.tan(Math.PI / 4 + latRad / 2)) * WGS84_ELLIPSOID_A$1];
2029
+ function apply([a, b, c, d, e, f], x, y) {
2030
+ return [a * x + b * y + c, d * x + e * y + f];
2105
2031
  }
2106
2032
  /**
2107
- * Wrap a proj4 forward projection to EPSG:3857 so that it never returns NaN.
2033
+ * Compose two affine transforms: A×B (apply B **first**, then A).
2108
2034
  *
2109
- * proj4 returns [NaN, NaN] for points at the poles (lat = ±90°) because the
2110
- * Mercator projection is undefined there. The wrapper falls back to:
2111
- * 1. Project the input to WGS84 via `forwardTo4326`
2112
- * 2. Clamp the latitude to the Web Mercator limit (±85.05°)
2113
- * 3. Convert analytically from WGS84 to EPSG:3857
2035
+ * This is equivalent to `a @ b` in Python's `affine` library, and is equivalent
2036
+ * to multiplying the 3×3 matrices:
2037
+ * ```
2038
+ * | a1 b1 c1 | | a2 b2 c2 |
2039
+ * | d1 e1 f1 | × | d2 e2 f2 |
2040
+ * | 0 0 1 | | 0 0 1 |
2041
+ * ```
2114
2042
  *
2115
- * This correctly handles any input CRS, not just EPSG:4326.
2043
+ * @param A The first affine transform to apply.
2044
+ * @param B The second affine transform to apply.
2116
2045
  *
2117
- * NOTE: An identical copy of this function lives in `raster-tile-traversal.ts`.
2118
- * The two packages cannot share code due to their dependency relationship
2119
- * (deck.gl-geotiff depends on deck.gl-raster, not vice versa). If this logic
2120
- * changes, update both copies.
2046
+ * @return The composed affine transform.
2047
+ */
2048
+ function compose([a1, b1, c1, d1, e1, f1], [a2, b2, c2, d2, e2, f2]) {
2049
+ return [
2050
+ a1 * a2 + b1 * d2,
2051
+ a1 * b2 + b1 * e2,
2052
+ a1 * c2 + b1 * f2 + c1,
2053
+ d1 * a2 + e1 * d2,
2054
+ d1 * b2 + e1 * e2,
2055
+ d1 * c2 + e1 * f2 + f1
2056
+ ];
2057
+ }
2058
+ /**
2059
+ * Compute the inverse of an Affine.
2121
2060
  *
2122
- * Perhaps in the future we'll make a `@developmentseed/projections` package to
2123
- * hold shared projection utilities like this. *
2061
+ * @param affine The affine transform to invert.
2062
+ * @return The inverted affine transform.
2063
+ * @throws If the transform is degenerate and cannot be inverted.
2124
2064
  */
2125
- function makeClampedForwardTo3857$1(forwardTo3857, forwardTo4326) {
2126
- return (x, y) => {
2127
- const [px, py] = forwardTo3857(x, y);
2128
- if (Number.isFinite(px) && Number.isFinite(py)) return [px, py];
2129
- const [lon, lat] = forwardTo4326(x, y);
2130
- return wgs84To3857(lon, Math.max(-85.05112877980659, Math.min(MAX_WEB_MERCATOR_LAT$1, lat)));
2131
- };
2065
+ function invert$2([sa, sb, sc, sd, se, sf]) {
2066
+ const det = sa * se - sb * sd;
2067
+ if (det === 0) throw new Error("Cannot invert degenerate transform");
2068
+ const idet = 1 / det;
2069
+ const ra = se * idet;
2070
+ const rb = -sb * idet;
2071
+ const rd = -sd * idet;
2072
+ const re = sa * idet;
2073
+ return [
2074
+ ra,
2075
+ rb,
2076
+ -sc * ra - sf * rb,
2077
+ rd,
2078
+ re,
2079
+ -sc * rd - sf * re
2080
+ ];
2081
+ }
2082
+ /** Get the 'a' component of an Affine transform. */
2083
+ function a(affine) {
2084
+ return affine[0];
2085
+ }
2086
+ /** Get the 'e' component of an Affine transform. */
2087
+ function e(affine) {
2088
+ return affine[4];
2132
2089
  }
2133
2090
  //#endregion
2091
+ //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/affine-tileset-level.js
2092
+ /**
2093
+ * A {@link RasterTilesetLevel} described by a single affine transform plus tile and
2094
+ * array sizes.
2095
+ *
2096
+ * This handles axis-aligned, rotated, skewed, and non-square-pixel grids
2097
+ * uniformly. Sources that fit this shape (tiled GeoTIFF overviews, GeoZarr
2098
+ * multiscales) can construct one of these per resolution level instead of
2099
+ * implementing {@link RasterTilesetLevel} manually.
2100
+ */
2101
+ var AffineTilesetLevel = class {
2102
+ tileWidth;
2103
+ tileHeight;
2104
+ matrixWidth;
2105
+ matrixHeight;
2106
+ metersPerPixel;
2107
+ /**
2108
+ * Source-CRS bounding box of the level's array `[minX, minY, maxX, maxY]`.
2109
+ * Computed from the affine applied to the four array corners.
2110
+ */
2111
+ projectedBounds;
2112
+ _affine;
2113
+ _invAffine;
2114
+ constructor(options) {
2115
+ this._affine = options.affine;
2116
+ this._invAffine = invert$2(options.affine);
2117
+ this.tileWidth = options.tileWidth;
2118
+ this.tileHeight = options.tileHeight;
2119
+ this.matrixWidth = Math.ceil(options.arrayWidth / options.tileWidth);
2120
+ this.matrixHeight = Math.ceil(options.arrayHeight / options.tileHeight);
2121
+ const a$1 = a(options.affine);
2122
+ const e$1 = e(options.affine);
2123
+ this.metersPerPixel = Math.sqrt(Math.abs(a$1 * e$1)) * options.mpu;
2124
+ const corners = [
2125
+ apply(options.affine, 0, 0),
2126
+ apply(options.affine, options.arrayWidth, 0),
2127
+ apply(options.affine, 0, options.arrayHeight),
2128
+ apply(options.affine, options.arrayWidth, options.arrayHeight)
2129
+ ];
2130
+ const xs = corners.map(([x]) => x);
2131
+ const ys = corners.map(([, y]) => y);
2132
+ this.projectedBounds = [
2133
+ Math.min(...xs),
2134
+ Math.min(...ys),
2135
+ Math.max(...xs),
2136
+ Math.max(...ys)
2137
+ ];
2138
+ }
2139
+ projectedTileCorners(col, row) {
2140
+ const tw = this.tileWidth;
2141
+ const th = this.tileHeight;
2142
+ const af = this._affine;
2143
+ return {
2144
+ topLeft: apply(af, col * tw, row * th),
2145
+ topRight: apply(af, (col + 1) * tw, row * th),
2146
+ bottomLeft: apply(af, col * tw, (row + 1) * th),
2147
+ bottomRight: apply(af, (col + 1) * tw, (row + 1) * th)
2148
+ };
2149
+ }
2150
+ tileTransform(col, row) {
2151
+ const tileOffset = translation(col * this.tileWidth, row * this.tileHeight);
2152
+ const tileAffine = compose(this._affine, tileOffset);
2153
+ const invTileAffine = invert$2(tileAffine);
2154
+ return {
2155
+ forwardTransform: (x, y) => apply(tileAffine, x, y),
2156
+ inverseTransform: (x, y) => apply(invTileAffine, x, y)
2157
+ };
2158
+ }
2159
+ crsBoundsToTileRange(projectedMinX, projectedMinY, projectedMaxX, projectedMaxY) {
2160
+ const inv = this._invAffine;
2161
+ const pixelCorners = [
2162
+ apply(inv, projectedMinX, projectedMinY),
2163
+ apply(inv, projectedMaxX, projectedMinY),
2164
+ apply(inv, projectedMinX, projectedMaxY),
2165
+ apply(inv, projectedMaxX, projectedMaxY)
2166
+ ];
2167
+ const xs = pixelCorners.map(([px]) => px);
2168
+ const ys = pixelCorners.map(([, py]) => py);
2169
+ const pixMinX = Math.min(...xs);
2170
+ const pixMaxX = Math.max(...xs);
2171
+ const pixMinY = Math.min(...ys);
2172
+ const pixMaxY = Math.max(...ys);
2173
+ const tw = this.tileWidth;
2174
+ const th = this.tileHeight;
2175
+ const maxColIdx = this.matrixWidth - 1;
2176
+ const maxRowIdx = this.matrixHeight - 1;
2177
+ return {
2178
+ minCol: Math.max(0, Math.floor(pixMinX / tw)),
2179
+ maxCol: Math.min(maxColIdx, Math.floor(pixMaxX / tw)),
2180
+ minRow: Math.max(0, Math.floor(pixMinY / th)),
2181
+ maxRow: Math.min(maxRowIdx, Math.floor(pixMaxY / th))
2182
+ };
2183
+ }
2184
+ };
2185
+ //#endregion
2134
2186
  //#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/bounding-volume-cache.js
2135
2187
  var DEFAULT_MAX_ENTRIES = 65536;
2136
2188
  /**
@@ -16284,6 +16336,44 @@ var COLORMAP_OPTIONS = COLORMAP_NAMES.map((name) => ({
16284
16336
  rowIndex: COLORMAP_INDEX[name]
16285
16337
  }));
16286
16338
  //#endregion
16339
+ //#region src/lib/raster/repair-geokeys.ts
16340
+ /**
16341
+ * Repair GeoTIFFs whose projected CRS is tagged with a "user-defined" model
16342
+ * type so {@link import('@developmentseed/geotiff').Overview.crs} can build it.
16343
+ *
16344
+ * `crsFromGeoKeys` only accepts `GTModelTypeGeoKey` of 1 (projected) or 2
16345
+ * (geographic) and throws `Unsupported GeoTIFF model type: 32767` for anything
16346
+ * else. Some exporters (notably ArcGIS, which writes an ESRI PE string for the
16347
+ * `WGS_1984_Web_Mercator` / "Popular Visualisation CRS" auxiliary-sphere
16348
+ * Mercator) emit a fully specified projected CRS via the projection geo keys
16349
+ * but leave `GTModelTypeGeoKey` and `ProjectedCSTypeGeoKey` as user-defined
16350
+ * (32767). COGLayer then fails to resolve the CRS and the raster never draws,
16351
+ * even though the projection is completely described by the keys already
16352
+ * present. See GeoLibre issue #393.
16353
+ *
16354
+ * When a projection coordinate-transformation method is present
16355
+ * (`ProjMethodGeoKey`, exposed as `gkd.projMethod`), the CRS is unambiguously
16356
+ * projected, so we set `modelType` to projected. `crsFromGeoKeys` then takes
16357
+ * the projected path and builds a PROJJSON CRS from the projection keys (or
16358
+ * returns the EPSG code when `ProjectedCSTypeGeoKey` carries one). Files with a
16359
+ * valid model type, or user-defined geographic CRSes with no projection method,
16360
+ * are left untouched.
16361
+ *
16362
+ * Must run before any `Overview.crs` access, which caches its result; callers
16363
+ * invoke it immediately after opening the GeoTIFF and before handing it to
16364
+ * COGLayer.
16365
+ *
16366
+ * @param tiff - The opened GeoTIFF to repair in place.
16367
+ */
16368
+ function repairUserDefinedProjectedCrs(tiff) {
16369
+ const MODEL_TYPE_PROJECTED = 1;
16370
+ const MODEL_TYPE_USER_DEFINED = 32767;
16371
+ for (const overview of tiff.overviews) {
16372
+ const gkd = overview.gkd;
16373
+ if ((gkd.modelType === null || gkd.modelType === MODEL_TYPE_USER_DEFINED) && gkd.projMethod !== null) gkd.modelType = MODEL_TYPE_PROJECTED;
16374
+ }
16375
+ }
16376
+ //#endregion
16287
16377
  //#region src/lib/raster/load-geotiff.ts
16288
16378
  /**
16289
16379
  * COG access pattern is hundreds of distinct Range requests against the
@@ -16362,10 +16452,12 @@ function loadGeoTIFF(url) {
16362
16452
  const promise = (async () => {
16363
16453
  const source = new CorsSafeSourceHttp(url, {});
16364
16454
  const view = new SourceView(source, [new SourceChunk({ size: CHUNK_SIZE }), new SourceCache({ size: CACHE_SIZE })]);
16365
- return await GeoTIFF.open({
16455
+ const tiff = await GeoTIFF.open({
16366
16456
  dataSource: source,
16367
16457
  headerSource: view
16368
16458
  });
16459
+ repairUserDefinedProjectedCrs(tiff);
16460
+ return tiff;
16369
16461
  })();
16370
16462
  inflight.set(url, promise);
16371
16463
  promise.finally(() => inflight.delete(url)).catch(() => {});
@@ -17318,6 +17410,7 @@ function extractPalette(tiff) {
17318
17410
  var DEFAULT_DEPS$1 = {
17319
17411
  loadGeoTIFF,
17320
17412
  computeAutoStats,
17413
+ epsgResolver: createResilientEpsgResolver(),
17321
17414
  createOverlay: (map, options) => {
17322
17415
  const overlay = new MapboxOverlay({
17323
17416
  interleaved: options.interleaved,
@@ -17351,6 +17444,7 @@ var LayerManager = class {
17351
17444
  _device = null;
17352
17445
  _colormapTexture = null;
17353
17446
  _handlers = new globalThis.Map();
17447
+ _crsFailed = /* @__PURE__ */ new Set();
17354
17448
  _destroyed = false;
17355
17449
  /**
17356
17450
  * Creates a LayerManager bound to a map.
@@ -17486,6 +17580,7 @@ var LayerManager = class {
17486
17580
  const [layer] = this._layers.splice(index, 1);
17487
17581
  layer.abort.abort();
17488
17582
  if (layer.source.kind === "file") URL.revokeObjectURL(layer.source.objectUrl);
17583
+ this._crsFailed.delete(id);
17489
17584
  this._destroyPaletteTexture(layer);
17490
17585
  if (this._selectedId === id) this.select(this._layers[this._layers.length - 1]?.id ?? null);
17491
17586
  this._rebuild();
@@ -17679,7 +17774,7 @@ var LayerManager = class {
17679
17774
  * layer's tile cache across rebuilds. */
17680
17775
  _rebuild() {
17681
17776
  if (!this._overlay) return;
17682
- const layers = this._layers.filter((l) => l.geotiff && l.state.visible).map((l) => this._buildCogLayer(l));
17777
+ const layers = this._layers.filter((l) => l.geotiff && l.state.visible && !this._crsFailed.has(l.id)).map((l) => this._buildCogLayer(l));
17683
17778
  this._overlay.setProps({ layers });
17684
17779
  }
17685
17780
  _buildCogLayer(layer) {
@@ -17691,6 +17786,10 @@ var LayerManager = class {
17691
17786
  getTileData,
17692
17787
  renderTile,
17693
17788
  beforeId: this._resolveBeforeId(layer.beforeId),
17789
+ epsgResolver: (epsg) => this._deps.epsgResolver(epsg).catch((err) => {
17790
+ this._failLayerCrs(layer, err);
17791
+ throw err;
17792
+ }),
17694
17793
  onGeoTIFFLoad: (_tiff, options) => {
17695
17794
  const boundsArrived = !layer.bounds;
17696
17795
  layer.bounds = options.geographicBounds;
@@ -17705,6 +17804,26 @@ var LayerManager = class {
17705
17804
  }
17706
17805
  });
17707
17806
  }
17807
+ /** Records a CRS-resolution failure once: marks the layer errored, drops it
17808
+ * from future rebuilds (so the resolver is not retried in a loop), and emits
17809
+ * the error to consumers. Runs after the resolver promise settles, so it is
17810
+ * never synchronous with a deck.gl render. */
17811
+ _failLayerCrs(layer, err) {
17812
+ if (this._destroyed || !this.getLayer(layer.id) || this._crsFailed.has(layer.id)) return;
17813
+ this._crsFailed.add(layer.id);
17814
+ const error = err instanceof Error ? err : new Error(String(err));
17815
+ layer.loading = false;
17816
+ layer.error = error;
17817
+ this._emit({
17818
+ type: "error",
17819
+ layerId: layer.id,
17820
+ error
17821
+ });
17822
+ this._emit({
17823
+ type: "rasterchange",
17824
+ layerId: layer.id
17825
+ });
17826
+ }
17708
17827
  /** Returns the beforeId only when that layer exists in the map's current
17709
17828
  * style (warns otherwise). */
17710
17829
  _resolveBeforeId(beforeId) {
@@ -19151,7 +19270,8 @@ var DEFAULT_OPTIONS = {
19151
19270
  className: "",
19152
19271
  interleaved: true,
19153
19272
  defaultUrl: "",
19154
- autoLoad: false
19273
+ autoLoad: false,
19274
+ epsgResolver: createResilientEpsgResolver()
19155
19275
  };
19156
19276
  /**
19157
19277
  * A MapLibre GL control for visualizing local and remote raster datasets
@@ -19212,7 +19332,7 @@ var RasterControl = class {
19212
19332
  this._container = this._createContainer();
19213
19333
  this._panel = this._createPanel();
19214
19334
  this._mapContainer.appendChild(this._panel);
19215
- this._layerManager = new LayerManager(map, { interleaved: this._options.interleaved });
19335
+ this._layerManager = new LayerManager(map, { interleaved: this._options.interleaved }, { epsgResolver: this._options.epsgResolver });
19216
19336
  this._forwardLayerManagerEvents(this._layerManager);
19217
19337
  const manager = this._layerManager;
19218
19338
  this._inspector = new PixelInspector(map, () => {
@@ -19603,6 +19723,6 @@ var RasterControl = class {
19603
19723
  }
19604
19724
  };
19605
19725
  //#endregion
19606
- export { colormaps_default as _, debounce as a, throttle as c, percentileFromHistogram as d, readBandNames as f, COLORMAP_ROW_COUNT as g, COLORMAP_OPTIONS as h, classNames as i, MAX_SAMPLE_TILES as l, COLORMAP_NAMES as m, PALETTE_COLORMAP as n, formatNumericValue as o, loadGeoTIFF as p, clamp as r, generateId as s, RasterControl as t, computeAutoStats as u };
19726
+ export { colormaps_default as _, debounce as a, throttle as c, percentileFromHistogram as d, readBandNames as f, COLORMAP_ROW_COUNT as g, COLORMAP_OPTIONS as h, classNames as i, MAX_SAMPLE_TILES as l, COLORMAP_NAMES as m, PALETTE_COLORMAP as n, formatNumericValue as o, loadGeoTIFF as p, clamp as r, generateId as s, RasterControl as t, computeAutoStats as u, createResilientEpsgResolver as v };
19607
19727
 
19608
- //# sourceMappingURL=RasterControl-Dsq7VIl7.js.map
19728
+ //# sourceMappingURL=RasterControl-BxGg08KC.js.map