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.
- package/dist/{RasterControl-Dsq7VIl7.js → RasterControl-BxGg08KC.js} +2110 -1990
- package/dist/RasterControl-BxGg08KC.js.map +1 -0
- package/dist/index.mjs +2 -2
- package/dist/react.mjs +1 -1
- package/dist/types/index.d.ts +31 -0
- package/dist/types/react.d.ts +9 -0
- package/package.json +1 -1
- package/dist/RasterControl-Dsq7VIl7.js.map +0 -1
|
@@ -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/
|
|
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
|
-
*
|
|
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
|
-
*
|
|
13
|
+
* From note g in http://docs.opengeospatial.org/is/17-083r2/17-083r2.html#table_2:
|
|
72
14
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
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
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
745
|
-
|
|
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
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
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
|
|
240
|
+
return result;
|
|
844
241
|
}
|
|
845
242
|
};
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
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
|
-
|
|
856
|
-
indices: new Uint32Array(reprojector.triangles),
|
|
857
|
-
positions,
|
|
858
|
-
texCoords
|
|
859
|
-
};
|
|
860
|
-
}
|
|
252
|
+
};
|
|
861
253
|
//#endregion
|
|
862
|
-
//#region node_modules
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
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
|
|
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
|
-
*
|
|
949
|
-
*
|
|
950
|
-
*
|
|
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
|
|
964
|
-
return
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
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
|
-
*
|
|
975
|
-
*
|
|
976
|
-
* @
|
|
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
|
|
981
|
-
|
|
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
|
|
298
|
+
//#region node_modules/wkt-parser/detectWKTVersion.js
|
|
1007
299
|
/**
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
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
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
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
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
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
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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
|
-
|
|
1101
|
-
|
|
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 (
|
|
1127
|
-
|
|
1128
|
-
|
|
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/
|
|
1134
|
-
var
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
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
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
-
|
|
1186
|
-
|
|
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
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
result.
|
|
1195
|
-
|
|
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 "
|
|
1256
|
-
result.
|
|
1257
|
-
result.
|
|
1258
|
-
result.
|
|
1259
|
-
|
|
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 "
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
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 "
|
|
1267
|
-
result.
|
|
1268
|
-
result
|
|
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 "
|
|
1274
|
-
result.
|
|
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 "
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
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
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
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 "
|
|
1311
|
-
if (
|
|
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 "
|
|
1318
|
-
|
|
1319
|
-
if (
|
|
1320
|
-
|
|
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
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
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
|
-
|
|
1330
|
-
result
|
|
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
|
-
|
|
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
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
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/
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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/
|
|
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
|
-
*
|
|
1373
|
-
*
|
|
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
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
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
|
-
*
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
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
|
|
1388
|
-
return (
|
|
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
|
|
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
|
-
*
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
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
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
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/
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
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
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
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
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
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
|
-
|
|
1475
|
-
|
|
1476
|
-
this.word += char;
|
|
1477
|
-
return;
|
|
1275
|
+
refine() {
|
|
1276
|
+
this._step();
|
|
1277
|
+
this._flush();
|
|
1478
1278
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
this.afterItem(char);
|
|
1482
|
-
return;
|
|
1279
|
+
getMaxError() {
|
|
1280
|
+
return this._errors[0];
|
|
1483
1281
|
}
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
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
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
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
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
this.
|
|
1505
|
-
|
|
1506
|
-
this.
|
|
1507
|
-
|
|
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
|
-
|
|
1510
|
-
this.
|
|
1511
|
-
|
|
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
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
this.
|
|
1518
|
-
this.
|
|
1519
|
-
|
|
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
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
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
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
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
|
-
|
|
1532
|
-
this.
|
|
1533
|
-
|
|
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
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
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
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
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
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
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
|
-
|
|
1573
|
-
|
|
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
|
-
|
|
1576
|
-
|
|
1577
|
-
return;
|
|
1490
|
+
_queueLess(i, j) {
|
|
1491
|
+
return this._errors[i] > this._errors[j];
|
|
1578
1492
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
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
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
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
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
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
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
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
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
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/
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
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
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
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
|
-
|
|
1695
|
-
|
|
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
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
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
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
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/
|
|
1820
|
-
var
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
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
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
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
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
if (
|
|
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
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
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
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
if (
|
|
1876
|
-
|
|
1877
|
-
|
|
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
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
if (
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
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
|
-
|
|
1911
|
-
|
|
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/
|
|
1947
|
+
//#region node_modules/@developmentseed/deck.gl-raster/dist/raster-tileset/affine-tileset.js
|
|
2005
1948
|
/**
|
|
2006
|
-
*
|
|
2007
|
-
* definition.
|
|
1949
|
+
* A {@link RasterTilesetDescriptor} backed by per-level affine transforms.
|
|
2008
1950
|
*
|
|
2009
|
-
*
|
|
1951
|
+
* Derives `projectedBounds` from the coarsest level's array. Everything else
|
|
1952
|
+
* is passed through from the constructor options.
|
|
2010
1953
|
*/
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
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
|
-
|
|
2018
|
-
}
|
|
1970
|
+
};
|
|
2019
1971
|
//#endregion
|
|
2020
|
-
//#region node_modules/@developmentseed/
|
|
1972
|
+
//#region node_modules/@developmentseed/affine/dist/affine.js
|
|
2021
1973
|
/**
|
|
2022
|
-
*
|
|
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
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
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
|
-
*
|
|
2044
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
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
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
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
|
-
*
|
|
2099
|
-
*
|
|
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
|
|
2102
|
-
|
|
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
|
-
*
|
|
2033
|
+
* Compose two affine transforms: A×B (apply B **first**, then A).
|
|
2108
2034
|
*
|
|
2109
|
-
*
|
|
2110
|
-
*
|
|
2111
|
-
*
|
|
2112
|
-
*
|
|
2113
|
-
*
|
|
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
|
-
*
|
|
2043
|
+
* @param A The first affine transform to apply.
|
|
2044
|
+
* @param B The second affine transform to apply.
|
|
2116
2045
|
*
|
|
2117
|
-
*
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
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
|
-
*
|
|
2123
|
-
*
|
|
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
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
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
|
-
|
|
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-
|
|
19728
|
+
//# sourceMappingURL=RasterControl-BxGg08KC.js.map
|