@mapcatch/util 2.0.3 → 2.0.5-a

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.
Files changed (74) hide show
  1. package/.eslintrc.js +54 -0
  2. package/.husky/pre-commit +1 -0
  3. package/.prettierrc +4 -0
  4. package/.vscode/settings.json +2 -0
  5. package/CHANGELOG.md +5 -1
  6. package/README.md +44 -0
  7. package/debug/app.js +26 -0
  8. package/debug/index.html +55 -0
  9. package/debug/libs/vue.global.js +16159 -0
  10. package/debug/my_icon.png +0 -0
  11. package/docs/Catolog.md +24 -0
  12. package/docs/Constant.md +92 -0
  13. package/docs/Event.md +90 -0
  14. package/docs/Util.md +345 -0
  15. package/package.json +2 -2
  16. package/src/constants/crs.js +42098 -42098
  17. package/src/constants/default_layers.js +102 -11
  18. package/src/constants/index.js +1 -0
  19. package/src/constants/layer_groups_multispectral.js +34 -0
  20. package/src/constants/layer_icons.js +1 -0
  21. package/src/gl-operations/constants.js +9 -9
  22. package/src/gl-operations/default_options.js +97 -97
  23. package/src/gl-operations/index.js +532 -520
  24. package/src/gl-operations/reglCommands/contours.js +27 -27
  25. package/src/gl-operations/reglCommands/default.js +45 -43
  26. package/src/gl-operations/reglCommands/hillshading.js +340 -332
  27. package/src/gl-operations/reglCommands/index.js +6 -6
  28. package/src/gl-operations/reglCommands/multiLayers.js +303 -301
  29. package/src/gl-operations/reglCommands/transitions.js +111 -109
  30. package/src/gl-operations/reglCommands/util.js +71 -71
  31. package/src/gl-operations/renderer.js +209 -192
  32. package/src/gl-operations/shaders/fragment/convertDem.js +25 -25
  33. package/src/gl-operations/shaders/fragment/convolutionSmooth.js +54 -54
  34. package/src/gl-operations/shaders/fragment/diffCalc.js +33 -33
  35. package/src/gl-operations/shaders/fragment/drawResult.js +46 -41
  36. package/src/gl-operations/shaders/fragment/hillshading/hsAdvAmbientShadows.js +78 -78
  37. package/src/gl-operations/shaders/fragment/hillshading/hsAdvDirect.js +59 -54
  38. package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalBaselayer.js +30 -30
  39. package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalColorscale.js +60 -55
  40. package/src/gl-operations/shaders/fragment/hillshading/hsAdvMergeAndScaleTiles.js +26 -26
  41. package/src/gl-operations/shaders/fragment/hillshading/hsAdvNormals.js +25 -25
  42. package/src/gl-operations/shaders/fragment/hillshading/hsAdvSmooth.js +53 -53
  43. package/src/gl-operations/shaders/fragment/hillshading/hsAdvSoftShadows.js +80 -80
  44. package/src/gl-operations/shaders/fragment/hillshading/hsPregen.js +54 -49
  45. package/src/gl-operations/shaders/fragment/interpolateColor.js +65 -62
  46. package/src/gl-operations/shaders/fragment/interpolateColorOnly.js +49 -46
  47. package/src/gl-operations/shaders/fragment/interpolateValue.js +136 -123
  48. package/src/gl-operations/shaders/fragment/multiAnalyze1Calc.js +35 -35
  49. package/src/gl-operations/shaders/fragment/multiAnalyze2Calc.js +45 -45
  50. package/src/gl-operations/shaders/fragment/multiAnalyze3Calc.js +53 -53
  51. package/src/gl-operations/shaders/fragment/multiAnalyze4Calc.js +61 -61
  52. package/src/gl-operations/shaders/fragment/multiAnalyze5Calc.js +69 -69
  53. package/src/gl-operations/shaders/fragment/multiAnalyze6Calc.js +77 -77
  54. package/src/gl-operations/shaders/fragment/single.js +93 -88
  55. package/src/gl-operations/shaders/transform.js +21 -21
  56. package/src/gl-operations/shaders/util/computeColor.glsl +85 -84
  57. package/src/gl-operations/shaders/util/getTexelValue.glsl +10 -10
  58. package/src/gl-operations/shaders/util/isCloseEnough.glsl +9 -9
  59. package/src/gl-operations/shaders/util/rgbaToFloat.glsl +17 -17
  60. package/src/gl-operations/shaders/vertex/double.js +16 -16
  61. package/src/gl-operations/shaders/vertex/multi3.js +19 -19
  62. package/src/gl-operations/shaders/vertex/multi4.js +22 -22
  63. package/src/gl-operations/shaders/vertex/multi5.js +25 -25
  64. package/src/gl-operations/shaders/vertex/multi6.js +28 -28
  65. package/src/gl-operations/shaders/vertex/single.js +13 -13
  66. package/src/gl-operations/shaders/vertex/singleNotTransformed.js +11 -11
  67. package/src/gl-operations/texture_manager.js +141 -141
  68. package/src/gl-operations/util.js +336 -336
  69. package/src/measure/index.js +14 -8
  70. package/src/transform.js +3 -0
  71. package/src/util.js +14 -6
  72. package/vite.config.js +58 -0
  73. package/dist/catchUtil.min.esm.js +0 -112833
  74. package/dist/catchUtil.min.js +0 -2922
