@pirireis/webglobeplugins 0.15.21-alpha → 0.15.24

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 (33) hide show
  1. package/Math/arc.js +1 -2
  2. package/Math/circle-cdf-points.js +1 -170
  3. package/Math/circle.js +0 -25
  4. package/Math/vec3.js +1 -1
  5. package/altitude-locator/plugin.js +1 -1
  6. package/package.json +1 -1
  7. package/point-tracks/plugin.js +5 -6
  8. package/programs/line-on-globe/lines-color-instanced-flat.js +0 -1
  9. package/programs/point-on-globe/element-globe-surface-glow.js +0 -1
  10. package/programs/totems/camerauniformblock.js +7 -0
  11. package/programs/totems/canvas-webglobe-info.js +9 -9
  12. package/programs/totems/globe-changes.js +21 -14
  13. package/range-tools-on-terrain/bearing-line/plugin.js +2 -5
  14. package/range-tools-on-terrain/circle-line-chain/chain-list-map.js +4 -9
  15. package/range-tools-on-terrain/circle-line-chain/plugin.js +4 -2
  16. package/range-tools-on-terrain/range-ring/adapters.js +25 -9
  17. package/range-tools-on-terrain/range-ring/plugin.js +200 -5
  18. package/range-tools-on-terrain/range-ring/types.js +9 -1
  19. package/semiplugins/lightweight/line-plugin.js +33 -15
  20. package/semiplugins/shape-on-terrain/arc-plugin.js +162 -99
  21. package/semiplugins/shape-on-terrain/circle-plugin.js +170 -83
  22. package/semiplugins/shape-on-terrain/padding-1-degree.js +244 -63
  23. package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +1 -1
  24. package/util/build-strategy/static-dynamic.js +11 -1
  25. package/util/frame-counter-trigger.js +84 -0
  26. package/wind/imagetovectorfieldandmagnitude.js +23 -0
  27. package/wind/index.js +2 -2
  28. package/wind/plugin.js +30 -9
  29. package/write-text/context-text4.js +140 -0
  30. package/Math/arc-generate-points copy.js +0 -366
  31. package/Math/globe-util/horizon-plane.js +0 -112
  32. package/altitude-locator/draw-subset-obj.js +0 -16
  33. package/semiplugins/shape-on-terrain/derived/padding-plugin.js +0 -101
@@ -9,6 +9,7 @@ import { globe3Dcoordinates, globe2Dcoordinates } from "../../Math/methods";
9
9
  import { StaticDynamicStrategy, StaticDynamicState } from "../../util/build-strategy/static-dynamic";
10
10
  import { WORLD_RADIUS_3D, WORLD_RADIUS_MERCATOR } from "../../Math/constants";
11
11
  import { opacityCheck } from "../../util/check/typecheck";
12
+ import { FrameCounterTrigger } from "../../util/frame-counter-trigger";
12
13
  const ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL = 8;
13
14
  const CIRCLE_POINTS_COUNT_HALF = 65; // Half of the points plus one for the reflection
14
15
  const CIRCLE_POINTS_COUNT = CIRCLE_POINTS_COUNT_HALF * 2 - 1; // Number of points to approximate the circle
