@mapcatch/util 1.0.0
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/.eslintrc.js +53 -0
- package/.prettierrc +4 -0
- package/CHANGELOG.md +0 -0
- package/README.md +44 -0
- package/docs/Catolog.md +24 -0
- package/docs/Util.md +170 -0
- package/package.json +30 -0
- package/src/constants/cameras.js +5 -0
- package/src/constants/index.js +1 -0
- package/src/event.js +205 -0
- package/src/exif/exif.js +37 -0
- package/src/exif/gps_tags.js +33 -0
- package/src/exif/ifd1_tags.js +22 -0
- package/src/exif/index.js +16 -0
- package/src/exif/iptc_field_map.js +12 -0
- package/src/exif/parse_image.js +446 -0
- package/src/exif/string_values.js +137 -0
- package/src/exif/tags.js +75 -0
- package/src/exif/tiff_tags.js +35 -0
- package/src/exif/util.js +108 -0
- package/src/gl-operations/constants.js +11 -0
- package/src/gl-operations/default_options.js +98 -0
- package/src/gl-operations/index.js +594 -0
- package/src/gl-operations/reglCommands/contours.js +27 -0
- package/src/gl-operations/reglCommands/default.js +44 -0
- package/src/gl-operations/reglCommands/hillshading.js +332 -0
- package/src/gl-operations/reglCommands/index.js +6 -0
- package/src/gl-operations/reglCommands/multiLayers.js +301 -0
- package/src/gl-operations/reglCommands/transitions.js +109 -0
- package/src/gl-operations/reglCommands/util.js +71 -0
- package/src/gl-operations/renderer.js +193 -0
- package/src/gl-operations/shaders/fragment/convertDem.js +26 -0
- package/src/gl-operations/shaders/fragment/convolutionSmooth.js +55 -0
- package/src/gl-operations/shaders/fragment/diffCalc.js +34 -0
- package/src/gl-operations/shaders/fragment/drawResult.js +42 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvAmbientShadows.js +79 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvDirect.js +55 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalBaselayer.js +31 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvFinalColorscale.js +56 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvMergeAndScaleTiles.js +27 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvNormals.js +26 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvSmooth.js +54 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsAdvSoftShadows.js +81 -0
- package/src/gl-operations/shaders/fragment/hillshading/hsPregen.js +50 -0
- package/src/gl-operations/shaders/fragment/interpolateColor.js +63 -0
- package/src/gl-operations/shaders/fragment/interpolateColorOnly.js +47 -0
- package/src/gl-operations/shaders/fragment/interpolateValue.js +124 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze1Calc.js +36 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze2Calc.js +46 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze3Calc.js +54 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze4Calc.js +62 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze5Calc.js +70 -0
- package/src/gl-operations/shaders/fragment/multiAnalyze6Calc.js +78 -0
- package/src/gl-operations/shaders/fragment/single.js +88 -0
- package/src/gl-operations/shaders/transform.js +22 -0
- package/src/gl-operations/shaders/util/computeColor.glsl +84 -0
- package/src/gl-operations/shaders/util/getTexelValue.glsl +10 -0
- package/src/gl-operations/shaders/util/isCloseEnough.glsl +9 -0
- package/src/gl-operations/shaders/util/rgbaToFloat.glsl +18 -0
- package/src/gl-operations/shaders/vertex/double.js +17 -0
- package/src/gl-operations/shaders/vertex/multi3.js +20 -0
- package/src/gl-operations/shaders/vertex/multi4.js +23 -0
- package/src/gl-operations/shaders/vertex/multi5.js +26 -0
- package/src/gl-operations/shaders/vertex/multi6.js +29 -0
- package/src/gl-operations/shaders/vertex/single.js +13 -0
- package/src/gl-operations/shaders/vertex/singleNotTransformed.js +12 -0
- package/src/gl-operations/texture_manager.js +141 -0
- package/src/gl-operations/util.js +336 -0
- package/src/index.js +10 -0
- package/src/util.js +332 -0
- package/vite.config.js +52 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flatMap,
|
|
3
|
+
isEmpty,
|
|
4
|
+
} from 'lodash';
|
|
5
|
+
import * as util from './util';
|
|
6
|
+
|
|
7
|
+
export default class TextureManager {
|
|
8
|
+
constructor(
|
|
9
|
+
regl,
|
|
10
|
+
tileSize = 256,
|
|
11
|
+
maxTextureDimension,
|
|
12
|
+
flipY = false,
|
|
13
|
+
textureFormat = 'rgba',
|
|
14
|
+
textureType = 'uint8',
|
|
15
|
+
) {
|
|
16
|
+
const tilesAcross = Math.floor(maxTextureDimension / tileSize);
|
|
17
|
+
const pixelsAcross = tilesAcross * tileSize;
|
|
18
|
+
const tileCapacity = tilesAcross * tilesAcross;
|
|
19
|
+
|
|
20
|
+
const texture = regl.texture({
|
|
21
|
+
width: pixelsAcross,
|
|
22
|
+
height: pixelsAcross,
|
|
23
|
+
flipY: flipY,
|
|
24
|
+
format: textureFormat,
|
|
25
|
+
type: textureType,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const contents = new Map();
|
|
29
|
+
const available = this.allTextureCoordinates(tilesAcross, tileSize);
|
|
30
|
+
|
|
31
|
+
Object.assign(this, {
|
|
32
|
+
tileSize,
|
|
33
|
+
tilesAcross,
|
|
34
|
+
pixelsAcross,
|
|
35
|
+
tileCapacity,
|
|
36
|
+
texture,
|
|
37
|
+
contents,
|
|
38
|
+
available,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addTile(
|
|
43
|
+
tileCoordinates,
|
|
44
|
+
data,
|
|
45
|
+
) {
|
|
46
|
+
const {
|
|
47
|
+
available,
|
|
48
|
+
contents,
|
|
49
|
+
texture,
|
|
50
|
+
tileSize,
|
|
51
|
+
} = this;
|
|
52
|
+
|
|
53
|
+
const hashKey = this.hashTileCoordinates(tileCoordinates);
|
|
54
|
+
if (contents.has(hashKey)) {
|
|
55
|
+
const textureCoordinates = contents.get(hashKey);
|
|
56
|
+
// We use a least-recently-used eviction policy for the tile cache. Map iterators are
|
|
57
|
+
// convenient for this, because they return entries in insertion order. But for this to work
|
|
58
|
+
// as expected, every time we access a tile, we need to reinsert it so that it moves to the
|
|
59
|
+
// end of that insertion-order list.
|
|
60
|
+
contents.delete(hashKey);
|
|
61
|
+
contents.set(hashKey, textureCoordinates);
|
|
62
|
+
return this.formatOutputTextureCoordinates(textureCoordinates);
|
|
63
|
+
}
|
|
64
|
+
if (isEmpty(available)) {
|
|
65
|
+
// Get the first key inserted. Map.prototype.keys() produces an iterable iterator over the keys
|
|
66
|
+
// in the order of insertion, so we can just use the iterator's first value.
|
|
67
|
+
const firstInsertedKey = contents.keys().next().value;
|
|
68
|
+
this.removeByHashKey(firstInsertedKey);
|
|
69
|
+
}
|
|
70
|
+
// remove from list of available positions
|
|
71
|
+
const textureCoordinates = available.pop();
|
|
72
|
+
// store mapping of tile to texture coordinates
|
|
73
|
+
contents.set(hashKey, textureCoordinates);
|
|
74
|
+
|
|
75
|
+
const { x: textureX, y: textureY } = textureCoordinates;
|
|
76
|
+
texture.subimage({
|
|
77
|
+
data,
|
|
78
|
+
width: tileSize,
|
|
79
|
+
height: tileSize,
|
|
80
|
+
}, textureX, textureY);
|
|
81
|
+
|
|
82
|
+
return this.formatOutputTextureCoordinates(textureCoordinates);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
removeTile(tileCoordinates) {
|
|
86
|
+
this.removeByHashKey(this.hashTileCoordinates(tileCoordinates));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
clearTiles() {
|
|
90
|
+
for (const hashKey of Array.from(this.contents.keys())) {
|
|
91
|
+
this.removeByHashKey(hashKey);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
destroy() {
|
|
96
|
+
this.texture.destroy();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
removeByHashKey(hashKey) {
|
|
100
|
+
// This method only removes the key. The pixel data remains in the texture.
|
|
101
|
+
if (this.contents.has(hashKey)) {
|
|
102
|
+
const textureCoordinates = this.contents.get(hashKey);
|
|
103
|
+
this.contents.delete(hashKey);
|
|
104
|
+
this.available.push(textureCoordinates);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
formatOutputTextureCoordinates(textureCoordinates) {
|
|
109
|
+
const { x, y } = textureCoordinates;
|
|
110
|
+
const { pixelsAcross, tileSize } = this;
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
x: x / pixelsAcross,
|
|
114
|
+
y: y / pixelsAcross,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
x: (x + tileSize) / pixelsAcross,
|
|
118
|
+
y: (y + tileSize) / pixelsAcross,
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
hashTileCoordinates({ x, y, z }) {
|
|
124
|
+
return `${x}:${y}:${z}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getTextureCoordinates(tileCoordinates) {
|
|
128
|
+
const hashKey = this.hashTileCoordinates(tileCoordinates);
|
|
129
|
+
const textureCoordinates = this.contents.get(hashKey);
|
|
130
|
+
return this.formatOutputTextureCoordinates(textureCoordinates);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
allTextureCoordinates(tilesAcross, tileSize) {
|
|
134
|
+
return flatMap(util.range(tilesAcross), x =>
|
|
135
|
+
util.range(tilesAcross).map(y => ({
|
|
136
|
+
x: x * tileSize,
|
|
137
|
+
y: y * tileSize,
|
|
138
|
+
})),
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 解析jpg文件,获取exif信息
|
|
2
|
+
export {getPhotoTags} from './exif'
|
|
3
|
+
// 常用公共函数和工具函数
|
|
4
|
+
export * from './util'
|
|
5
|
+
// 事件处理类
|
|
6
|
+
export {default as Event} from './event'
|
|
7
|
+
// dsm瓦片渲染类
|
|
8
|
+
export {default as GLOperations} from './gl-operations'
|
|
9
|
+
// 常量
|
|
10
|
+
export * from './constants'
|