@pirireis/webglobeplugins 0.17.1 → 1.0.3
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/Math/haversine.js +22 -0
- package/Math/methods.js +15 -2
- package/Math/tessellation/methods.js +4 -1
- package/Math/tessellation/nearest-value-padding.js +112 -0
- package/Math/tessellation/spherical-triangle-area.js +99 -0
- package/Math/tessellation/tile-merger.js +346 -215
- package/Math/tessellation/triangle-tessellation.js +381 -9
- package/Math/vec3.js +4 -0
- package/Math/xyz-tile.js +18 -0
- package/altitude-locator/plugin.js +1 -2
- package/investigation-tools/draw/tiles/adapters.js +2 -2
- package/investigation-tools/draw/tiles/tiles.js +2 -2
- package/package.json +1 -1
- package/programs/helpers/fadeaway.js +6 -1
- package/programs/point-on-globe/square-pixel-point.js +1 -0
- package/programs/polygon-on-globe/texture-dem-triangles.js +94 -116
- package/programs/totems/camera-totem-attactment-interface.js +1 -0
- package/programs/totems/camerauniformblock.js +33 -22
- package/programs/totems/dem-textures-manager.js +265 -0
- package/programs/vectorfields/logics/drawrectangleparticles.js +51 -18
- package/programs/vectorfields/logics/{ubo-new.js → particle-ubo.js} +5 -14
- package/programs/vectorfields/logics/pixelbased.js +42 -36
- package/programs/vectorfields/pingpongbuffermanager.js +34 -8
- package/semiplugins/shape-on-terrain/terrain-polygon/adapters.js +55 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/cache.js +102 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/index-polygon-map.js +45 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/manager.js +4 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/master-worker.js +177 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/polygon-to-triangles.js +100 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/random.js +121 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/types.js +1 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/worker-contact.js +63 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/worker.js +125 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/terrain-polygon.js +219 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/types.js +8 -0
- package/semiplugins/shell/bbox-renderer/logic.js +18 -58
- package/semiplugins/shell/bbox-renderer/object.js +19 -9
- package/tracks/point-heat-map/point-to-heat-map-flow.js +1 -1
- package/tracks/point-tracks/plugin.js +13 -6
- package/tracks/timetracks/program-line-strip.js +1 -1
- package/util/account/single-attribute-buffer-management/buffer-manager.js +5 -3
- package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +2 -2
- package/util/gl-util/uniform-block/manager.js +20 -10
- package/util/helper-methods.js +8 -0
- package/util/picking/fence.js +4 -2
- package/util/picking/picker-displayer.js +51 -9
- package/util/programs/draw-texture-on-canvas.js +18 -15
- package/util/shaderfunctions/geometrytransformations.js +67 -1
- package/vectorfield/waveparticles/plugin.js +241 -116
- package/vectorfield/wind/adapters/image-to-fields.js +61 -0
- package/vectorfield/wind/adapters/types.js +1 -0
- package/vectorfield/wind/imagetovectorfieldandmagnitude.js +6 -9
- package/vectorfield/wind/plugin-persistant copy.js +364 -0
- package/vectorfield/wind/plugin-persistant.js +375 -0
- package/vectorfield/wind/plugin.js +1 -1
- package/Math/tessellation/earcut/adapters.js +0 -37
- package/Math/tessellation/hybrid-triangle-tessellation-meta.js +0 -123
- package/Math/tessellation/shred-input.js +0 -18
- package/Math/tessellation/tiler.js +0 -50
- package/Math/tessellation/triangle-tessellation-meta.js +0 -523
- package/programs/polygon-on-globe/texture-dem-triangle-test-plugin-triangle.js +0 -328
- package/programs/vectorfields/logics/drawrectangleparticles1.js +0 -112
- package/semiplugins/shape-on-terrain/terrain-cover/texture-dem-cover.js +0 -1
- package/util/gl-util/uniform-block/types.js +0 -1
- package/util/webglobe/index.js +0 -2
- /package/Math/tessellation/{zoom-catch.js → constants.js} +0 -0
- /package/util/{webglobe/gldefaultstates.js → globe-default-gl-states.js} +0 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author: Toprak Nihat Deniz Ozturk
|
|
3
|
+
*/
|
|
4
|
+
import { imageToFields } from "./adapters/image-to-fields";
|
|
5
|
+
import ParticlePlugin from "../waveparticles/plugin";
|
|
6
|
+
import { createImageFromBase64 } from "../../util/webglobjectbuilders";
|
|
7
|
+
import { TexturePointSampler } from "../../heatwave/texture-point-sampler";
|
|
8
|
+
import imageToMagnitude, { imageToRadianAngle } from "./imagetovectorfieldandmagnitude";
|
|
9
|
+
import { isBoolean } from "../../util/check/typecheck";
|
|
10
|
+
const windyLegendData = {
|
|
11
|
+
thresholds: [0, 3, 3, 5, 5, 7, 10, 10, 13, 15, 15, 17, 20, 20, 25, 25, 30],
|
|
12
|
+
values: [
|
|
13
|
+
"#6271B8",
|
|
14
|
+
"#6271B8",
|
|
15
|
+
"#6271B8",
|
|
16
|
+
"#6271B8",
|
|
17
|
+
"#3D6EA3",
|
|
18
|
+
"#4A94AA",
|
|
19
|
+
"#4A9294",
|
|
20
|
+
"#4D8E7C",
|
|
21
|
+
"#4CA44C",
|
|
22
|
+
"#67A436",
|
|
23
|
+
"#A28740",
|
|
24
|
+
"#A26D5C",
|
|
25
|
+
"#8D3F5C",
|
|
26
|
+
"#974B91",
|
|
27
|
+
"#5F64A0",
|
|
28
|
+
"#5B88A1",
|
|
29
|
+
"#5B88A1"
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
export default class WindPlugin {
|
|
33
|
+
id;
|
|
34
|
+
globe;
|
|
35
|
+
gl = null;
|
|
36
|
+
particlePlugin;
|
|
37
|
+
windMetadata;
|
|
38
|
+
_legendData;
|
|
39
|
+
options;
|
|
40
|
+
windData;
|
|
41
|
+
_height;
|
|
42
|
+
_speedFactor;
|
|
43
|
+
_dropRate;
|
|
44
|
+
texturePointSampler;
|
|
45
|
+
texturePointSamplerAngle;
|
|
46
|
+
/**
|
|
47
|
+
* @param id - Plugin identifier
|
|
48
|
+
* @param windDataMeta - Wind data metadata
|
|
49
|
+
* @param windDataMeta.width - image width
|
|
50
|
+
* @param windDataMeta.height - image height
|
|
51
|
+
* @param windDataMeta.bbox - bounding box [minLon, minLat, maxLon, maxLat]
|
|
52
|
+
* @param options - Plugin options
|
|
53
|
+
* @param options.fadeOpacity - how fast the particle trails fade on each frame | between 0 - 1 | default 0.746
|
|
54
|
+
* @param options.speedFactor - how fast the particles move | between 0 - 1 | default 0.6
|
|
55
|
+
* @param options.dropRate - how often the particles move to a random place | between 0 - 1 | default 0.007
|
|
56
|
+
* @param options.dropRateBump - drop rate increase relative to individual particle speed
|
|
57
|
+
* @param options.baseOpacity - opacity of drawn particle trails | between 0 - 1 | default 1.0
|
|
58
|
+
* @param options.wingSize - wing size of particle arrow | positive number | default 7.0
|
|
59
|
+
* @param options.tailSize - tail size of particle arrow | positive number | default 1.0
|
|
60
|
+
* @param options.minSpeed - minimum speed threshold | positive number | default 0.0
|
|
61
|
+
* @param options.maxSpeed - maximum speed threshold | positive number | default 1000.0
|
|
62
|
+
* @param options.height - height of the particles | number | default 0.0
|
|
63
|
+
* @param options.numParticles - number of particles | positive integer | default 40000
|
|
64
|
+
* @param options.legendData - legend data for color mapping
|
|
65
|
+
*/
|
|
66
|
+
constructor(id, windDataMeta, options = {}) {
|
|
67
|
+
this.id = id;
|
|
68
|
+
this.windMetadata = windDataMeta;
|
|
69
|
+
this._legendData = options.legendData || windyLegendData;
|
|
70
|
+
this.options = {
|
|
71
|
+
fadeOpacity: options.fadeOpacity ?? 0.746,
|
|
72
|
+
speedFactor: options.speedFactor ?? 0.6,
|
|
73
|
+
dropRate: options.dropRate ?? 0.007,
|
|
74
|
+
dropRateBump: options.dropRateBump ?? 0.001,
|
|
75
|
+
baseOpacity: options.baseOpacity ?? 1.0,
|
|
76
|
+
wingSize: options.wingSize ?? 7.0,
|
|
77
|
+
tailSize: options.tailSize ?? 1.0,
|
|
78
|
+
minSpeed: options.minSpeed ?? 0.0,
|
|
79
|
+
maxSpeed: options.maxSpeed ?? 1000.0,
|
|
80
|
+
height: options.height ?? 0.0,
|
|
81
|
+
numParticles: options.numParticles ?? 40000,
|
|
82
|
+
legendData: this._legendData
|
|
83
|
+
};
|
|
84
|
+
this.windData = null;
|
|
85
|
+
this._height = this.options.height;
|
|
86
|
+
this._speedFactor = this.options.speedFactor;
|
|
87
|
+
this._dropRate = this.options.dropRate;
|
|
88
|
+
}
|
|
89
|
+
// Globe plugin init method
|
|
90
|
+
init(globe, gl) {
|
|
91
|
+
this.globe = globe;
|
|
92
|
+
this.gl = gl;
|
|
93
|
+
// Initialize the particle plugin with appropriate options
|
|
94
|
+
const { bbox, width, height, flipY } = this.windMetadata;
|
|
95
|
+
this.particlePlugin = new ParticlePlugin(`${this.id}_particles`, {
|
|
96
|
+
dataWidth: width,
|
|
97
|
+
dataHeight: height,
|
|
98
|
+
fadeOpacity: this.options.fadeOpacity,
|
|
99
|
+
opacity: this.options.baseOpacity,
|
|
100
|
+
speed: this._speedFactor,
|
|
101
|
+
dropRate: this._dropRate,
|
|
102
|
+
height: this._height,
|
|
103
|
+
minLon: bbox[0],
|
|
104
|
+
minLat: bbox[1] < -85 ? -85 : bbox[1],
|
|
105
|
+
maxLon: bbox[2],
|
|
106
|
+
maxLat: bbox[3] > 85 ? 85 : bbox[3],
|
|
107
|
+
particleCount: this.options.numParticles,
|
|
108
|
+
flipY: flipY ?? true,
|
|
109
|
+
useColorTexture: false, // TODO: under test.. make it true later
|
|
110
|
+
useSpeedTexture: true,
|
|
111
|
+
minSpeedThreshold: this.options.minSpeed,
|
|
112
|
+
maxSpeedThreshold: this.options.maxSpeed,
|
|
113
|
+
tailSize: this.options.tailSize,
|
|
114
|
+
wingSize: this.options.wingSize
|
|
115
|
+
});
|
|
116
|
+
this.particlePlugin.init(globe, gl);
|
|
117
|
+
// apply initial speed thresholds from options
|
|
118
|
+
this.particlePlugin.setSpeedThresholds(this.options.minSpeed, this.options.maxSpeed);
|
|
119
|
+
}
|
|
120
|
+
draw3D() {
|
|
121
|
+
if (this.particlePlugin) {
|
|
122
|
+
this.particlePlugin.draw3D();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
free() {
|
|
126
|
+
if (this.particlePlugin) {
|
|
127
|
+
this.particlePlugin.free();
|
|
128
|
+
}
|
|
129
|
+
if (this.texturePointSampler) {
|
|
130
|
+
this.texturePointSampler = undefined;
|
|
131
|
+
}
|
|
132
|
+
if (this.texturePointSamplerAngle) {
|
|
133
|
+
this.texturePointSamplerAngle = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ===== Wind Data Management =====
|
|
137
|
+
/**
|
|
138
|
+
* Set wind data from base64 encoded image
|
|
139
|
+
* @param windData - Wind data object
|
|
140
|
+
* @param windData.image - base64 encoded image
|
|
141
|
+
* @param windData.width - image width
|
|
142
|
+
* @param windData.height - image height
|
|
143
|
+
* @param windData.uMin - minimum u value
|
|
144
|
+
* @param windData.vMin - minimum v value
|
|
145
|
+
* @param windData.uMax - maximum u value
|
|
146
|
+
* @param windData.vMax - maximum v value
|
|
147
|
+
* @param windData.bbox - bounding box [minLon, minLat, maxLon, maxLat]
|
|
148
|
+
*/
|
|
149
|
+
setWindDataWithImageBase64(windData) {
|
|
150
|
+
const image = createImageFromBase64(windData.image);
|
|
151
|
+
image.onload = () => {
|
|
152
|
+
const fullWindData = {
|
|
153
|
+
image: image,
|
|
154
|
+
uMin: windData.uMin,
|
|
155
|
+
vMin: windData.vMin,
|
|
156
|
+
uMax: windData.uMax,
|
|
157
|
+
vMax: windData.vMax
|
|
158
|
+
};
|
|
159
|
+
this.setWind(fullWindData);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Set wind data from HTMLImageElement
|
|
164
|
+
*/
|
|
165
|
+
setWind(windData) {
|
|
166
|
+
this.windData = windData;
|
|
167
|
+
if (!this.particlePlugin) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Convert wind image to vector field, speed field, and color field
|
|
171
|
+
const { vectorFieldData, speedFieldData, colorFieldData } = imageToFields(windData, this._legendData);
|
|
172
|
+
// Update the particle plugin with the new data
|
|
173
|
+
this.particlePlugin.setVectorFieldData(vectorFieldData, {
|
|
174
|
+
dataWidth: windData.image.width,
|
|
175
|
+
dataHeight: windData.image.height,
|
|
176
|
+
flipY: this.windMetadata.flipY
|
|
177
|
+
});
|
|
178
|
+
this.particlePlugin.setSpeedField(speedFieldData);
|
|
179
|
+
this.particlePlugin.setColorField(colorFieldData);
|
|
180
|
+
// Update texture point samplers if they exist
|
|
181
|
+
this._setCoorcinatesDataCalculatorData();
|
|
182
|
+
}
|
|
183
|
+
// ===== Legend and Color Management =====
|
|
184
|
+
/**
|
|
185
|
+
* Set legend data for color mapping
|
|
186
|
+
* @param legendData - Legend data object
|
|
187
|
+
* @param legendData.thresholds - list of speed thresholds
|
|
188
|
+
* @param legendData.values - list of colors in hex format like #ff0000
|
|
189
|
+
*/
|
|
190
|
+
setLegend(legendData) {
|
|
191
|
+
this._legendData = legendData;
|
|
192
|
+
// If wind data is already set, re-process to update colors
|
|
193
|
+
if (this.windData && this.particlePlugin) {
|
|
194
|
+
const { vectorFieldData, speedFieldData, colorFieldData } = imageToFields(this.windData, this._legendData);
|
|
195
|
+
this.particlePlugin.setColorField(colorFieldData);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
setFlipY(flipY) {
|
|
199
|
+
isBoolean(flipY);
|
|
200
|
+
this.windMetadata.flipY = flipY;
|
|
201
|
+
if (this.particlePlugin && this.windData) {
|
|
202
|
+
this.setWind(this.windData);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
setDrawTextureMaxPixelOnDimension(value) {
|
|
206
|
+
if (this.particlePlugin) {
|
|
207
|
+
this.particlePlugin.setDrawTextureMaxPixelOnDimension(value);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// ===== Property Setters =====
|
|
211
|
+
set height(value) {
|
|
212
|
+
this._height = value;
|
|
213
|
+
if (this.particlePlugin) {
|
|
214
|
+
this.particlePlugin.setHeight(value);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
get height() {
|
|
218
|
+
return this._height;
|
|
219
|
+
}
|
|
220
|
+
set minSpeed(value) {
|
|
221
|
+
this.options.minSpeed = value;
|
|
222
|
+
if (this.particlePlugin) {
|
|
223
|
+
this.particlePlugin.setMinSpeedThreshold(value);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
get minSpeed() {
|
|
227
|
+
return this.options.minSpeed;
|
|
228
|
+
}
|
|
229
|
+
set maxSpeed(value) {
|
|
230
|
+
this.options.maxSpeed = value;
|
|
231
|
+
if (this.particlePlugin) {
|
|
232
|
+
this.particlePlugin.setMaxSpeedThreshold(value);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
get maxSpeed() {
|
|
236
|
+
return this.options.maxSpeed;
|
|
237
|
+
}
|
|
238
|
+
set fadeOpacity(value) {
|
|
239
|
+
this.options.fadeOpacity = value;
|
|
240
|
+
if (this.particlePlugin) {
|
|
241
|
+
this.particlePlugin.setFadeOpacity(value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
get fadeOpacity() {
|
|
245
|
+
return this.options.fadeOpacity;
|
|
246
|
+
}
|
|
247
|
+
set speedFactor(value) {
|
|
248
|
+
this._speedFactor = value;
|
|
249
|
+
if (this.particlePlugin) {
|
|
250
|
+
this.particlePlugin.setParticleSpeed(value);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
get speedFactor() {
|
|
254
|
+
return this._speedFactor;
|
|
255
|
+
}
|
|
256
|
+
set dropRate(value) {
|
|
257
|
+
this._dropRate = value;
|
|
258
|
+
if (this.particlePlugin) {
|
|
259
|
+
this.particlePlugin.setDropRate(value);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
get dropRate() {
|
|
263
|
+
return this._dropRate;
|
|
264
|
+
}
|
|
265
|
+
set dropRateBump(value) {
|
|
266
|
+
this.options.dropRateBump = value;
|
|
267
|
+
// Note: ParticlePlugin doesn't have dropRateBump parameter
|
|
268
|
+
// This would need to be added to ParticlePlugin if needed
|
|
269
|
+
}
|
|
270
|
+
get dropRateBump() {
|
|
271
|
+
return this.options.dropRateBump;
|
|
272
|
+
}
|
|
273
|
+
set baseOpacity(value) {
|
|
274
|
+
this.options.baseOpacity = value;
|
|
275
|
+
if (this.particlePlugin) {
|
|
276
|
+
this.particlePlugin.setOpacity(value);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
get baseOpacity() {
|
|
280
|
+
return this.options.baseOpacity;
|
|
281
|
+
}
|
|
282
|
+
set numParticles(value) {
|
|
283
|
+
this.options.numParticles = value;
|
|
284
|
+
if (this.particlePlugin) {
|
|
285
|
+
this.particlePlugin.setParticleCount(value);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
get numParticles() {
|
|
289
|
+
return this.options.numParticles;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Set wing and tail size for particle arrows
|
|
293
|
+
*/
|
|
294
|
+
setParticleDimensions(tail, wing) {
|
|
295
|
+
this.options.tailSize = tail;
|
|
296
|
+
this.options.wingSize = wing;
|
|
297
|
+
if (this.particlePlugin) {
|
|
298
|
+
this.particlePlugin.setParticleDimensions(tail, wing);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Set particle color (used when not using color field)
|
|
303
|
+
*/
|
|
304
|
+
setParticleColor(color) {
|
|
305
|
+
if (this.particlePlugin) {
|
|
306
|
+
this.particlePlugin.setParticleColor(color);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Set bounding box
|
|
311
|
+
*/
|
|
312
|
+
setBBox(bbox) {
|
|
313
|
+
// rescale
|
|
314
|
+
if (this.particlePlugin) {
|
|
315
|
+
this.particlePlugin.setBBox({
|
|
316
|
+
minLon: bbox.minLon,
|
|
317
|
+
minLat: bbox.minLat < -85 ? -85 : bbox.minLat,
|
|
318
|
+
maxLon: bbox.maxLon,
|
|
319
|
+
maxLat: bbox.maxLat > 85 ? 85 : bbox.maxLat
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
// Update metadata
|
|
323
|
+
this.windMetadata.bbox = [bbox.minLon, bbox.minLat, bbox.maxLon, bbox.maxLat];
|
|
324
|
+
}
|
|
325
|
+
// ===== Texture Point Sampler (for backward compatibility) =====
|
|
326
|
+
/**
|
|
327
|
+
* Get texture point sampler for magnitude or angle
|
|
328
|
+
* @param type - 'magnitude' or 'angle'
|
|
329
|
+
*/
|
|
330
|
+
getTexturePointSampler(type = 'magnitude') {
|
|
331
|
+
if (type === 'magnitude') {
|
|
332
|
+
if (!this.texturePointSampler) {
|
|
333
|
+
this._createTexturePointSampler();
|
|
334
|
+
this._setCoorcinatesDataCalculatorData();
|
|
335
|
+
}
|
|
336
|
+
return this.texturePointSampler;
|
|
337
|
+
}
|
|
338
|
+
else if (type === 'angle') {
|
|
339
|
+
if (!this.texturePointSamplerAngle) {
|
|
340
|
+
this._createTexturePointSamplerAngle();
|
|
341
|
+
this._setCoorcinatesDataCalculatorData();
|
|
342
|
+
}
|
|
343
|
+
return this.texturePointSamplerAngle;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
throw new Error(`WindPlugin.getTexturePointSampler: type must be either 'magnitude' or 'angle'.`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
_createTexturePointSamplerAngle() {
|
|
350
|
+
const { bbox, width, height } = this.windMetadata;
|
|
351
|
+
this.texturePointSamplerAngle = new TexturePointSampler(bbox, width, height);
|
|
352
|
+
}
|
|
353
|
+
_createTexturePointSampler() {
|
|
354
|
+
const { bbox, width, height } = this.windMetadata;
|
|
355
|
+
this.texturePointSampler = new TexturePointSampler(bbox, width, height);
|
|
356
|
+
}
|
|
357
|
+
_setCoorcinatesDataCalculatorData() {
|
|
358
|
+
if (!this.windData) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const windDataWithDimensions = {
|
|
362
|
+
...this.windData,
|
|
363
|
+
width: this.windData.image.width,
|
|
364
|
+
height: this.windData.image.height
|
|
365
|
+
};
|
|
366
|
+
if (this.texturePointSamplerAngle) {
|
|
367
|
+
const angle = imageToRadianAngle(windDataWithDimensions);
|
|
368
|
+
this.texturePointSamplerAngle.updateTextureData(0, angle, angle);
|
|
369
|
+
}
|
|
370
|
+
if (this.texturePointSampler) {
|
|
371
|
+
const magnitude = imageToMagnitude(windDataWithDimensions);
|
|
372
|
+
this.texturePointSampler.updateTextureData(0, magnitude, magnitude);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Author: Toprak Nihat Deniz Ozturk
|
|
3
3
|
*/
|
|
4
4
|
import { createImageFromBase64, createProgramWrapper, createTexture, createBuffer, bindAttribute, bindFramebuffer, bindTexture, getColorRamp } from "../../util/webglobjectbuilders";
|
|
5
|
-
import { defaultblendfunction } from "../../util/
|
|
5
|
+
import { defaultblendfunction } from "../../util/globe-default-gl-states";
|
|
6
6
|
import imageToMagnitude, { imageToRadianAngle } from "./imagetovectorfieldandmagnitude";
|
|
7
7
|
import { TexturePointSampler } from "../../heatwave/texture-point-sampler";
|
|
8
8
|
/**
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
function geoJSONToEarcut(geojson) {
|
|
2
|
-
const vertices = [];
|
|
3
|
-
const holes = [];
|
|
4
|
-
const dimensions = 2; // Assuming 2D coordinates (longitude, latitude)
|
|
5
|
-
let holeIndex = 0;
|
|
6
|
-
if (geojson.type !== 'FeatureCollection') {
|
|
7
|
-
throw new Error('Invalid GeoJSON: Expected FeatureCollection');
|
|
8
|
-
}
|
|
9
|
-
const features = geojson.features;
|
|
10
|
-
function processPolygon(coordinates) {
|
|
11
|
-
for (let i = 0; i < coordinates.length; i++) {
|
|
12
|
-
if (i > 0) {
|
|
13
|
-
holeIndex += coordinates[i - 1].length;
|
|
14
|
-
holes.push(holeIndex);
|
|
15
|
-
}
|
|
16
|
-
for (const coord of coordinates[i]) {
|
|
17
|
-
vertices.push(coord[0], coord[1]);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
function processMultiPolygon(coordinates) {
|
|
22
|
-
for (const polygon of coordinates) {
|
|
23
|
-
processPolygon(polygon);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
for (const feature of features) {
|
|
27
|
-
const geometry = feature.geometry;
|
|
28
|
-
if (geometry.type === 'Polygon') {
|
|
29
|
-
processPolygon(geometry.coordinates);
|
|
30
|
-
}
|
|
31
|
-
else if (geometry.type === 'MultiPolygon') {
|
|
32
|
-
processMultiPolygon(geometry.coordinates);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return { vertices, holes, dimensions };
|
|
36
|
-
}
|
|
37
|
-
export { geoJSONToEarcut };
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Toprak Ozturk
|
|
3
|
-
*/
|
|
4
|
-
import { equals, fromLongLatToUnitVector, fromUnitVectorToLongLat } from "../vec3";
|
|
5
|
-
import { pointsOnArc } from "../juction/arc-plane";
|
|
6
|
-
import { junctionVerticalOrHorizontalLines } from "../finite-line-2d";
|
|
7
|
-
// TODO:get rid of embedded lists. always flat list
|
|
8
|
-
const TILE_DEM_VERTEX_COUNT = 5; // 5x5 grid for DEM
|
|
9
|
-
const TILE_DEM_STEPCOUNT = TILE_DEM_VERTEX_COUNT - 1; // 4 inner divisions in each dimension
|
|
10
|
-
var EdgeType;
|
|
11
|
-
(function (EdgeType) {
|
|
12
|
-
EdgeType[EdgeType["ARC"] = 0] = "ARC";
|
|
13
|
-
EdgeType[EdgeType["LINEAR"] = 1] = "LINEAR";
|
|
14
|
-
})(EdgeType || (EdgeType = {}));
|
|
15
|
-
const _tempVec2 = /*@__PURE__*/ [0, 0];
|
|
16
|
-
const _plane = /*@__PURE__*/ { normal: [0, 0, 0], distance: 0 };
|
|
17
|
-
const _resultPoints = /*@__PURE__*/ [[0, 0, 0], [0, 0, 0]];
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @param triangleMeta
|
|
21
|
-
* @param zoom
|
|
22
|
-
* @param angle
|
|
23
|
-
* @param dimension false for longitude (meridian) true for latitude (parallel)
|
|
24
|
-
*/
|
|
25
|
-
function getPoints(triangleMeta, angle, dimension) {
|
|
26
|
-
// console.log("getPoints called with angle:", angle * 180 / Math.PI, "dimension:", dimension ? 'latitude' : 'longitude');
|
|
27
|
-
// find which arcs are cut by plane
|
|
28
|
-
const radians = angle;
|
|
29
|
-
if (dimension) {
|
|
30
|
-
_plane.normal[0] = 0;
|
|
31
|
-
_plane.normal[1] = 0;
|
|
32
|
-
_plane.normal[2] = 1;
|
|
33
|
-
_plane.distance = Math.sin(radians);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
_plane.normal[0] = Math.sin(radians);
|
|
37
|
-
_plane.normal[1] = -Math.cos(radians);
|
|
38
|
-
_plane.normal[2] = 0;
|
|
39
|
-
_plane.distance = 0;
|
|
40
|
-
}
|
|
41
|
-
let result = [];
|
|
42
|
-
// Add debugging
|
|
43
|
-
let resultsFromDistinctEdges = 0;
|
|
44
|
-
for (let i = 0; i < 3; i++) {
|
|
45
|
-
const edgeType = triangleMeta.edgeTypes[i];
|
|
46
|
-
const edge = triangleMeta.edges[i];
|
|
47
|
-
const coordIndex = dimension ? 1 : 0;
|
|
48
|
-
const minCoord = edge.bbox.min[coordIndex];
|
|
49
|
-
const maxCoord = edge.bbox.max[coordIndex];
|
|
50
|
-
if (minCoord > angle || maxCoord < angle) {
|
|
51
|
-
continue; // edge is out of range
|
|
52
|
-
}
|
|
53
|
-
let count = 0;
|
|
54
|
-
if (edgeType === EdgeType.ARC) {
|
|
55
|
-
count = pointsOnArc(edge, _plane, _resultPoints);
|
|
56
|
-
if (count === 1) {
|
|
57
|
-
fromUnitVectorToLongLat(_tempVec2, _resultPoints[0]);
|
|
58
|
-
result.push([[..._resultPoints[0]], [..._tempVec2]]);
|
|
59
|
-
}
|
|
60
|
-
else if (count === 2) {
|
|
61
|
-
// throw new Error('Unexpected 2 cut points on arc, should be max 1'); // TODO DELETE this line later
|
|
62
|
-
fromUnitVectorToLongLat(_tempVec2, _resultPoints[0]);
|
|
63
|
-
result.push([[..._resultPoints[0]], [..._tempVec2]]);
|
|
64
|
-
fromUnitVectorToLongLat(_tempVec2, _resultPoints[1]);
|
|
65
|
-
result.push([[..._resultPoints[1]], [..._tempVec2]]); // TODO: this is a fix for a bug, need to investigate later
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
// linear line
|
|
70
|
-
count = junctionVerticalOrHorizontalLines(_tempVec2, edge.line, angle, dimension);
|
|
71
|
-
if (count === 1) {
|
|
72
|
-
fromLongLatToUnitVector(_resultPoints[0], _tempVec2);
|
|
73
|
-
result.push([[..._resultPoints[0]], [..._tempVec2]]);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
resultsFromDistinctEdges += 1;
|
|
77
|
-
}
|
|
78
|
-
if (resultsFromDistinctEdges === 3) {
|
|
79
|
-
result = filterDuplicate(result);
|
|
80
|
-
}
|
|
81
|
-
if (result.length !== 2 && result.length !== 4) {
|
|
82
|
-
// TODO: THERE is a case where 4 points are found.
|
|
83
|
-
// this happens when two arcs has limit and share space in Z dimension
|
|
84
|
-
console.log("ERROR");
|
|
85
|
-
const text = 'Angle:' + angle + ' dimension:' + (dimension ? 'latitude' : 'longitude') + "\n" +
|
|
86
|
-
'Result points count:' + result.length + "\n" +
|
|
87
|
-
"bbox:" + triangleMeta.bbox.min[0] * 180 / Math.PI + ", " + triangleMeta.bbox.min[1] * 180 / Math.PI + ", " + triangleMeta.bbox.max[0] * 180 / Math.PI + ", " + triangleMeta.bbox.max[1] * 180 / Math.PI + "\n";
|
|
88
|
-
for (let res of result) {
|
|
89
|
-
const ll = res[1];
|
|
90
|
-
console.log("Point: " + ll[0] * 180 / Math.PI + ", " + ll[1] * 180 / Math.PI + "\n");
|
|
91
|
-
}
|
|
92
|
-
throw new Error(`Unexpected cut count for tile cut, got: ${result.length}, angle: ${angle * 180 / Math.PI}, dimension: ${dimension ? 'latitude' : 'longitude'} \n` + text);
|
|
93
|
-
}
|
|
94
|
-
// TODO: i want to see it delete later
|
|
95
|
-
if (result.length === 4) {
|
|
96
|
-
console.warn("Warning: 4 cut points found on triangle for angle:", angle * 180 / Math.PI, "dimension:", dimension ? 'latitude' : 'longitude', "points:", result);
|
|
97
|
-
}
|
|
98
|
-
result.sort((a, b) => {
|
|
99
|
-
if (dimension) {
|
|
100
|
-
return a[1][0] - b[1][0]; // sort by y for longitude cuts
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
return a[1][1] - b[1][1]; // sort by x for latitude cuts
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
function filterDuplicate(points) {
|
|
109
|
-
const result = [points[0]];
|
|
110
|
-
let dublicate = false;
|
|
111
|
-
for (let i = 1; i < points.length; i++) {
|
|
112
|
-
for (let j = 0; j < result.length; j++) {
|
|
113
|
-
if (equals(points[i][0], result[j][0])) {
|
|
114
|
-
dublicate = true;
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (!dublicate) {
|
|
119
|
-
result.push(points[i]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import earcut from "earcut";
|
|
2
|
-
import { createTriangleTessellationMeta } from "./triangle-tessellation-meta";
|
|
3
|
-
function shredInput(vertices, holes, zoomLevel) {
|
|
4
|
-
const result = [];
|
|
5
|
-
const triangles = earcut(vertices, holes, 2);
|
|
6
|
-
for (let i = 0; i < triangles.length; i += 3) {
|
|
7
|
-
const idx1 = triangles[i] * 2;
|
|
8
|
-
const idx2 = triangles[i + 1] * 2;
|
|
9
|
-
const idx3 = triangles[i + 2] * 2;
|
|
10
|
-
const p1 = [vertices[idx1], vertices[idx1 + 1]];
|
|
11
|
-
const p2 = [vertices[idx2], vertices[idx2 + 1]];
|
|
12
|
-
const p3 = [vertices[idx3], vertices[idx3 + 1]];
|
|
13
|
-
const triangleMeta = createTriangleTessellationMeta(p1, p2, p3);
|
|
14
|
-
result.push(triangleMeta);
|
|
15
|
-
}
|
|
16
|
-
// cut triangles into smaller pieces based on zoom level...
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// /**
|
|
3
|
-
// * Find length in x and y for a tile in given zoom level (in wgs84)
|
|
4
|
-
// * Find tile cuts for given line represented by two points
|
|
5
|
-
// * Find inner position of point in tile
|
|
6
|
-
// *
|
|
7
|
-
// */
|
|
8
|
-
// import { LongLat } from "../../types";
|
|
9
|
-
// export function tileLength(zoom: number): LongLat {
|
|
10
|
-
// const tileSize = 256; // in pixels
|
|
11
|
-
// const worldSize = tileSize * Math.pow(2, zoom);
|
|
12
|
-
// const latLength = 180 / worldSize;
|
|
13
|
-
// const lonLength = 360 / worldSize;
|
|
14
|
-
// return [lonLength, latLength];
|
|
15
|
-
// }
|
|
16
|
-
// // export function tileCuts(p1: LongLat, p2: LongLat, zoom: number): LongLat[] {
|
|
17
|
-
// // const cuts: LongLat[] = [];
|
|
18
|
-
// // const tileSize = 256;
|
|
19
|
-
// // const worldSize = tileSize * Math.pow(2, zoom);
|
|
20
|
-
// // const latLength = 180 / worldSize;
|
|
21
|
-
// // const lonLength = 360 / worldSize;
|
|
22
|
-
// // const x1 = (p1[0] + 180) / lonLength;
|
|
23
|
-
// // const y1 = (90 - p1[1]) / latLength;
|
|
24
|
-
// // const x2 = (p2[0] + 180) / lonLength;
|
|
25
|
-
// // const y2 = (90 - p2[1]) / latLength;
|
|
26
|
-
// // const dx = x2 - x1;
|
|
27
|
-
// // const dy = y2 - y1;
|
|
28
|
-
// // const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
29
|
-
// // const xStep = dx / steps;
|
|
30
|
-
// // const yStep = dy / steps;
|
|
31
|
-
// // let x = x1;
|
|
32
|
-
// // let y = y1;
|
|
33
|
-
// // for (let i = 0; i <= steps; i++) {
|
|
34
|
-
// // const tileX = Math.floor(x);
|
|
35
|
-
// // const tileY = Math.floor(y);
|
|
36
|
-
// // const cutX = tileX * lonLength - 180;
|
|
37
|
-
// // const cutY = 90 - tileY * latLength;
|
|
38
|
-
// // const cut: LongLat = [cutX, cutY];
|
|
39
|
-
// // if (cuts.length === 0 || (cuts[cuts.length - 1][0] !== cut[0] || cuts[cuts.length - 1][1] !== cut[1])) {
|
|
40
|
-
// // cuts.push(cut);
|
|
41
|
-
// // }
|
|
42
|
-
// // x += xStep;
|
|
43
|
-
// // y += yStep;
|
|
44
|
-
// // }
|
|
45
|
-
// // return cuts;
|
|
46
|
-
// // }
|
|
47
|
-
// // function fillTriangle(p1: LongLat, p2: LongLat, p3: LongLat, zoom: number): {positions:LongLat[], indices:number[]} {
|
|
48
|
-
// // // this function fills the triangle triangle iteratively
|
|
49
|
-
// // //
|
|
50
|
-
// // }
|