@@ -58,15 +59,16 @@ export class CircleOnTerrainPlugin {
58
59
  globe = null;
59
60
  gl = null;
60
61
  lineProgram = null;
61
- bufferManagerMap = new Map();
62
+ bufferManagersMap = new Map();
62
63
  bufferOrchestrator = new BufferOrchestrator();
63
64
  circleMap = new Map();
64
65
  _cameraUniformBlock = null;
65
- _isFree = false;
66
+ _freed = false;
66
67
  _circleUBOHandler = null;
67
68
  _opacity = 1;
68
69
  _vao = null;
69
70
  _dobuild = true; // This is used to trigger the build of circles when the camera position changes.
71
+ _frameCounterTrigger = null;
70
72
  _staticDynamicStrategy = null;
71
73
  _options = {
72
74
  variativeColorsOn: false,
@@ -74,6 +76,7 @@ export class CircleOnTerrainPlugin {
74
76
  defaultHeightFromGroundIn3D: 30.0,
75
77
  isMSL: false
76
78
  };
79
+ _textDataPreAdaptor = undefined;
77
80
  constructor(id, styleOptions = null) {
78
81
  this.id = id;
79
82
  if (styleOptions) {
@@ -84,13 +87,11 @@ export class CircleOnTerrainPlugin {
84
87
  this.globe = globe;
85
88
  this.gl = gl;
86
89
  // Initialize the program cache for line strip rendering.
87
- this._staticDynamicStrategy = new StaticDynamicStrategy(globe, ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL);
88
90
  this.lineProgram = LineStripProgramCache.get(globe);
89
- // const g3D = globe3Dcoordinates(globe, 30);
90
91
  const g2D = globe2Dcoordinates(globe);
91
92
  // Initialize with a reasonable initial capacity to prevent buffer size issues
92
93
  const initialCapacity = 100; // Start with capacity for 100 circles
93
- this.bufferManagerMap.set("position3d", {
94
+ this.bufferManagersMap.set("position3d", {
94
95
  bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 3, { initialCapacity }), // plus 1 is for butting linestrips
95
96
  adaptor: (item) => {
96
97
  const { longLatArr, height = this._options.defaultHeightFromGroundIn3D, msl = this._options.isMSL } = item;
@@ -98,7 +99,7 @@ export class CircleOnTerrainPlugin {
98
99
  return result;
99
100
  }
100
101
  });
101
- this.bufferManagerMap.set("position2d", {
102
+ this.bufferManagersMap.set("position2d", {
102
103
  bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 2, { initialCapacity }),
103
104
  adaptor: (item) => {
104
105
  const { longLatArr } = item;
@@ -107,7 +108,7 @@ export class CircleOnTerrainPlugin {
107
108
  }
108
109
  });
109
110
  if (this._options.variativeColorsOn) {
110
- this.bufferManagerMap.set("color", {
111
+ this.bufferManagersMap.set("color", {
111
112
  bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 4, { initialCapacity }),
112
113
  adaptor: (item) => {
113
114
  if (item.color) {
@@ -124,49 +125,102 @@ export class CircleOnTerrainPlugin {
124
125
  }
125
126
  });
126
127
  }
127
- this._vao = this.lineProgram.createVAO(createBufferAndReadInfo(this.bufferManagerMap.get("position3d")?.bufferManager.buffer), createBufferAndReadInfo(this.bufferManagerMap.get("position2d")?.bufferManager.buffer), this._options.variativeColorsOn ?
128
- createBufferAndReadInfo(this.bufferManagerMap.get("color")?.bufferManager.buffer) : null);
128
+ this._vao = this.lineProgram.createVAO(createBufferAndReadInfo(this.bufferManagersMap.get("position3d")?.bufferManager.buffer), createBufferAndReadInfo(this.bufferManagersMap.get("position2d")?.bufferManager.buffer), this._options.variativeColorsOn ?
129
+ createBufferAndReadInfo(this.bufferManagersMap.get("color")?.bufferManager.buffer) : null);
129
130
  this._circleUBOHandler = this.lineProgram.createUBO();
130
131
  this.setDefaultColor(this._options.defaultColor);
131
132
  this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
133
+ this._staticDynamicStrategy = new StaticDynamicStrategy(globe, ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL, () => {
134
+ this.__buildStaticCircles();
135
+ });
136
+ this._frameCounterTrigger = new FrameCounterTrigger(globe, 15, 1000, (globeChanges) => {
137
+ if (this._freed)
138
+ return;
139
+ this._buildCircles();
140
+ });
141
+ }
142
+ increaseSpace(amount) {
143
+ if (this._freed) {
144
+ console.warn("Plugin is freed, cannot increase space");
145
+ return;
146
+ }
147
+ if (this.globe === null) {
148
+ console.warn("Globe is not initialized.");
149
+ return;
150
+ }
151
+ if (typeof amount !== "number" || amount <= 0) {
152
+ console.warn("Invalid amount, must be a positive number");
153
+ return;
154
+ }
155
+ this.bufferOrchestrator.ensureSpace(amount, this.bufferManagersMap);
132
156
  }
133
157
  insertBulk(circles) {
134
- if (this._isFree)
158
+ if (this._freed)
135
159
  return;
136
160
  if (!this.globe || !this.gl || !this.lineProgram || !this.bufferOrchestrator ||
137
- !this.bufferManagerMap || !this._vao || !this._circleUBOHandler) {
161
+ !this.bufferManagersMap || !this._vao || !this._circleUBOHandler) {
138
162
  throw new Error("Plugin not initialized properly");
139
163
  }
140
- //
141
- const fillStaticKeys = [];
164
+ const keys = [];
165
+ let newItemCount = 0;
142
166
  for (const circleInput of circles) {
143
167
  if (!circleInput.key || !circleInput.center || !circleInput.radius) {
144
168
  console.warn(`CircleOnTerrainPlugin: Circle input is missing required properties: ${circleInput.radius} or ${circleInput.center} or ${circleInput.key}`);
145
169
  continue;
146
170
  }
147
171
  if (circleInput.radius <= 0) {
148
- console.warn(`CircleOnTerrainPlugin: Circle ${circleInput.key} has non-positive radius
149
- ${circleInput.radius}. Skipping.`);
172
+ console.warn(`CircleOnTerrainPlugin: Circle ${circleInput.key} has non-positive radius ${circleInput.radius}. Skipping.`);
150
173
  continue;
151
174
  }
152
- fillStaticKeys.push(circleInput.key);
175
+ keys.push(circleInput.key);
176
+ if (!this.circleMap.has(circleInput.key)) {
177
+ newItemCount++;
178
+ }
153
179
  const circleForAzimuthCalc = CircleMethods.createCircleClosestAzimuthAngleProperties(circleInput);
154
180
  this.circleMap.set(circleInput.key, [circleInput, circleForAzimuthCalc]);
155
- if (this._staticDynamicStrategy?.getState() !== StaticDynamicState.DYNAMIC) {
156
- fillStaticKeys.push(circleInput.key);
157
- }
158
181
  }
159
- this.__buildStaticCircles(fillStaticKeys);
182
+ this.bufferOrchestrator.ensureSpace(newItemCount, this.bufferManagersMap);
183
+ this._buildCircles(keys);
184
+ if (this._options.variativeColorsOn) {
185
+ this.__fillColor(keys);
186
+ }
160
187
  this.globe.DrawRender();
161
188
  }
189
+ updateColors(keyColorCouples, drawRender = true) {
190
+ if (this._freed) {
191
+ console.warn("Plugin is freed, cannot increase space");
192
+ return;
193
+ }
194
+ if (this.globe === null) {
195
+ console.warn("Globe is not initialized.");
196
+ return;
197
+ }
198
+ if (this._options.variativeColorsOn === false) {
199
+ console.warn("VariativeColors are not enabled");
200
+ return;
201
+ }
202
+ for (const { key, color } of keyColorCouples) {
203
+ const [circleInput] = this.circleMap.get(key) || [];
204
+ if (circleInput) {
205
+ circleInput.color = color;
206
+ this.__fillColor([key]);
207
+ }
208
+ else {
209
+ console.warn(`Circle key ${key} not found in circleMap.`);
210
+ }
211
+ }
212
+ if (drawRender) {
213
+ this.globe.DrawRender();
214
+ }
215
+ }
162
216
  deleteBulk(keys) {
163
- if (this._isFree)
217
+ if (this._freed)
164
218
  return;
165
219
  if (!this.globe || !this.gl || !this.lineProgram || !this.bufferOrchestrator ||
166
- !this.bufferManagerMap || !this._vao || !this._circleUBOHandler) {
220
+ !this.bufferManagersMap || !this._vao || !this._circleUBOHandler) {
167
221
  throw new Error("Plugin not initialized properly");
168
222
  }
169
- this.bufferOrchestrator.deleteBulk(keys, this.bufferManagerMap);
223
+ this.bufferOrchestrator.deleteBulk(keys, this.bufferManagersMap);
170
224
  for (const key of keys) {
171
225
  if (this.circleMap.has(key)) {
172
226
  this.circleMap.delete(key);
@@ -211,25 +265,63 @@ export class CircleOnTerrainPlugin {
211
265
  this.globe.DrawRender();
212
266
  }
213
267
  }
268
+ updateCoordinates(items) {
269
+ if (this._freed) {
270
+ console.warn("CircleOnTerrainPlugin is freed, cannot update coordinates");
271
+ return;
272
+ }
273
+ if (this.globe === null) {
274
+ console.warn("Globe is not initialized, cannot update coordinates");
275
+ return;
276
+ }
277
+ const updateKeys = [];
278
+ for (const item of items) {
279
+ const { key, center, radius } = item;
280
+ const [circleInput] = this.circleMap.get(key) || [];
281
+ if (circleInput) {
282
+ circleInput.center = center;
283
+ circleInput.radius = radius;
284
+ updateKeys.push(key);
285
+ }
286
+ else {
287
+ console.warn(`Circle key ${key} not found in circleMap.`);
288
+ continue;
289
+ }
290
+ }
291
+ this._buildCircles(updateKeys);
292
+ this.globe.DrawRender();
293
+ }
214
294
  // IMPLICIT METHODS
215
- _buildCircles() {
295
+ __fillColor(subSetIDs) {
296
+ if (!this._options.variativeColorsOn)
297
+ return;
298
+ const wrapper = [null];
299
+ for (const key of subSetIDs) {
300
+ const [circleInput, circleForAzimuthCalc] = this.circleMap.get(key) || [];
301
+ if (circleInput) {
302
+ wrapper[0] = circleInput;
303
+ this.bufferOrchestrator.insertBulk(wrapper, this.bufferManagersMap, ["color"]);
304
+ }
305
+ }
306
+ }
307
+ _buildCircles(subSetIDs = null) {
216
308
  // @ts-ignore
217
309
  this._staticDynamicStrategy?.updateState();
218
310
  const state = this._staticDynamicStrategy?.getState();
219
- if (state === StaticDynamicState.TO_STATIC) {
220
- this.__buildStaticCircles();
311
+ if (state === StaticDynamicState.DYNAMIC) {
312
+ this.__buildDynamicCircles(subSetIDs);
221
313
  }
222
- else if (state === StaticDynamicState.DYNAMIC) {
223
- this.__buildCircles();
314
+ else if (subSetIDs || state === StaticDynamicState.TO_STATIC) {
315
+ this.__buildStaticCircles(subSetIDs);
224
316
  }
225
317
  }
226
- __buildCircles() {
227
- const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagerMap, circleMap } = this;
318
+ __buildDynamicCircles(subSetIDs = null) {
319
+ const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagersMap, circleMap } = this;
228
320
  if (!globe || !gl || !_cameraUniformBlock || !lineProgram ||
229
- !bufferOrchestrator || !bufferManagerMap || !circleMap)
321
+ !bufferOrchestrator || !bufferManagersMap || !circleMap)
230
322
  throw new Error("Plugin not initialized properly");
231
323
  // unoptimized.. resets all circles.
232
- // bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
324
+ // bufferOrchestrator.resetWithCapacity(bufferManagersMap, circleMap.size);
233
325
  // Prepare the data for the buffers
234
326
  const data = [{
235
327
  key: "",
@@ -244,8 +336,16 @@ export class CircleOnTerrainPlugin {
244
336
  vec3.normalize(cameraPosition, cameraPosition);
245
337
  const currentLOD = globe.api_GetCurrentLODWithDecimal();
246
338
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
247
- for (const [key, circle] of this.circleMap.entries()) {
248
- const [{ radius, center, height = null, msl = null }, circleForAzimuthCalc] = circle;
339
+ let keys;
340
+ if (!subSetIDs || subSetIDs.length === 0) {
341
+ keys = Array.from(this.circleMap.keys());
342
+ // bufferOrchestrator.resetWithCapacity(bufferManagersMap, circleMap.size);
343
+ }
344
+ else {
345
+ keys = subSetIDs;
346
+ }
347
+ for (const key of keys) {
348
+ const [{ radius, center, height = null, msl = null }, circleForAzimuthCalc] = this.circleMap.get(key);
249
349
  const closestAzimuthAngle = CircleMethods.closestAzimuthAngle(circleForAzimuthCalc, cameraPosition);
250
350
  const stregthLevel = defineStregthLevel(currentLOD, radius);
251
351
  if (stregthLevel < 0) {
@@ -259,72 +359,59 @@ export class CircleOnTerrainPlugin {
259
359
  data[0].height = height;
260
360
  data[0].msl = msl;
261
361
  // Add to buffer orchestrator
262
- this.bufferOrchestrator.insertBulk(data, bufferManagerMap, ["position3d", "position2d"]);
362
+ this.bufferOrchestrator.insertBulk(data, bufferManagersMap, [
363
+ this.globe?.api_GetCurrentGeometry() === 0 ? "position3d" : "position2d",
364
+ ]);
263
365
  }
264
366
  }
265
367
  // this will be used to build static circles, which are not affected by camera position or LOD.
266
368
  // LOD < 8 or something
267
369
  __buildStaticCircles(subSetIDs = null) {
268
- const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagerMap, circleMap } = this;
370
+ const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagersMap, circleMap } = this;
269
371
  if (!globe || !gl || !_cameraUniformBlock || !lineProgram ||
270
- !bufferOrchestrator || !bufferManagerMap || !circleMap)
372
+ !bufferOrchestrator || !bufferManagersMap || !circleMap)
271
373
  throw new Error("Plugin not initialized properly");
272
- const data = [{
273
- key: "",
274
- longLatArr: [],
275
- height: null,
276
- color: [1, 1, 1, 1],
277
- msl: false
278
- }];
374
+ const datas = [];
279
375
  // ensure buffer orchestrotrator have enough capacity
280
376
  // all circles are build with even sampling, AttractionLevel = 0
281
377
  const templateAngles = AnglesStash[0];
282
378
  const zeroRotation = 0;
379
+ let keys;
283
380
  if (!subSetIDs || subSetIDs.length === 0) {
284
- const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
285
- bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
286
- for (const [key, circle] of this.circleMap.entries()) {
287
- const [{ radius, center, height = null, color = null, msl = undefined }, _] = circle;
288
- CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
289
- data[0].key = key;
290
- data[0].longLatArr = circlePointsLongLat;
291
- data[0].height = height;
292
- data[0].color = color || this._options.defaultColor;
293
- data[0].msl = msl;
294
- this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
295
- }
381
+ keys = Array.from(this.circleMap.keys());
382
+ // bufferOrchestrator.resetWithCapacity(bufferManagersMap, circleMap.size);
296
383
  }
297
384
  else {
298
- // This does check the size beforehand.
299
- // subset is probably is used to insert a single item or,
300
- // rebuild of existing items which passed from rbushTree or similar indexed search.
301
- // therefore, it is not necessary to check for new items and extend capacity
302
- for (let key of subSetIDs) {
303
- if (!this.circleMap.has(key)) {
304
- console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap.`);
305
- continue;
306
- }
307
- const [{ radius, center, height = null, color = null, msl = undefined }, _] = this.circleMap.get(key);
308
- const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
309
- CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
310
- data[0].key = key;
311
- data[0].longLatArr = circlePointsLongLat;
312
- data[0].height = height;
313
- data[0].color = color || this._options.defaultColor;
314
- data[0].msl = msl;
315
- this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
385
+ keys = subSetIDs;
386
+ }
387
+ for (let key of keys) {
388
+ if (!this.circleMap.has(key)) {
389
+ console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap.`);
390
+ continue;
316
391
  }
392
+ const [{ radius, center, height = null, color = null, msl = undefined }, _] = this.circleMap.get(key);
393
+ const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
394
+ CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
395
+ datas.push({
396
+ key,
397
+ longLatArr: circlePointsLongLat,
398
+ height,
399
+ color: color || this._options.defaultColor,
400
+ msl
401
+ });
317
402
  }
403
+ this.bufferOrchestrator.insertBulk(datas, bufferManagersMap, [this.globe?.api_GetCurrentGeometry() === 0 ? "position3d" : "position2d"]);
318
404
  }
319
405
  // GLOBE API INTERFACE
320
406
  draw3D() {
321
- const { _isFree, globe, gl, lineProgram, bufferOrchestrator, bufferManagerMap, _vao, _circleUBOHandler } = this;
322
- if (_isFree || !globe || !gl || !lineProgram || !bufferOrchestrator ||
323
- !bufferManagerMap || !_vao || !_circleUBOHandler) {
407
+ const { _freed, globe, gl, lineProgram, bufferOrchestrator, bufferManagersMap, _vao, _circleUBOHandler } = this;
408
+ if (_freed || !globe || !gl || !lineProgram || !bufferOrchestrator ||
409
+ !bufferManagersMap || !_vao || !_circleUBOHandler) {
324
410
  return;
325
411
  }
326
- if (globe.api_IsScreenMoving())
327
- this._buildCircles();
412
+ // if (globe.api_IsScreenMoving())
413
+ this._frameCounterTrigger?.trigger();
414
+ // this._buildCircles();
328
415
  const drawOptions = {
329
416
  drawRange: {
330
417
  first: 0,
@@ -336,18 +423,18 @@ export class CircleOnTerrainPlugin {
336
423
  gl.enable(gl.DEPTH_TEST);
337
424
  }
338
425
  free() {
339
- if (this._isFree)
426
+ if (this._freed)
340
427
  return;
341
- this._isFree = true;
428
+ this._freed = true;
342
429
  if (this.lineProgram) {
343
430
  LineStripProgramCache.release(this.lineProgram);
344
431
  this.lineProgram = null;
345
432
  }
346
433
  this.circleMap.clear();
347
- this.bufferManagerMap.forEach(({ bufferManager }) => {
434
+ this.bufferManagersMap.forEach(({ bufferManager }) => {
348
435
  bufferManager.free();
349
436
  });
350
- this.bufferManagerMap.clear();
437
+ this.bufferManagersMap.clear();
351
438
  CameraUniformBlockTotemCache.release(this.globe);
352
439
  }
353
440
  }