@mapcatch/util 2.0.4 → 2.0.5-b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/catchUtil.min.esm.js +56 -102
- package/dist/catchUtil.min.js +2 -2
- package/package.json +26 -2
- package/src/constants/crs.js +42098 -42098
- package/src/constants/default_layers.js +42 -94
- package/src/gl-operations/constants.js +9 -9
- package/src/gl-operations/default_options.js +97 -97
- package/src/gl-operations/index.js +532 -532
- package/src/gl-operations/reglCommands/contours.js +27 -27
- package/src/gl-operations/reglCommands/default.js +45 -45
- package/src/gl-operations/reglCommands/hillshading.js +340 -340
- package/src/gl-operations/reglCommands/index.js +6 -6
- package/src/gl-operations/reglCommands/multiLayers.js +303 -303
- package/src/gl-operations/reglCommands/transitions.js +111 -111
- package/src/gl-operations/reglCommands/util.js +71 -71
- package/src/gl-operations/renderer.js +209 -209
- package/src/gl-operations/shaders/fragment/convertDem.js +25 -25
- package/src/gl-operations/shaders/fragment/convolutionSmooth.js +54 -54
- package/src/gl-operations/shaders/fragment/diffCalc.js +33 -33
- package/src/gl-operations/shaders/fragment/drawResult.js +46 -46
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvAmbientShadows.js +78 -78
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvDirect.js +59 -59
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalBaselayer.js +30 -30
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalColorscale.js +60 -60
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvMergeAndScaleTiles.js +26 -26
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvNormals.js +25 -25
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvSmooth.js +53 -53
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvSoftShadows.js +80 -80
- package/src/gl-operations/shaders/fragment/hillshading/hsPregen.js +54 -54
- package/src/gl-operations/shaders/fragment/interpolateColor.js +65 -65
- package/src/gl-operations/shaders/fragment/interpolateColorOnly.js +49 -49
- package/src/gl-operations/shaders/fragment/interpolateValue.js +136 -136
- package/src/gl-operations/shaders/fragment/multiAnalyze1Calc.js +35 -35
- package/src/gl-operations/shaders/fragment/multiAnalyze2Calc.js +45 -45
- package/src/gl-operations/shaders/fragment/multiAnalyze3Calc.js +53 -53
- package/src/gl-operations/shaders/fragment/multiAnalyze4Calc.js +61 -61
- package/src/gl-operations/shaders/fragment/multiAnalyze5Calc.js +69 -69
- package/src/gl-operations/shaders/fragment/multiAnalyze6Calc.js +77 -77
- package/src/gl-operations/shaders/fragment/single.js +93 -93
- package/src/gl-operations/shaders/transform.js +21 -21
- package/src/gl-operations/shaders/util/computeColor.glsl +85 -85
- package/src/gl-operations/shaders/util/getTexelValue.glsl +10 -10
- package/src/gl-operations/shaders/util/isCloseEnough.glsl +9 -9
- package/src/gl-operations/shaders/util/rgbaToFloat.glsl +17 -17
- package/src/gl-operations/shaders/vertex/double.js +16 -16
- package/src/gl-operations/shaders/vertex/multi3.js +19 -19
- package/src/gl-operations/shaders/vertex/multi4.js +22 -22
- package/src/gl-operations/shaders/vertex/multi5.js +25 -25
- package/src/gl-operations/shaders/vertex/multi6.js +28 -28
- package/src/gl-operations/shaders/vertex/single.js +13 -13
- package/src/gl-operations/shaders/vertex/singleNotTransformed.js +11 -11
- package/src/gl-operations/texture_manager.js +141 -141
- package/src/gl-operations/util.js +336 -336
- package/src/util.js +14 -6
- package/CHANGELOG.md +0 -72
|
@@ -1,533 +1,533 @@
|
|
|
1
|
-
import defaultOptions from './default_options'
|
|
2
|
-
import * as util from './util'
|
|
3
|
-
import Renderer from './renderer'
|
|
4
|
-
import { EARTH_CIRCUMFERENCE } from './constants'
|
|
5
|
-
|
|
6
|
-
export default class GLOperations {
|
|
7
|
-
constructor (options) {
|
|
8
|
-
this.options = Object.assign({}, defaultOptions, options)
|
|
9
|
-
this._checkColorScaleAndSentinels()
|
|
10
|
-
this.setHillshadeOptions()
|
|
11
|
-
const {
|
|
12
|
-
nodataValue,
|
|
13
|
-
tileSize
|
|
14
|
-
} = this.options
|
|
15
|
-
|
|
16
|
-
this._renderer = new Renderer(
|
|
17
|
-
this,
|
|
18
|
-
tileSize,
|
|
19
|
-
nodataValue,
|
|
20
|
-
this.options.colorScale,
|
|
21
|
-
this.options.sentinelValues,
|
|
22
|
-
this.options.colorscaleMaxLength,
|
|
23
|
-
this.options.sentinelMaxLength,
|
|
24
|
-
this.options.aboveColor,
|
|
25
|
-
this.options.belowColor
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
this._renderer.generateAmbientDirections(this.options.hsAdvAmbientIterations)
|
|
29
|
-
this._renderer.generateSunDirections(
|
|
30
|
-
this.options.hsAdvSoftIterations,
|
|
31
|
-
this.options.hsAdvSunRadiusMultiplier
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
destroy () {
|
|
36
|
-
if (this._renderer) this._renderer.destroy()
|
|
37
|
-
this._renderer = null
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
updateOptions (options) {
|
|
41
|
-
const {
|
|
42
|
-
url: prevUrl,
|
|
43
|
-
operationUrlA: prevUrlA,
|
|
44
|
-
operationUrlB: prevUrlB,
|
|
45
|
-
operationUrlC: prevUrlC,
|
|
46
|
-
operationUrlD: prevUrlD,
|
|
47
|
-
colorScale: prevColorScale,
|
|
48
|
-
sentinelValues: prevSentinelValues,
|
|
49
|
-
hillshadeType: prevHillshadeType,
|
|
50
|
-
hsAdvSoftIterations: prevHsAdvSoftIterations,
|
|
51
|
-
hsAdvAmbientIterations: prevHsAdvAmbientIterations,
|
|
52
|
-
hsAdvSunRadiusMultiplier: prevHsAdvSunRadiusMultiplier,
|
|
53
|
-
hsAdvBaselayerUrl: prevHsAdvBaselayerUrl,
|
|
54
|
-
colorscaleMaxLength: prevScaleMaxLength,
|
|
55
|
-
sentinelMaxLength: prevSentinelMaxLength,
|
|
56
|
-
aboveColor: prevAboveColor,
|
|
57
|
-
belowColor: prevBelowColor
|
|
58
|
-
} = this.options
|
|
59
|
-
Object.assign(this.options, options)
|
|
60
|
-
// create new renderer if max length of sentinels or colorscale changes
|
|
61
|
-
if (this.options.colorscaleMaxLength !== prevScaleMaxLength || this.options.sentinelMaxLength !== prevSentinelMaxLength) {
|
|
62
|
-
const tileSize = this._tileSizeAsNumber()
|
|
63
|
-
const renderer = new Renderer(
|
|
64
|
-
this,
|
|
65
|
-
tileSize,
|
|
66
|
-
this.options.nodataValue,
|
|
67
|
-
this.options.colorScale,
|
|
68
|
-
this.options.sentinelValues,
|
|
69
|
-
this.options.colorscaleMaxLength,
|
|
70
|
-
this.options.sentinelMaxLength
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
this._renderer.regl.destroy()
|
|
74
|
-
// @ts-ignore
|
|
75
|
-
delete this._renderer
|
|
76
|
-
|
|
77
|
-
Object.assign(this, {
|
|
78
|
-
_renderer: renderer
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
this._checkColorScaleAndSentinels()
|
|
82
|
-
if (this.options.colorScale !== prevColorScale) {
|
|
83
|
-
this._renderer.updateColorscale(this.options.colorScale)
|
|
84
|
-
}
|
|
85
|
-
if (this.options.aboveColor !== prevAboveColor || this.options.belowColor !== prevBelowColor) {
|
|
86
|
-
this._renderer.updateOuteRangeColor(this.options.aboveColor, this.options.belowColor)
|
|
87
|
-
}
|
|
88
|
-
if (this.options.sentinelValues !== prevSentinelValues) {
|
|
89
|
-
this._renderer.updateSentinels(this.options.sentinelValues)
|
|
90
|
-
}
|
|
91
|
-
if (this.options.hsAdvAmbientIterations !== prevHsAdvAmbientIterations) {
|
|
92
|
-
this._renderer.generateAmbientDirections(this.options.hsAdvAmbientIterations)
|
|
93
|
-
}
|
|
94
|
-
if (
|
|
95
|
-
this.options.hsAdvSoftIterations !== prevHsAdvSoftIterations ||
|
|
96
|
-
this.options.hsAdvSunRadiusMultiplier !== prevHsAdvSunRadiusMultiplier
|
|
97
|
-
) {
|
|
98
|
-
this._renderer.generateSunDirections(this.options.hsAdvSoftIterations, this.options.hsAdvSunRadiusMultiplier)
|
|
99
|
-
}
|
|
100
|
-
this.setHillshadeOptions()
|
|
101
|
-
|
|
102
|
-
if (this.options.extraPixelLayers > 0 && this.options.glOperation === 'none') {
|
|
103
|
-
this._maybeLoadExtraLayers(prevUrlA, prevUrlB, prevUrlC, prevUrlD)
|
|
104
|
-
}
|
|
105
|
-
// TODO: Fix shader so simple hillshading works ok with larger texture than tileSize
|
|
106
|
-
if (this.options.hillshadeType !== prevHillshadeType) {
|
|
107
|
-
// reduce textureManager size as simple hillshading type currently gets "edges" around the tiles with larger texture.
|
|
108
|
-
if (this.options.hillshadeType === 'simple') {
|
|
109
|
-
this._renderer.setMaxTextureDimension(this._tileSizeAsNumber())
|
|
110
|
-
} else if (prevHillshadeType === 'simple') {
|
|
111
|
-
this._renderer.setMaxTextureDimension(this._renderer.findMaxTextureDimension())
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (this.options.url !== prevUrl) {
|
|
116
|
-
// need to clear tiles so they are not reused with adv.hs.
|
|
117
|
-
this._renderer.textureManager.clearTiles()
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (this.options.hsAdvBaselayerUrl !== prevHsAdvBaselayerUrl) {
|
|
121
|
-
// need to clear tiles so they are not reused
|
|
122
|
-
// TODO: Check why necessary
|
|
123
|
-
this._renderer.textureManagerHillshade.clearTiles()
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
createTile (coords) {
|
|
128
|
-
const {
|
|
129
|
-
extraPixelLayers,
|
|
130
|
-
tileSize,
|
|
131
|
-
url,
|
|
132
|
-
operationUrlA,
|
|
133
|
-
operationUrlB,
|
|
134
|
-
operationUrlC,
|
|
135
|
-
operationUrlD,
|
|
136
|
-
operationUrlE,
|
|
137
|
-
operationUrlF,
|
|
138
|
-
filterLowA,
|
|
139
|
-
filterHighA,
|
|
140
|
-
filterLowB,
|
|
141
|
-
filterHighB,
|
|
142
|
-
filterLowC,
|
|
143
|
-
filterHighC,
|
|
144
|
-
filterLowD,
|
|
145
|
-
filterHighD,
|
|
146
|
-
filterLowE,
|
|
147
|
-
filterHighE,
|
|
148
|
-
filterLowF,
|
|
149
|
-
filterHighF,
|
|
150
|
-
multiplierA,
|
|
151
|
-
multiplierB,
|
|
152
|
-
multiplierC,
|
|
153
|
-
multiplierD,
|
|
154
|
-
multiplierE,
|
|
155
|
-
multiplierF
|
|
156
|
-
} = this.options
|
|
157
|
-
|
|
158
|
-
// Create a <canvas> element to contain the rendered image.
|
|
159
|
-
const tileCanvas = document.createElement('canvas')
|
|
160
|
-
// Configure the element.
|
|
161
|
-
Object.assign(tileCanvas, {
|
|
162
|
-
className: 'gl-tile',
|
|
163
|
-
width: tileSize,
|
|
164
|
-
height: tileSize
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
return new Promise((resolve) => {
|
|
168
|
-
if (this.options.glOperation === 'none') {
|
|
169
|
-
// Download an extra layer if required
|
|
170
|
-
if (extraPixelLayers === 1) {
|
|
171
|
-
this._fetchTileData(coords, operationUrlA).then((pixelDataA) => {
|
|
172
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
this._fetchTileData(coords, url).then((pixelData) => {
|
|
177
|
-
let [sourceX, sourceY] = this._renderer.renderTile(
|
|
178
|
-
{ coords, pixelData },
|
|
179
|
-
this.options._hillshadeOptions,
|
|
180
|
-
coords.z
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
184
|
-
tileCanvas.pixelData = pixelData
|
|
185
|
-
|
|
186
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
187
|
-
|
|
188
|
-
resolve(tileCanvas)
|
|
189
|
-
})
|
|
190
|
-
} else if (this.options.glOperation === 'diff') {
|
|
191
|
-
Promise.all([
|
|
192
|
-
this._fetchTileData(coords, operationUrlA),
|
|
193
|
-
this._fetchTileData(coords, operationUrlB)
|
|
194
|
-
]).then((pixelDataArray) => {
|
|
195
|
-
const pixelDataA = pixelDataArray[0]
|
|
196
|
-
const pixelDataB = pixelDataArray[1]
|
|
197
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileDiff(
|
|
198
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
199
|
-
{ coords: coords, pixelData: pixelDataB }
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
203
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
204
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
205
|
-
|
|
206
|
-
// Copy contents to tileCanvas.
|
|
207
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
208
|
-
})
|
|
209
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 1) {
|
|
210
|
-
Promise.all([
|
|
211
|
-
this._fetchTileData(coords, operationUrlA)
|
|
212
|
-
]).then((pixelDataArray) => {
|
|
213
|
-
const pixelDataA = pixelDataArray[0]
|
|
214
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti1(
|
|
215
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
216
|
-
filterLowA,
|
|
217
|
-
filterHighA,
|
|
218
|
-
multiplierA
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
222
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
223
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
224
|
-
|
|
225
|
-
// Copy contents to tileCanvas.
|
|
226
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
227
|
-
})
|
|
228
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 2) {
|
|
229
|
-
Promise.all([
|
|
230
|
-
this._fetchTileData(coords, operationUrlA),
|
|
231
|
-
this._fetchTileData(coords, operationUrlB)
|
|
232
|
-
]).then((pixelDataArray) => {
|
|
233
|
-
const pixelDataA = pixelDataArray[0]
|
|
234
|
-
const pixelDataB = pixelDataArray[1]
|
|
235
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti2(
|
|
236
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
237
|
-
{ coords: coords, pixelData: pixelDataB },
|
|
238
|
-
filterLowA,
|
|
239
|
-
filterHighA,
|
|
240
|
-
filterLowB,
|
|
241
|
-
filterHighB,
|
|
242
|
-
multiplierA,
|
|
243
|
-
multiplierB
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
247
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
248
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
249
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
250
|
-
|
|
251
|
-
// Copy contents to tileCanvas.
|
|
252
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
253
|
-
})
|
|
254
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 3) {
|
|
255
|
-
Promise.all([
|
|
256
|
-
this._fetchTileData(coords, operationUrlA),
|
|
257
|
-
this._fetchTileData(coords, operationUrlB),
|
|
258
|
-
this._fetchTileData(coords, operationUrlC)
|
|
259
|
-
]).then((pixelDataArray) => {
|
|
260
|
-
const pixelDataA = pixelDataArray[0]
|
|
261
|
-
const pixelDataB = pixelDataArray[1]
|
|
262
|
-
const pixelDataC = pixelDataArray[2]
|
|
263
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti3(
|
|
264
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
265
|
-
{ coords: coords, pixelData: pixelDataB },
|
|
266
|
-
{ coords: coords, pixelData: pixelDataC },
|
|
267
|
-
filterLowA,
|
|
268
|
-
filterHighA,
|
|
269
|
-
filterLowB,
|
|
270
|
-
filterHighB,
|
|
271
|
-
filterLowC,
|
|
272
|
-
filterHighC,
|
|
273
|
-
multiplierA,
|
|
274
|
-
multiplierB,
|
|
275
|
-
multiplierC
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
279
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
280
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
281
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
282
|
-
tileCanvas.pixelDataC = pixelDataC
|
|
283
|
-
|
|
284
|
-
// Copy contents to tileCanvas.
|
|
285
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
286
|
-
})
|
|
287
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 4) {
|
|
288
|
-
Promise.all([
|
|
289
|
-
this._fetchTileData(coords, operationUrlA),
|
|
290
|
-
this._fetchTileData(coords, operationUrlB),
|
|
291
|
-
this._fetchTileData(coords, operationUrlC),
|
|
292
|
-
this._fetchTileData(coords, operationUrlD)
|
|
293
|
-
]).then((pixelDataArray) => {
|
|
294
|
-
const pixelDataA = pixelDataArray[0]
|
|
295
|
-
const pixelDataB = pixelDataArray[1]
|
|
296
|
-
const pixelDataC = pixelDataArray[2]
|
|
297
|
-
const pixelDataD = pixelDataArray[3]
|
|
298
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti4(
|
|
299
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
300
|
-
{ coords: coords, pixelData: pixelDataB },
|
|
301
|
-
{ coords: coords, pixelData: pixelDataC },
|
|
302
|
-
{ coords: coords, pixelData: pixelDataD },
|
|
303
|
-
filterLowA,
|
|
304
|
-
filterHighA,
|
|
305
|
-
filterLowB,
|
|
306
|
-
filterHighB,
|
|
307
|
-
filterLowC,
|
|
308
|
-
filterHighC,
|
|
309
|
-
filterLowD,
|
|
310
|
-
filterHighD,
|
|
311
|
-
multiplierA,
|
|
312
|
-
multiplierB,
|
|
313
|
-
multiplierC,
|
|
314
|
-
multiplierD
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
318
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
319
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
320
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
321
|
-
tileCanvas.pixelDataC = pixelDataC
|
|
322
|
-
tileCanvas.pixelDataD = pixelDataD
|
|
323
|
-
|
|
324
|
-
// Copy contents to tileCanvas.
|
|
325
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
326
|
-
})
|
|
327
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 5) {
|
|
328
|
-
Promise.all([
|
|
329
|
-
this._fetchTileData(coords, operationUrlA),
|
|
330
|
-
this._fetchTileData(coords, operationUrlB),
|
|
331
|
-
this._fetchTileData(coords, operationUrlC),
|
|
332
|
-
this._fetchTileData(coords, operationUrlD),
|
|
333
|
-
this._fetchTileData(coords, operationUrlE)
|
|
334
|
-
]).then((pixelDataArray) => {
|
|
335
|
-
const pixelDataA = pixelDataArray[0]
|
|
336
|
-
const pixelDataB = pixelDataArray[1]
|
|
337
|
-
const pixelDataC = pixelDataArray[2]
|
|
338
|
-
const pixelDataD = pixelDataArray[3]
|
|
339
|
-
const pixelDataE = pixelDataArray[4]
|
|
340
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti5(
|
|
341
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
342
|
-
{ coords: coords, pixelData: pixelDataB },
|
|
343
|
-
{ coords: coords, pixelData: pixelDataC },
|
|
344
|
-
{ coords: coords, pixelData: pixelDataD },
|
|
345
|
-
{ coords: coords, pixelData: pixelDataE },
|
|
346
|
-
filterLowA,
|
|
347
|
-
filterHighA,
|
|
348
|
-
filterLowB,
|
|
349
|
-
filterHighB,
|
|
350
|
-
filterLowC,
|
|
351
|
-
filterHighC,
|
|
352
|
-
filterLowD,
|
|
353
|
-
filterHighD,
|
|
354
|
-
filterLowE,
|
|
355
|
-
filterHighE,
|
|
356
|
-
multiplierA,
|
|
357
|
-
multiplierB,
|
|
358
|
-
multiplierC,
|
|
359
|
-
multiplierD,
|
|
360
|
-
multiplierE
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
364
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
365
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
366
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
367
|
-
tileCanvas.pixelDataC = pixelDataC
|
|
368
|
-
tileCanvas.pixelDataD = pixelDataD
|
|
369
|
-
tileCanvas.pixelDataE = pixelDataE
|
|
370
|
-
|
|
371
|
-
// Copy contents to tileCanvas.
|
|
372
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
373
|
-
})
|
|
374
|
-
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 6) {
|
|
375
|
-
Promise.all([
|
|
376
|
-
this._fetchTileData(coords, operationUrlA),
|
|
377
|
-
this._fetchTileData(coords, operationUrlB),
|
|
378
|
-
this._fetchTileData(coords, operationUrlC),
|
|
379
|
-
this._fetchTileData(coords, operationUrlD),
|
|
380
|
-
this._fetchTileData(coords, operationUrlE),
|
|
381
|
-
this._fetchTileData(coords, operationUrlF)
|
|
382
|
-
]).then((pixelDataArray) => {
|
|
383
|
-
const pixelDataA = pixelDataArray[0]
|
|
384
|
-
const pixelDataB = pixelDataArray[1]
|
|
385
|
-
const pixelDataC = pixelDataArray[2]
|
|
386
|
-
const pixelDataD = pixelDataArray[3]
|
|
387
|
-
const pixelDataE = pixelDataArray[4]
|
|
388
|
-
const pixelDataF = pixelDataArray[5]
|
|
389
|
-
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti6(
|
|
390
|
-
{ coords: coords, pixelData: pixelDataA },
|
|
391
|
-
{ coords: coords, pixelData: pixelDataB },
|
|
392
|
-
{ coords: coords, pixelData: pixelDataC },
|
|
393
|
-
{ coords: coords, pixelData: pixelDataD },
|
|
394
|
-
{ coords: coords, pixelData: pixelDataE },
|
|
395
|
-
{ coords: coords, pixelData: pixelDataF },
|
|
396
|
-
filterLowA,
|
|
397
|
-
filterHighA,
|
|
398
|
-
filterLowB,
|
|
399
|
-
filterHighB,
|
|
400
|
-
filterLowC,
|
|
401
|
-
filterHighC,
|
|
402
|
-
filterLowD,
|
|
403
|
-
filterHighD,
|
|
404
|
-
filterLowE,
|
|
405
|
-
filterHighE,
|
|
406
|
-
filterLowF,
|
|
407
|
-
filterHighF,
|
|
408
|
-
multiplierA,
|
|
409
|
-
multiplierB,
|
|
410
|
-
multiplierC,
|
|
411
|
-
multiplierD,
|
|
412
|
-
multiplierE,
|
|
413
|
-
multiplierF
|
|
414
|
-
)
|
|
415
|
-
|
|
416
|
-
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
417
|
-
tileCanvas.pixelData = resultEncodedPixels
|
|
418
|
-
tileCanvas.pixelDataA = pixelDataA
|
|
419
|
-
tileCanvas.pixelDataB = pixelDataB
|
|
420
|
-
tileCanvas.pixelDataC = pixelDataC
|
|
421
|
-
tileCanvas.pixelDataD = pixelDataD
|
|
422
|
-
tileCanvas.pixelDataE = pixelDataE
|
|
423
|
-
tileCanvas.pixelDataF = pixelDataF
|
|
424
|
-
|
|
425
|
-
// Copy contents to tileCanvas.
|
|
426
|
-
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
427
|
-
})
|
|
428
|
-
}
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
_checkColorScaleAndSentinels () {
|
|
434
|
-
const {
|
|
435
|
-
colorScale,
|
|
436
|
-
sentinelValues,
|
|
437
|
-
colorscaleMaxLength,
|
|
438
|
-
sentinelMaxLength
|
|
439
|
-
} = this.options
|
|
440
|
-
if (colorScale.length === 0 && sentinelValues.length === 0) {
|
|
441
|
-
throw new Error('Either `colorScale` or `sentinelValues` must be of non-zero length.')
|
|
442
|
-
}
|
|
443
|
-
if (colorScale.length > colorscaleMaxLength) {
|
|
444
|
-
throw new Error(
|
|
445
|
-
`Color scale length ${colorScale.length} exceeds the maximum, ${colorscaleMaxLength}.`
|
|
446
|
-
)
|
|
447
|
-
}
|
|
448
|
-
if (sentinelValues.length > sentinelMaxLength) {
|
|
449
|
-
throw new Error(
|
|
450
|
-
`Sentinel values length ${sentinelValues.length} exceeds the maximum, ${sentinelMaxLength}.`
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
setHillshadeOptions () {
|
|
456
|
-
this.options._hillshadeOptions = {
|
|
457
|
-
hillshadeType: this.options.hillshadeType,
|
|
458
|
-
hsAdvValueScale: this.options.hsAdvValueScale,
|
|
459
|
-
hsAdvPixelScale: this.options.hsAdvPixelScale,
|
|
460
|
-
hsSimpleSlopescale: this.options.hsSimpleSlopescale,
|
|
461
|
-
hsSimpleAzimuth: this.options.hsSimpleAzimuth,
|
|
462
|
-
hsSimpleAltitude: this.options.hsSimpleAltitude,
|
|
463
|
-
hsSimpleZoomdelta: this.options.hsSimpleZoomdelta,
|
|
464
|
-
hsAdvSoftIterations: this.options.hsAdvSoftIterations,
|
|
465
|
-
hsAdvAmbientIterations: this.options.hsAdvAmbientIterations,
|
|
466
|
-
hsAdvSunRadiusMultiplier: this.options.hsAdvSunRadiusMultiplier,
|
|
467
|
-
hsAdvFinalSoftMultiplier: this.options.hsAdvFinalSoftMultiplier,
|
|
468
|
-
hsAdvFinalAmbientMultiplier: this.options.hsAdvFinalAmbientMultiplier,
|
|
469
|
-
hsAdvBaselayerUrl: this.options.hsAdvBaselayerUrl,
|
|
470
|
-
hsAdvSmoothInput: this.options.hsAdvSmoothInput,
|
|
471
|
-
hsAdvSmoothInputKernel: this.options.hsAdvSmoothInputKernel,
|
|
472
|
-
hsPregenUrl: this.options.hsPregenUrl
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
_tileSizeAsNumber () {
|
|
477
|
-
return this.options.tileSize
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
async _fetchTileData (coords, url, tileFormat = this.options.tileFormat) {
|
|
481
|
-
if (tileFormat === 'float32' || tileFormat === 'image') {
|
|
482
|
-
return util.fetchPNGData(this.getTileUrl(coords, url), this.options.nodataValue, this._tileSizeAsNumber())
|
|
483
|
-
} else if (tileFormat === 'dem') {
|
|
484
|
-
const nodataTile = util.createNoDataTile(this.options.nodataValue, this._tileSizeAsNumber())
|
|
485
|
-
const imageData = await util.fetchPNGData(this.getTileUrl(coords, url), this.options.nodataValue, this._tileSizeAsNumber())
|
|
486
|
-
if (util.typedArraysAreEqual(imageData, nodataTile)) {
|
|
487
|
-
return imageData
|
|
488
|
-
} else {
|
|
489
|
-
const rgbaData = this._renderer.renderConvertDem(imageData)
|
|
490
|
-
return rgbaData
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return util.createNoDataTile(this.options.nodataValue, this._tileSizeAsNumber())
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
_copyToTileCanvas (tile, sourceX, sourceY) {
|
|
497
|
-
const tileSize = this._tileSizeAsNumber()
|
|
498
|
-
const tileCanvas2DContext = tile.getContext('2d')
|
|
499
|
-
if (tileCanvas2DContext === null) {
|
|
500
|
-
throw new Error('Tile canvas 2D context is null.')
|
|
501
|
-
}
|
|
502
|
-
// Clear the current contents of the canvas. Otherwise, the new image will be composited with
|
|
503
|
-
// the existing image.
|
|
504
|
-
tileCanvas2DContext.clearRect(0, 0, tileSize, tileSize)
|
|
505
|
-
// Copy the image data from the Renderer's canvas to the tile's canvas.
|
|
506
|
-
tileCanvas2DContext.drawImage(
|
|
507
|
-
this._renderer.canvas,
|
|
508
|
-
sourceX, sourceY, tileSize, tileSize, // source canvas offset (x, y) and size (x, y)
|
|
509
|
-
0, 0, tileSize, tileSize // destination canvas offset (x, y) and size (x, y)
|
|
510
|
-
)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
getTileUrl (coords, url) {
|
|
514
|
-
return url
|
|
515
|
-
.replace(/{z}/g, String(coords.z))
|
|
516
|
-
.replace(/{x}/g, String(coords.x))
|
|
517
|
-
.replace(/{y}/g, String(coords.y))
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
_getPixelScale (coords) {
|
|
521
|
-
let {bbox: {south, north}, z: zoom} = coords
|
|
522
|
-
let pixelScale = 1
|
|
523
|
-
let lat = (south + north) / 2
|
|
524
|
-
if (this.options.hsAdvPixelScale === 'auto') {
|
|
525
|
-
pixelScale = EARTH_CIRCUMFERENCE * Math.abs(
|
|
526
|
-
Math.cos(lat / 180 * Math.PI
|
|
527
|
-
)) / Math.pow(2, zoom + 8)
|
|
528
|
-
} else if (typeof this.options.hsAdvPixelScale === 'number') {
|
|
529
|
-
pixelScale = this.options.hsAdvPixelScale / (this._tileSizeAsNumber() * (2 ** zoom))
|
|
530
|
-
}
|
|
531
|
-
return pixelScale
|
|
532
|
-
}
|
|
1
|
+
import defaultOptions from './default_options'
|
|
2
|
+
import * as util from './util'
|
|
3
|
+
import Renderer from './renderer'
|
|
4
|
+
import { EARTH_CIRCUMFERENCE } from './constants'
|
|
5
|
+
|
|
6
|
+
export default class GLOperations {
|
|
7
|
+
constructor (options) {
|
|
8
|
+
this.options = Object.assign({}, defaultOptions, options)
|
|
9
|
+
this._checkColorScaleAndSentinels()
|
|
10
|
+
this.setHillshadeOptions()
|
|
11
|
+
const {
|
|
12
|
+
nodataValue,
|
|
13
|
+
tileSize
|
|
14
|
+
} = this.options
|
|
15
|
+
|
|
16
|
+
this._renderer = new Renderer(
|
|
17
|
+
this,
|
|
18
|
+
tileSize,
|
|
19
|
+
nodataValue,
|
|
20
|
+
this.options.colorScale,
|
|
21
|
+
this.options.sentinelValues,
|
|
22
|
+
this.options.colorscaleMaxLength,
|
|
23
|
+
this.options.sentinelMaxLength,
|
|
24
|
+
this.options.aboveColor,
|
|
25
|
+
this.options.belowColor
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
this._renderer.generateAmbientDirections(this.options.hsAdvAmbientIterations)
|
|
29
|
+
this._renderer.generateSunDirections(
|
|
30
|
+
this.options.hsAdvSoftIterations,
|
|
31
|
+
this.options.hsAdvSunRadiusMultiplier
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
destroy () {
|
|
36
|
+
if (this._renderer) this._renderer.destroy()
|
|
37
|
+
this._renderer = null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
updateOptions (options) {
|
|
41
|
+
const {
|
|
42
|
+
url: prevUrl,
|
|
43
|
+
operationUrlA: prevUrlA,
|
|
44
|
+
operationUrlB: prevUrlB,
|
|
45
|
+
operationUrlC: prevUrlC,
|
|
46
|
+
operationUrlD: prevUrlD,
|
|
47
|
+
colorScale: prevColorScale,
|
|
48
|
+
sentinelValues: prevSentinelValues,
|
|
49
|
+
hillshadeType: prevHillshadeType,
|
|
50
|
+
hsAdvSoftIterations: prevHsAdvSoftIterations,
|
|
51
|
+
hsAdvAmbientIterations: prevHsAdvAmbientIterations,
|
|
52
|
+
hsAdvSunRadiusMultiplier: prevHsAdvSunRadiusMultiplier,
|
|
53
|
+
hsAdvBaselayerUrl: prevHsAdvBaselayerUrl,
|
|
54
|
+
colorscaleMaxLength: prevScaleMaxLength,
|
|
55
|
+
sentinelMaxLength: prevSentinelMaxLength,
|
|
56
|
+
aboveColor: prevAboveColor,
|
|
57
|
+
belowColor: prevBelowColor
|
|
58
|
+
} = this.options
|
|
59
|
+
Object.assign(this.options, options)
|
|
60
|
+
// create new renderer if max length of sentinels or colorscale changes
|
|
61
|
+
if (this.options.colorscaleMaxLength !== prevScaleMaxLength || this.options.sentinelMaxLength !== prevSentinelMaxLength) {
|
|
62
|
+
const tileSize = this._tileSizeAsNumber()
|
|
63
|
+
const renderer = new Renderer(
|
|
64
|
+
this,
|
|
65
|
+
tileSize,
|
|
66
|
+
this.options.nodataValue,
|
|
67
|
+
this.options.colorScale,
|
|
68
|
+
this.options.sentinelValues,
|
|
69
|
+
this.options.colorscaleMaxLength,
|
|
70
|
+
this.options.sentinelMaxLength
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
this._renderer.regl.destroy()
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
delete this._renderer
|
|
76
|
+
|
|
77
|
+
Object.assign(this, {
|
|
78
|
+
_renderer: renderer
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
this._checkColorScaleAndSentinels()
|
|
82
|
+
if (this.options.colorScale !== prevColorScale) {
|
|
83
|
+
this._renderer.updateColorscale(this.options.colorScale)
|
|
84
|
+
}
|
|
85
|
+
if (this.options.aboveColor !== prevAboveColor || this.options.belowColor !== prevBelowColor) {
|
|
86
|
+
this._renderer.updateOuteRangeColor(this.options.aboveColor, this.options.belowColor)
|
|
87
|
+
}
|
|
88
|
+
if (this.options.sentinelValues !== prevSentinelValues) {
|
|
89
|
+
this._renderer.updateSentinels(this.options.sentinelValues)
|
|
90
|
+
}
|
|
91
|
+
if (this.options.hsAdvAmbientIterations !== prevHsAdvAmbientIterations) {
|
|
92
|
+
this._renderer.generateAmbientDirections(this.options.hsAdvAmbientIterations)
|
|
93
|
+
}
|
|
94
|
+
if (
|
|
95
|
+
this.options.hsAdvSoftIterations !== prevHsAdvSoftIterations ||
|
|
96
|
+
this.options.hsAdvSunRadiusMultiplier !== prevHsAdvSunRadiusMultiplier
|
|
97
|
+
) {
|
|
98
|
+
this._renderer.generateSunDirections(this.options.hsAdvSoftIterations, this.options.hsAdvSunRadiusMultiplier)
|
|
99
|
+
}
|
|
100
|
+
this.setHillshadeOptions()
|
|
101
|
+
|
|
102
|
+
if (this.options.extraPixelLayers > 0 && this.options.glOperation === 'none') {
|
|
103
|
+
this._maybeLoadExtraLayers(prevUrlA, prevUrlB, prevUrlC, prevUrlD)
|
|
104
|
+
}
|
|
105
|
+
// TODO: Fix shader so simple hillshading works ok with larger texture than tileSize
|
|
106
|
+
if (this.options.hillshadeType !== prevHillshadeType) {
|
|
107
|
+
// reduce textureManager size as simple hillshading type currently gets "edges" around the tiles with larger texture.
|
|
108
|
+
if (this.options.hillshadeType === 'simple') {
|
|
109
|
+
this._renderer.setMaxTextureDimension(this._tileSizeAsNumber())
|
|
110
|
+
} else if (prevHillshadeType === 'simple') {
|
|
111
|
+
this._renderer.setMaxTextureDimension(this._renderer.findMaxTextureDimension())
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (this.options.url !== prevUrl) {
|
|
116
|
+
// need to clear tiles so they are not reused with adv.hs.
|
|
117
|
+
this._renderer.textureManager.clearTiles()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.options.hsAdvBaselayerUrl !== prevHsAdvBaselayerUrl) {
|
|
121
|
+
// need to clear tiles so they are not reused
|
|
122
|
+
// TODO: Check why necessary
|
|
123
|
+
this._renderer.textureManagerHillshade.clearTiles()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
createTile (coords) {
|
|
128
|
+
const {
|
|
129
|
+
extraPixelLayers,
|
|
130
|
+
tileSize,
|
|
131
|
+
url,
|
|
132
|
+
operationUrlA,
|
|
133
|
+
operationUrlB,
|
|
134
|
+
operationUrlC,
|
|
135
|
+
operationUrlD,
|
|
136
|
+
operationUrlE,
|
|
137
|
+
operationUrlF,
|
|
138
|
+
filterLowA,
|
|
139
|
+
filterHighA,
|
|
140
|
+
filterLowB,
|
|
141
|
+
filterHighB,
|
|
142
|
+
filterLowC,
|
|
143
|
+
filterHighC,
|
|
144
|
+
filterLowD,
|
|
145
|
+
filterHighD,
|
|
146
|
+
filterLowE,
|
|
147
|
+
filterHighE,
|
|
148
|
+
filterLowF,
|
|
149
|
+
filterHighF,
|
|
150
|
+
multiplierA,
|
|
151
|
+
multiplierB,
|
|
152
|
+
multiplierC,
|
|
153
|
+
multiplierD,
|
|
154
|
+
multiplierE,
|
|
155
|
+
multiplierF
|
|
156
|
+
} = this.options
|
|
157
|
+
|
|
158
|
+
// Create a <canvas> element to contain the rendered image.
|
|
159
|
+
const tileCanvas = document.createElement('canvas')
|
|
160
|
+
// Configure the element.
|
|
161
|
+
Object.assign(tileCanvas, {
|
|
162
|
+
className: 'gl-tile',
|
|
163
|
+
width: tileSize,
|
|
164
|
+
height: tileSize
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
return new Promise((resolve) => {
|
|
168
|
+
if (this.options.glOperation === 'none') {
|
|
169
|
+
// Download an extra layer if required
|
|
170
|
+
if (extraPixelLayers === 1) {
|
|
171
|
+
this._fetchTileData(coords, operationUrlA).then((pixelDataA) => {
|
|
172
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this._fetchTileData(coords, url).then((pixelData) => {
|
|
177
|
+
let [sourceX, sourceY] = this._renderer.renderTile(
|
|
178
|
+
{ coords, pixelData },
|
|
179
|
+
this.options._hillshadeOptions,
|
|
180
|
+
coords.z
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
184
|
+
tileCanvas.pixelData = pixelData
|
|
185
|
+
|
|
186
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
187
|
+
|
|
188
|
+
resolve(tileCanvas)
|
|
189
|
+
})
|
|
190
|
+
} else if (this.options.glOperation === 'diff') {
|
|
191
|
+
Promise.all([
|
|
192
|
+
this._fetchTileData(coords, operationUrlA),
|
|
193
|
+
this._fetchTileData(coords, operationUrlB)
|
|
194
|
+
]).then((pixelDataArray) => {
|
|
195
|
+
const pixelDataA = pixelDataArray[0]
|
|
196
|
+
const pixelDataB = pixelDataArray[1]
|
|
197
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileDiff(
|
|
198
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
199
|
+
{ coords: coords, pixelData: pixelDataB }
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
203
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
204
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
205
|
+
|
|
206
|
+
// Copy contents to tileCanvas.
|
|
207
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
208
|
+
})
|
|
209
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 1) {
|
|
210
|
+
Promise.all([
|
|
211
|
+
this._fetchTileData(coords, operationUrlA)
|
|
212
|
+
]).then((pixelDataArray) => {
|
|
213
|
+
const pixelDataA = pixelDataArray[0]
|
|
214
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti1(
|
|
215
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
216
|
+
filterLowA,
|
|
217
|
+
filterHighA,
|
|
218
|
+
multiplierA
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
222
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
223
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
224
|
+
|
|
225
|
+
// Copy contents to tileCanvas.
|
|
226
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
227
|
+
})
|
|
228
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 2) {
|
|
229
|
+
Promise.all([
|
|
230
|
+
this._fetchTileData(coords, operationUrlA),
|
|
231
|
+
this._fetchTileData(coords, operationUrlB)
|
|
232
|
+
]).then((pixelDataArray) => {
|
|
233
|
+
const pixelDataA = pixelDataArray[0]
|
|
234
|
+
const pixelDataB = pixelDataArray[1]
|
|
235
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti2(
|
|
236
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
237
|
+
{ coords: coords, pixelData: pixelDataB },
|
|
238
|
+
filterLowA,
|
|
239
|
+
filterHighA,
|
|
240
|
+
filterLowB,
|
|
241
|
+
filterHighB,
|
|
242
|
+
multiplierA,
|
|
243
|
+
multiplierB
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
247
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
248
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
249
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
250
|
+
|
|
251
|
+
// Copy contents to tileCanvas.
|
|
252
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
253
|
+
})
|
|
254
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 3) {
|
|
255
|
+
Promise.all([
|
|
256
|
+
this._fetchTileData(coords, operationUrlA),
|
|
257
|
+
this._fetchTileData(coords, operationUrlB),
|
|
258
|
+
this._fetchTileData(coords, operationUrlC)
|
|
259
|
+
]).then((pixelDataArray) => {
|
|
260
|
+
const pixelDataA = pixelDataArray[0]
|
|
261
|
+
const pixelDataB = pixelDataArray[1]
|
|
262
|
+
const pixelDataC = pixelDataArray[2]
|
|
263
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti3(
|
|
264
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
265
|
+
{ coords: coords, pixelData: pixelDataB },
|
|
266
|
+
{ coords: coords, pixelData: pixelDataC },
|
|
267
|
+
filterLowA,
|
|
268
|
+
filterHighA,
|
|
269
|
+
filterLowB,
|
|
270
|
+
filterHighB,
|
|
271
|
+
filterLowC,
|
|
272
|
+
filterHighC,
|
|
273
|
+
multiplierA,
|
|
274
|
+
multiplierB,
|
|
275
|
+
multiplierC
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
279
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
280
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
281
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
282
|
+
tileCanvas.pixelDataC = pixelDataC
|
|
283
|
+
|
|
284
|
+
// Copy contents to tileCanvas.
|
|
285
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
286
|
+
})
|
|
287
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 4) {
|
|
288
|
+
Promise.all([
|
|
289
|
+
this._fetchTileData(coords, operationUrlA),
|
|
290
|
+
this._fetchTileData(coords, operationUrlB),
|
|
291
|
+
this._fetchTileData(coords, operationUrlC),
|
|
292
|
+
this._fetchTileData(coords, operationUrlD)
|
|
293
|
+
]).then((pixelDataArray) => {
|
|
294
|
+
const pixelDataA = pixelDataArray[0]
|
|
295
|
+
const pixelDataB = pixelDataArray[1]
|
|
296
|
+
const pixelDataC = pixelDataArray[2]
|
|
297
|
+
const pixelDataD = pixelDataArray[3]
|
|
298
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti4(
|
|
299
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
300
|
+
{ coords: coords, pixelData: pixelDataB },
|
|
301
|
+
{ coords: coords, pixelData: pixelDataC },
|
|
302
|
+
{ coords: coords, pixelData: pixelDataD },
|
|
303
|
+
filterLowA,
|
|
304
|
+
filterHighA,
|
|
305
|
+
filterLowB,
|
|
306
|
+
filterHighB,
|
|
307
|
+
filterLowC,
|
|
308
|
+
filterHighC,
|
|
309
|
+
filterLowD,
|
|
310
|
+
filterHighD,
|
|
311
|
+
multiplierA,
|
|
312
|
+
multiplierB,
|
|
313
|
+
multiplierC,
|
|
314
|
+
multiplierD
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
318
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
319
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
320
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
321
|
+
tileCanvas.pixelDataC = pixelDataC
|
|
322
|
+
tileCanvas.pixelDataD = pixelDataD
|
|
323
|
+
|
|
324
|
+
// Copy contents to tileCanvas.
|
|
325
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
326
|
+
})
|
|
327
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 5) {
|
|
328
|
+
Promise.all([
|
|
329
|
+
this._fetchTileData(coords, operationUrlA),
|
|
330
|
+
this._fetchTileData(coords, operationUrlB),
|
|
331
|
+
this._fetchTileData(coords, operationUrlC),
|
|
332
|
+
this._fetchTileData(coords, operationUrlD),
|
|
333
|
+
this._fetchTileData(coords, operationUrlE)
|
|
334
|
+
]).then((pixelDataArray) => {
|
|
335
|
+
const pixelDataA = pixelDataArray[0]
|
|
336
|
+
const pixelDataB = pixelDataArray[1]
|
|
337
|
+
const pixelDataC = pixelDataArray[2]
|
|
338
|
+
const pixelDataD = pixelDataArray[3]
|
|
339
|
+
const pixelDataE = pixelDataArray[4]
|
|
340
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti5(
|
|
341
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
342
|
+
{ coords: coords, pixelData: pixelDataB },
|
|
343
|
+
{ coords: coords, pixelData: pixelDataC },
|
|
344
|
+
{ coords: coords, pixelData: pixelDataD },
|
|
345
|
+
{ coords: coords, pixelData: pixelDataE },
|
|
346
|
+
filterLowA,
|
|
347
|
+
filterHighA,
|
|
348
|
+
filterLowB,
|
|
349
|
+
filterHighB,
|
|
350
|
+
filterLowC,
|
|
351
|
+
filterHighC,
|
|
352
|
+
filterLowD,
|
|
353
|
+
filterHighD,
|
|
354
|
+
filterLowE,
|
|
355
|
+
filterHighE,
|
|
356
|
+
multiplierA,
|
|
357
|
+
multiplierB,
|
|
358
|
+
multiplierC,
|
|
359
|
+
multiplierD,
|
|
360
|
+
multiplierE
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
364
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
365
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
366
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
367
|
+
tileCanvas.pixelDataC = pixelDataC
|
|
368
|
+
tileCanvas.pixelDataD = pixelDataD
|
|
369
|
+
tileCanvas.pixelDataE = pixelDataE
|
|
370
|
+
|
|
371
|
+
// Copy contents to tileCanvas.
|
|
372
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
373
|
+
})
|
|
374
|
+
} else if (this.options.glOperation === 'multi' && this.options.multiLayers === 6) {
|
|
375
|
+
Promise.all([
|
|
376
|
+
this._fetchTileData(coords, operationUrlA),
|
|
377
|
+
this._fetchTileData(coords, operationUrlB),
|
|
378
|
+
this._fetchTileData(coords, operationUrlC),
|
|
379
|
+
this._fetchTileData(coords, operationUrlD),
|
|
380
|
+
this._fetchTileData(coords, operationUrlE),
|
|
381
|
+
this._fetchTileData(coords, operationUrlF)
|
|
382
|
+
]).then((pixelDataArray) => {
|
|
383
|
+
const pixelDataA = pixelDataArray[0]
|
|
384
|
+
const pixelDataB = pixelDataArray[1]
|
|
385
|
+
const pixelDataC = pixelDataArray[2]
|
|
386
|
+
const pixelDataD = pixelDataArray[3]
|
|
387
|
+
const pixelDataE = pixelDataArray[4]
|
|
388
|
+
const pixelDataF = pixelDataArray[5]
|
|
389
|
+
const [sourceX, sourceY, resultEncodedPixels] = this._renderer.renderTileMulti6(
|
|
390
|
+
{ coords: coords, pixelData: pixelDataA },
|
|
391
|
+
{ coords: coords, pixelData: pixelDataB },
|
|
392
|
+
{ coords: coords, pixelData: pixelDataC },
|
|
393
|
+
{ coords: coords, pixelData: pixelDataD },
|
|
394
|
+
{ coords: coords, pixelData: pixelDataE },
|
|
395
|
+
{ coords: coords, pixelData: pixelDataF },
|
|
396
|
+
filterLowA,
|
|
397
|
+
filterHighA,
|
|
398
|
+
filterLowB,
|
|
399
|
+
filterHighB,
|
|
400
|
+
filterLowC,
|
|
401
|
+
filterHighC,
|
|
402
|
+
filterLowD,
|
|
403
|
+
filterHighD,
|
|
404
|
+
filterLowE,
|
|
405
|
+
filterHighE,
|
|
406
|
+
filterLowF,
|
|
407
|
+
filterHighF,
|
|
408
|
+
multiplierA,
|
|
409
|
+
multiplierB,
|
|
410
|
+
multiplierC,
|
|
411
|
+
multiplierD,
|
|
412
|
+
multiplierE,
|
|
413
|
+
multiplierF
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
// Copy pixel data to a property on tile canvas element (for later retrieval).
|
|
417
|
+
tileCanvas.pixelData = resultEncodedPixels
|
|
418
|
+
tileCanvas.pixelDataA = pixelDataA
|
|
419
|
+
tileCanvas.pixelDataB = pixelDataB
|
|
420
|
+
tileCanvas.pixelDataC = pixelDataC
|
|
421
|
+
tileCanvas.pixelDataD = pixelDataD
|
|
422
|
+
tileCanvas.pixelDataE = pixelDataE
|
|
423
|
+
tileCanvas.pixelDataF = pixelDataF
|
|
424
|
+
|
|
425
|
+
// Copy contents to tileCanvas.
|
|
426
|
+
this._copyToTileCanvas(tileCanvas, sourceX, sourceY)
|
|
427
|
+
})
|
|
428
|
+
}
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
_checkColorScaleAndSentinels () {
|
|
434
|
+
const {
|
|
435
|
+
colorScale,
|
|
436
|
+
sentinelValues,
|
|
437
|
+
colorscaleMaxLength,
|
|
438
|
+
sentinelMaxLength
|
|
439
|
+
} = this.options
|
|
440
|
+
if (colorScale.length === 0 && sentinelValues.length === 0) {
|
|
441
|
+
throw new Error('Either `colorScale` or `sentinelValues` must be of non-zero length.')
|
|
442
|
+
}
|
|
443
|
+
if (colorScale.length > colorscaleMaxLength) {
|
|
444
|
+
throw new Error(
|
|
445
|
+
`Color scale length ${colorScale.length} exceeds the maximum, ${colorscaleMaxLength}.`
|
|
446
|
+
)
|
|
447
|
+
}
|
|
448
|
+
if (sentinelValues.length > sentinelMaxLength) {
|
|
449
|
+
throw new Error(
|
|
450
|
+
`Sentinel values length ${sentinelValues.length} exceeds the maximum, ${sentinelMaxLength}.`
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
setHillshadeOptions () {
|
|
456
|
+
this.options._hillshadeOptions = {
|
|
457
|
+
hillshadeType: this.options.hillshadeType,
|
|
458
|
+
hsAdvValueScale: this.options.hsAdvValueScale,
|
|
459
|
+
hsAdvPixelScale: this.options.hsAdvPixelScale,
|
|
460
|
+
hsSimpleSlopescale: this.options.hsSimpleSlopescale,
|
|
461
|
+
hsSimpleAzimuth: this.options.hsSimpleAzimuth,
|
|
462
|
+
hsSimpleAltitude: this.options.hsSimpleAltitude,
|
|
463
|
+
hsSimpleZoomdelta: this.options.hsSimpleZoomdelta,
|
|
464
|
+
hsAdvSoftIterations: this.options.hsAdvSoftIterations,
|
|
465
|
+
hsAdvAmbientIterations: this.options.hsAdvAmbientIterations,
|
|
466
|
+
hsAdvSunRadiusMultiplier: this.options.hsAdvSunRadiusMultiplier,
|
|
467
|
+
hsAdvFinalSoftMultiplier: this.options.hsAdvFinalSoftMultiplier,
|
|
468
|
+
hsAdvFinalAmbientMultiplier: this.options.hsAdvFinalAmbientMultiplier,
|
|
469
|
+
hsAdvBaselayerUrl: this.options.hsAdvBaselayerUrl,
|
|
470
|
+
hsAdvSmoothInput: this.options.hsAdvSmoothInput,
|
|
471
|
+
hsAdvSmoothInputKernel: this.options.hsAdvSmoothInputKernel,
|
|
472
|
+
hsPregenUrl: this.options.hsPregenUrl
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
_tileSizeAsNumber () {
|
|
477
|
+
return this.options.tileSize
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async _fetchTileData (coords, url, tileFormat = this.options.tileFormat) {
|
|
481
|
+
if (tileFormat === 'float32' || tileFormat === 'image') {
|
|
482
|
+
return util.fetchPNGData(this.getTileUrl(coords, url), this.options.nodataValue, this._tileSizeAsNumber())
|
|
483
|
+
} else if (tileFormat === 'dem') {
|
|
484
|
+
const nodataTile = util.createNoDataTile(this.options.nodataValue, this._tileSizeAsNumber())
|
|
485
|
+
const imageData = await util.fetchPNGData(this.getTileUrl(coords, url), this.options.nodataValue, this._tileSizeAsNumber())
|
|
486
|
+
if (util.typedArraysAreEqual(imageData, nodataTile)) {
|
|
487
|
+
return imageData
|
|
488
|
+
} else {
|
|
489
|
+
const rgbaData = this._renderer.renderConvertDem(imageData)
|
|
490
|
+
return rgbaData
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return util.createNoDataTile(this.options.nodataValue, this._tileSizeAsNumber())
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
_copyToTileCanvas (tile, sourceX, sourceY) {
|
|
497
|
+
const tileSize = this._tileSizeAsNumber()
|
|
498
|
+
const tileCanvas2DContext = tile.getContext('2d')
|
|
499
|
+
if (tileCanvas2DContext === null) {
|
|
500
|
+
throw new Error('Tile canvas 2D context is null.')
|
|
501
|
+
}
|
|
502
|
+
// Clear the current contents of the canvas. Otherwise, the new image will be composited with
|
|
503
|
+
// the existing image.
|
|
504
|
+
tileCanvas2DContext.clearRect(0, 0, tileSize, tileSize)
|
|
505
|
+
// Copy the image data from the Renderer's canvas to the tile's canvas.
|
|
506
|
+
tileCanvas2DContext.drawImage(
|
|
507
|
+
this._renderer.canvas,
|
|
508
|
+
sourceX, sourceY, tileSize, tileSize, // source canvas offset (x, y) and size (x, y)
|
|
509
|
+
0, 0, tileSize, tileSize // destination canvas offset (x, y) and size (x, y)
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
getTileUrl (coords, url) {
|
|
514
|
+
return url
|
|
515
|
+
.replace(/{z}/g, String(coords.z))
|
|
516
|
+
.replace(/{x}/g, String(coords.x))
|
|
517
|
+
.replace(/{y}/g, String(coords.y))
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
_getPixelScale (coords) {
|
|
521
|
+
let {bbox: {south, north}, z: zoom} = coords
|
|
522
|
+
let pixelScale = 1
|
|
523
|
+
let lat = (south + north) / 2
|
|
524
|
+
if (this.options.hsAdvPixelScale === 'auto') {
|
|
525
|
+
pixelScale = EARTH_CIRCUMFERENCE * Math.abs(
|
|
526
|
+
Math.cos(lat / 180 * Math.PI
|
|
527
|
+
)) / Math.pow(2, zoom + 8)
|
|
528
|
+
} else if (typeof this.options.hsAdvPixelScale === 'number') {
|
|
529
|
+
pixelScale = this.options.hsAdvPixelScale / (this._tileSizeAsNumber() * (2 ** zoom))
|
|
530
|
+
}
|
|
531
|
+
return pixelScale
|
|
532
|
+
}
|
|
533
533
|
}
|