@@ -1,336 +1,336 @@
1
- import { memoize } from 'lodash'
2
- import { decode, toRGBA8 } from 'upng-js'
3
-
4
- import {
5
- RGB_REGEX,
6
- HEX_REGEX
7
- } from './constants'
8
-
9
- export function machineIsLittleEndian () {
10
- const uint8Array = new Uint8Array([0xAA, 0xBB])
11
- const uint16array = new Uint16Array(uint8Array.buffer)
12
- return uint16array[0] === 0xBBAA
13
- }
14
-
15
- /**
16
- * Cribbed from Python's built-in `range` function.
17
- */
18
- export function range (...args) {
19
- if (args.length === 1) {
20
- const [until] = args
21
- return new Array(until).fill(undefined).map((_, i) => i)
22
- } else {
23
- const [from, until, step = 1] = args
24
- if (step === 0) {
25
- throw new Error('Argument step must be nonzero.')
26
- }
27
- const output = []
28
- for (let val = from; (step > 0) ? val < until : val > until; val += step) {
29
- output.push(val)
30
- }
31
- return output
32
- }
33
- }
34
-
35
- /**
36
- * Fetch a png and decode data. If png does not exist return an array with nodataValue.
37
- */
38
- export async function fetchPNGData (url, nodataValue, tileDimension) {
39
- return new Promise((resolve, reject) => {
40
- const xhr = new XMLHttpRequest()
41
- xhr.open('GET', url, true)
42
- xhr.responseType = 'arraybuffer'
43
- xhr.addEventListener('load', () => {
44
- resolve(xhr.response)
45
- })
46
- xhr.addEventListener('error', reject)
47
- xhr.send(null)
48
- }).then((data) => {
49
- const img = decode(data)
50
- const rgba = toRGBA8(img)[0]
51
- return new Uint8Array(rgba)
52
- }).catch(() => createNoDataTile(nodataValue, tileDimension))
53
- }
54
-
55
- /**
56
- * Check if two TypedArrays are equal
57
- */
58
- export function typedArraysAreEqual (a, b) {
59
- if (a.byteLength !== b.byteLength) return false
60
- return a.every((val, i) => val === b[i])
61
- }
62
-
63
- /**
64
- * The matrix output by this function transforms coordinates in pixel space within the drawing
65
- * buffer (with upper left corner (0, 0) and lower right corner (buffer width, buffer height))
66
- * to WebGL "clipspace", with upper left corner (-1, 1) and lower right corner (1, -1).
67
- */
68
- export function getTransformMatrix (drawingBufferWidth, drawingBufferHeight) {
69
- // To scale horizontally, divide by width (in pixels) and multiply by 2, because width is 2 in clipspace.
70
- const sx = 2 / drawingBufferWidth
71
- // To scale vertically, divide by height (in pixels) and multiply by -2, because height is 2 in clipspace,
72
- // and the direction is flipped (positive is up, negative is down).
73
- const sy = -2 / drawingBufferHeight
74
- // We translate by -1 horizontally (so the range 0 to 2 maps to the range -1 to 1).
75
- const tx = -1
76
- // We translate by 1 horizontally (so the range -2 to 0 maps to the range -1 to 1).
77
- const ty = 1
78
- // Matrix must be in column-major order for WebGL.
79
- return [
80
- sx, 0, 0, 0,
81
- 0, sy, 0, 0,
82
- 0, 0, 1, 0,
83
- tx, ty, 0, 1
84
- ]
85
- }
86
-
87
- /**
88
- * From a TextureBounds object, this function generates the four vertices WebGL needs to draw the
89
- * corresponding rectangle (as two conjoined triangles generated with the triangle strip primitive).
90
- */
91
- export function getTexCoordVerticesTriangleStripQuad (textureBounds) {
92
- const [{ x: left, y: top }, { x: right, y: bottom }] = textureBounds
93
- return [
94
- [left, top ],
95
- [right, top ],
96
- [left, bottom],
97
- [right, bottom]
98
- ]
99
- }
100
-
101
- /**
102
- * From a TextureBounds object, this function generates the six vertices WebGL needs to draw the
103
- * corresponding rectangle (as two triangles).
104
- */
105
- export function getTexCoordVerticesTriangleQuad (textureBounds) {
106
- const [{ x: left, y: top }, { x: right, y: bottom }] = textureBounds
107
- return [
108
- [left, top ],
109
- [right, top ],
110
- [left, bottom],
111
- [right, bottom],
112
- [right, top ],
113
- [left, bottom]
114
- ]
115
- }
116
-
117
- /**
118
- * Produces a Promise that resolves when the desired `duration` has expired.
119
- */
120
- export function Timer (duration) {
121
- return new Promise((resolve) => setTimeout(resolve, duration))
122
- }
123
-
124
- /**
125
- * Useful for sorting TileCoordinates objects.
126
- */
127
- export function compareTileCoordinates (a, b) {
128
- const z = a.z - b.z
129
- const x = a.x - b.x
130
- const y = a.y - b.y
131
- if (z !== 0) {
132
- // First compare z values.
133
- return z
134
- } else if (x !== 0) {
135
- // If z values are the same, compare x values.
136
- return x
137
- } else {
138
- // If x values are the same, compare y values.
139
- return y
140
- }
141
- }
142
-
143
- /**
144
- * Determines whether two arrays of TileCoordinates are the same.
145
- */
146
- export function sameTiles (a, b) {
147
- return (
148
- // arrays are of the same length
149
- a.length === b.length
150
- // and corresponding elements have the same tile coordinates
151
- && a.every((tileA, index) => compareTileCoordinates(tileA, b[index]) === 0)
152
- )
153
- }
154
-
155
- export const createNoDataTile = memoize((nodataValue, tileDimension = 256) => {
156
- // Create a float 32 array.
157
- const float32Tile = new Float32Array(tileDimension * tileDimension)
158
- // Fill the tile array with the no data value
159
- float32Tile.fill(nodataValue)
160
- // return the no data tile.
161
- return new Uint8Array(float32Tile.buffer)
162
- })
163
-
164
- /**
165
- * Force TypeScript to interpret value `val` as type `T`.
166
- */
167
- export function staticCast (val) {
168
- return val
169
- }
170
-
171
- /**
172
- * Add one or more macro definitions to a GLSL source string.
173
- */
174
- export function defineMacros (src, macros) {
175
- const defs = Object.keys(macros).map((key) => `#define ${key} ${macros[key]}\n`).join('')
176
- return `${defs}\n${src}`
177
- }
178
-
179
- /**
180
- * Ping-pong technique. Render to a destination framebuffer,
181
- * then use it as a source texture in our next iteration.
182
- * Then swap them and continue. Used for advanced hillshading.
183
- */
184
- export function PingPong (regl, opts) {
185
- const fbos = [regl.framebuffer(opts), regl.framebuffer(opts)]
186
-
187
- let index = 0
188
-
189
- function ping () {
190
- return fbos[index]
191
- }
192
-
193
- function pong () {
194
- return fbos[1 - index]
195
- }
196
-
197
- function swap () {
198
- index = 1 - index
199
- }
200
-
201
- function destroy () {
202
- fbos[0].destroy()
203
- fbos[1].destroy()
204
- }
205
-
206
- return {
207
- ping,
208
- pong,
209
- swap,
210
- destroy
211
- }
212
- }
213
-
214
- /**
215
- * hexToRGB converts a color from hex format to rgba.
216
- * const [r, g, b, a] = hexToRGB("#ffeeaaff")
217
- */
218
- export const hexToRGB = (hex) => {
219
- const hasAlpha = hex.length === 9
220
- const start = hasAlpha ? 24 : 16
221
- const bigint = parseInt(hex.slice(1), 16)
222
- const r = (bigint >> start) & 255
223
- const g = (bigint >> (start - 8)) & 255
224
- const b = (bigint >> (start - 16)) & 255
225
- const a = hasAlpha ? (bigint >> (start - 24)) & 255 : 255
226
- return [r, g, b, a]
227
- }
228
-
229
- /**
230
- * Parses a color string of the form 'rgb({rVal}, {gVal}, {bVal})' and converts the resulting values
231
- * to an array with ints 0 - 255.
232
- */
233
- export function colorStringToInts (colorstring) {
234
- if (colorstring === 'transparent') {
235
- return [0, 0, 0, 0]
236
- }
237
- const rgbmatch = colorstring.match(RGB_REGEX)
238
- const hexmatch = colorstring.match(HEX_REGEX)
239
- if (rgbmatch !== null) {
240
- const [, r, g, b] = rgbmatch
241
- return [+r, +g, +b, 255]
242
- } else if (hexmatch !== null) {
243
- return hexToRGB(colorstring)
244
- } else {
245
- throw new Error(`'${colorstring}' is not a valid RGB or hex color expression.`)
246
- }
247
- }
248
-
249
- /**
250
- * colormapToFlatArray takes the input colormap and returns a flat array to be
251
- * used as input to a texture. The first row in the array contains the colors.
252
- * The second row contains the encoded offset values.
253
- */
254
- export const colormapToFlatArray = (colormap) => {
255
- const offsets = []
256
- let colors = []
257
- for (let i = 0; i < colormap.length; i++) {
258
- offsets.push(colormap[i].offset)
259
- const colorsnew = colorStringToInts(colormap[i].color)
260
- colors = colors.concat(colorsnew)
261
- }
262
-
263
- const floatOffsets = new Float32Array(offsets)
264
- const uintOffsets = new Uint8Array(floatOffsets.buffer)
265
- const normalOffsets = Array.from(uintOffsets)
266
- const colormapArray = colors.concat(normalOffsets)
267
-
268
- return colormapArray
269
- }
270
-
271
- /**
272
- * Creates a texture with colors on first row and offsets on second row
273
- */
274
- export function createColormapTexture (colormapInput, regl) {
275
- const colormapFlatArray = colormapToFlatArray(colormapInput)
276
- let colormapTexture
277
- if (colormapInput.length === 0) {
278
- // empty texture
279
- colormapTexture = regl.texture({
280
- shape: [2, 2]
281
- })
282
- } else {
283
- colormapTexture = regl.texture({
284
- width: colormapInput.length,
285
- height: 2,
286
- data: colormapFlatArray
287
- })
288
- }
289
-
290
- return colormapTexture
291
- }
292
-
293
- /**
294
- * Fetch 8 adjacent tiles, if not already existing in tileManager.
295
- * Return array with texture coord vertices for all tiles.
296
- */
297
- export async function getAdjacentTilesTexCoords (gloperations, textureManager, coords, url) {
298
- // Get existing tiles in TextureManager
299
- const textureContents = textureManager.contents
300
-
301
- // use 3x3 tiles for adv. hillshading
302
- // TODO: add as plugin option?
303
- const adjacentTiles = 3
304
- let textureCoords = []
305
-
306
- for (let i = 0; i < adjacentTiles; i++) {
307
- const _x = coords['x'] + (i - 1)
308
- for (let j = 0; j < adjacentTiles; j++) {
309
- const _y = coords['y'] + (j - 1)
310
- const coordsAdjacent = {
311
- x: _x,
312
- y: _y,
313
- z: coords['z']
314
- }
315
-
316
- // Fetch data for adjacent tile if not already existing in TextureManager
317
- const hashKey = textureManager.hashTileCoordinates(coordsAdjacent)
318
- if (!textureContents.has(hashKey)) {
319
- // Retrieve and add data to TextureManager
320
- const pixelDataAdjacent = await gloperations._fetchTileData(coordsAdjacent, url)
321
- const textureBounds = gloperations._renderer.textureManager.addTile(coordsAdjacent, pixelDataAdjacent)
322
- textureCoords = textureCoords.concat(getTexCoordVerticesTriangleQuad(textureBounds))
323
- } else {
324
- const textureBounds = gloperations._renderer.textureManager.getTextureCoordinates(coordsAdjacent)
325
- textureCoords = textureCoords.concat(getTexCoordVerticesTriangleQuad(textureBounds))
326
- }
327
- }
328
- }
329
- return textureCoords
330
- }
331
-
332
- export function delay (ms) {
333
- return new Promise(function (resolve) {
334
- setTimeout(resolve, ms)
335
- })
336
- }
1
+ import { memoize } from 'lodash'
2
+ import { decode, toRGBA8 } from 'upng-js'
3
+
4
+ import {
5
+ RGB_REGEX,
6
+ HEX_REGEX
7
+ } from './constants'
8
+
9
+ export function machineIsLittleEndian () {
10
+ const uint8Array = new Uint8Array([0xAA, 0xBB])
11
+ const uint16array = new Uint16Array(uint8Array.buffer)
12
+ return uint16array[0] === 0xBBAA
13
+ }
14
+
15
+ /**
16
+ * Cribbed from Python's built-in `range` function.
17
+ */
18
+ export function range (...args) {
19
+ if (args.length === 1) {
20
+ const [until] = args
21
+ return new Array(until).fill(undefined).map((_, i) => i)
22
+ } else {
23
+ const [from, until, step = 1] = args
24
+ if (step === 0) {
25
+ throw new Error('Argument step must be nonzero.')
26
+ }
27
+ const output = []
28
+ for (let val = from; (step > 0) ? val < until : val > until; val += step) {
29
+ output.push(val)
30
+ }
31
+ return output
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Fetch a png and decode data. If png does not exist return an array with nodataValue.
37
+ */
38
+ export async function fetchPNGData (url, nodataValue, tileDimension) {
39
+ return new Promise((resolve, reject) => {
40
+ const xhr = new XMLHttpRequest()
41
+ xhr.open('GET', url, true)
42
+ xhr.responseType = 'arraybuffer'
43
+ xhr.addEventListener('load', () => {
44
+ resolve(xhr.response)
45
+ })
46
+ xhr.addEventListener('error', reject)
47
+ xhr.send(null)
48
+ }).then((data) => {
49
+ const img = decode(data)
50
+ const rgba = toRGBA8(img)[0]
51
+ return new Uint8Array(rgba)
52
+ }).catch(() => createNoDataTile(nodataValue, tileDimension))
53
+ }
54
+
55
+ /**
56
+ * Check if two TypedArrays are equal
57
+ */
58
+ export function typedArraysAreEqual (a, b) {
59
+ if (a.byteLength !== b.byteLength) return false
60
+ return a.every((val, i) => val === b[i])
61
+ }
62
+
63
+ /**
64
+ * The matrix output by this function transforms coordinates in pixel space within the drawing
65
+ * buffer (with upper left corner (0, 0) and lower right corner (buffer width, buffer height))
66
+ * to WebGL "clipspace", with upper left corner (-1, 1) and lower right corner (1, -1).
67
+ */
68
+ export function getTransformMatrix (drawingBufferWidth, drawingBufferHeight) {
69
+ // To scale horizontally, divide by width (in pixels) and multiply by 2, because width is 2 in clipspace.
70
+ const sx = 2 / drawingBufferWidth
71
+ // To scale vertically, divide by height (in pixels) and multiply by -2, because height is 2 in clipspace,
72
+ // and the direction is flipped (positive is up, negative is down).
73
+ const sy = -2 / drawingBufferHeight
74
+ // We translate by -1 horizontally (so the range 0 to 2 maps to the range -1 to 1).
75
+ const tx = -1
76
+ // We translate by 1 horizontally (so the range -2 to 0 maps to the range -1 to 1).
77
+ const ty = 1
78
+ // Matrix must be in column-major order for WebGL.
79
+ return [
80
+ sx, 0, 0, 0,
81
+ 0, sy, 0, 0,
82
+ 0, 0, 1, 0,
83
+ tx, ty, 0, 1
84
+ ]
85
+ }
86
+
87
+ /**
88
+ * From a TextureBounds object, this function generates the four vertices WebGL needs to draw the
89
+ * corresponding rectangle (as two conjoined triangles generated with the triangle strip primitive).
90
+ */
91
+ export function getTexCoordVerticesTriangleStripQuad (textureBounds) {
92
+ const [{ x: left, y: top }, { x: right, y: bottom }] = textureBounds
93
+ return [
94
+ [left, top ],
95
+ [right, top ],
96
+ [left, bottom],
97
+ [right, bottom]
98
+ ]
99
+ }
100
+
101
+ /**
102
+ * From a TextureBounds object, this function generates the six vertices WebGL needs to draw the
103
+ * corresponding rectangle (as two triangles).
104
+ */
105
+ export function getTexCoordVerticesTriangleQuad (textureBounds) {
106
+ const [{ x: left, y: top }, { x: right, y: bottom }] = textureBounds
107
+ return [
108
+ [left, top ],
109
+ [right, top ],
110
+ [left, bottom],
111
+ [right, bottom],
112
+ [right, top ],
113
+ [left, bottom]
114
+ ]
115
+ }
116
+
117
+ /**
118
+ * Produces a Promise that resolves when the desired `duration` has expired.
119
+ */
120
+ export function Timer (duration) {
121
+ return new Promise((resolve) => setTimeout(resolve, duration))
122
+ }
123
+
124
+ /**
125
+ * Useful for sorting TileCoordinates objects.
126
+ */
127
+ export function compareTileCoordinates (a, b) {
128
+ const z = a.z - b.z
129
+ const x = a.x - b.x
130
+ const y = a.y - b.y
131
+ if (z !== 0) {
132
+ // First compare z values.
133
+ return z
134
+ } else if (x !== 0) {
135
+ // If z values are the same, compare x values.
136
+ return x
137
+ } else {
138
+ // If x values are the same, compare y values.
139
+ return y
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Determines whether two arrays of TileCoordinates are the same.
145
+ */
146
+ export function sameTiles (a, b) {
147
+ return (
148
+ // arrays are of the same length
149
+ a.length === b.length
150
+ // and corresponding elements have the same tile coordinates
151
+ && a.every((tileA, index) => compareTileCoordinates(tileA, b[index]) === 0)
152
+ )
153
+ }
154
+
155
+ export const createNoDataTile = memoize((nodataValue, tileDimension = 256) => {
156
+ // Create a float 32 array.
157
+ const float32Tile = new Float32Array(tileDimension * tileDimension)
158
+ // Fill the tile array with the no data value
159
+ float32Tile.fill(nodataValue)
160
+ // return the no data tile.
161
+ return new Uint8Array(float32Tile.buffer)
162
+ })
163
+
164
+ /**
165
+ * Force TypeScript to interpret value `val` as type `T`.
166
+ */
167
+ export function staticCast (val) {
168
+ return val
169
+ }
170
+
171
+ /**
172
+ * Add one or more macro definitions to a GLSL source string.
173
+ */
174
+ export function defineMacros (src, macros) {
175
+ const defs = Object.keys(macros).map((key) => `#define ${key} ${macros[key]}\n`).join('')
176
+ return `${defs}\n${src}`
177
+ }
178
+
179
+ /**
180
+ * Ping-pong technique. Render to a destination framebuffer,
181
+ * then use it as a source texture in our next iteration.
182
+ * Then swap them and continue. Used for advanced hillshading.
183
+ */
184
+ export function PingPong (regl, opts) {
185
+ const fbos = [regl.framebuffer(opts), regl.framebuffer(opts)]
186
+
187
+ let index = 0
188
+
189
+ function ping () {
190
+ return fbos[index]
191
+ }
192
+
193
+ function pong () {
194
+ return fbos[1 - index]
195
+ }
196
+
197
+ function swap () {
198
+ index = 1 - index
199
+ }
200
+
201
+ function destroy () {
202
+ fbos[0].destroy()
203
+ fbos[1].destroy()
204
+ }
205
+
206
+ return {
207
+ ping,
208
+ pong,
209
+ swap,
210
+ destroy
211
+ }
212
+ }
213
+
214
+ /**
215
+ * hexToRGB converts a color from hex format to rgba.
216
+ * const [r, g, b, a] = hexToRGB("#ffeeaaff")
217
+ */
218
+ export const hexToRGB = (hex) => {
219
+ const hasAlpha = hex.length === 9
220
+ const start = hasAlpha ? 24 : 16
221
+ const bigint = parseInt(hex.slice(1), 16)
222
+ const r = (bigint >> start) & 255
223
+ const g = (bigint >> (start - 8)) & 255
224
+ const b = (bigint >> (start - 16)) & 255
225
+ const a = hasAlpha ? (bigint >> (start - 24)) & 255 : 255
226
+ return [r, g, b, a]
227
+ }
228
+
229
+ /**
230
+ * Parses a color string of the form 'rgb({rVal}, {gVal}, {bVal})' and converts the resulting values
231
+ * to an array with ints 0 - 255.
232
+ */
233
+ export function colorStringToInts (colorstring) {
234
+ if (colorstring === 'transparent') {
235
+ return [0, 0, 0, 0]
236
+ }
237
+ const rgbmatch = colorstring.match(RGB_REGEX)
238
+ const hexmatch = colorstring.match(HEX_REGEX)
239
+ if (rgbmatch !== null) {
240
+ const [, r, g, b] = rgbmatch
241
+ return [+r, +g, +b, 255]
242
+ } else if (hexmatch !== null) {
243
+ return hexToRGB(colorstring)
244
+ } else {
245
+ throw new Error(`'${colorstring}' is not a valid RGB or hex color expression.`)
246
+ }
247
+ }
248
+
249
+ /**
250
+ * colormapToFlatArray takes the input colormap and returns a flat array to be
251
+ * used as input to a texture. The first row in the array contains the colors.
252
+ * The second row contains the encoded offset values.
253
+ */
254
+ export const colormapToFlatArray = (colormap) => {
255
+ const offsets = []
256
+ let colors = []
257
+ for (let i = 0; i < colormap.length; i++) {
258
+ offsets.push(colormap[i].offset)
259
+ const colorsnew = colorStringToInts(colormap[i].color)
260
+ colors = colors.concat(colorsnew)
261
+ }
262
+
263
+ const floatOffsets = new Float32Array(offsets)
264
+ const uintOffsets = new Uint8Array(floatOffsets.buffer)
265
+ const normalOffsets = Array.from(uintOffsets)
266
+ const colormapArray = colors.concat(normalOffsets)
267
+
268
+ return colormapArray
269
+ }
270
+
271
+ /**
272
+ * Creates a texture with colors on first row and offsets on second row
273
+ */
274
+ export function createColormapTexture (colormapInput, regl) {
275
+ const colormapFlatArray = colormapToFlatArray(colormapInput)
276
+ let colormapTexture
277
+ if (colormapInput.length === 0) {
278
+ // empty texture
279
+ colormapTexture = regl.texture({
280
+ shape: [2, 2]
281
+ })
282
+ } else {
283
+ colormapTexture = regl.texture({
284
+ width: colormapInput.length,
285
+ height: 2,
286
+ data: colormapFlatArray
287
+ })
288
+ }
289
+
290
+ return colormapTexture
291
+ }
292
+
293
+ /**
294
+ * Fetch 8 adjacent tiles, if not already existing in tileManager.
295
+ * Return array with texture coord vertices for all tiles.
296
+ */
297
+ export async function getAdjacentTilesTexCoords (gloperations, textureManager, coords, url) {
298
+ // Get existing tiles in TextureManager
299
+ const textureContents = textureManager.contents
300
+
301
+ // use 3x3 tiles for adv. hillshading
302
+ // TODO: add as plugin option?
303
+ const adjacentTiles = 3
304
+ let textureCoords = []
305
+
306
+ for (let i = 0; i < adjacentTiles; i++) {
307
+ const _x = coords['x'] + (i - 1)
308
+ for (let j = 0; j < adjacentTiles; j++) {
309
+ const _y = coords['y'] + (j - 1)
310
+ const coordsAdjacent = {
311
+ x: _x,
312
+ y: _y,
313
+ z: coords['z']
314
+ }
315
+
316
+ // Fetch data for adjacent tile if not already existing in TextureManager
317
+ const hashKey = textureManager.hashTileCoordinates(coordsAdjacent)
318
+ if (!textureContents.has(hashKey)) {
319
+ // Retrieve and add data to TextureManager
320
+ const pixelDataAdjacent = await gloperations._fetchTileData(coordsAdjacent, url)
321
+ const textureBounds = gloperations._renderer.textureManager.addTile(coordsAdjacent, pixelDataAdjacent)
322
+ textureCoords = textureCoords.concat(getTexCoordVerticesTriangleQuad(textureBounds))
323
+ } else {
324
+ const textureBounds = gloperations._renderer.textureManager.getTextureCoordinates(coordsAdjacent)
325
+ textureCoords = textureCoords.concat(getTexCoordVerticesTriangleQuad(textureBounds))
326
+ }
327
+ }
328
+ }
329
+ return textureCoords
330
+ }
331
+
332
+ export function delay (ms) {
333
+ return new Promise(function (resolve) {
334
+ setTimeout(resolve, ms)
335
+ })
336
+ }