@pirireis/webglobeplugins 0.13.0-alpha → 0.14.0-alpha

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 (54) hide show
  1. package/Math/arc-cdf-points.js +20 -0
  2. package/Math/arc-generate-points copy.js +1 -0
  3. package/Math/arc.js +21 -8
  4. package/Math/circle.js +35 -16
  5. package/Math/templete-shapes/grid-visually-equal.js +66 -0
  6. package/altitude-locator/plugin.js +3 -2
  7. package/bearing-line/plugin.js +1 -2
  8. package/circle-line-chain/plugin.js +4 -7
  9. package/compass-rose/compass-rose-padding-flat.js +12 -0
  10. package/package.json +1 -1
  11. package/programs/line-on-globe/degree-padding-around-circle-3d.js +1 -1
  12. package/programs/line-on-globe/linestrip/linestrip.js +5 -3
  13. package/programs/line-on-globe/naive-accurate-flexible.js +23 -16
  14. package/programs/picking/pickable-renderer.js +1 -2
  15. package/programs/rings/partial-ring/piece-of-pie copy.js +286 -0
  16. package/programs/rings/partial-ring/piece-of-pie.js +26 -13
  17. package/programs/totems/camerauniformblock.js +1 -1
  18. package/programs/totems/index.js +1 -1
  19. package/range-tools-on-terrain/bearing-line/adapters.js +111 -0
  20. package/range-tools-on-terrain/bearing-line/plugin.js +360 -0
  21. package/range-tools-on-terrain/circle-line-chain/adapters.js +83 -0
  22. package/range-tools-on-terrain/circle-line-chain/chain-list-map.js +351 -0
  23. package/range-tools-on-terrain/circle-line-chain/plugin.js +389 -0
  24. package/range-tools-on-terrain/circle-line-chain/types.js +1 -0
  25. package/range-tools-on-terrain/range-ring/adapters.js +25 -0
  26. package/range-tools-on-terrain/range-ring/plugin.js +31 -0
  27. package/range-tools-on-terrain/range-ring/types.js +1 -0
  28. package/rangerings/plugin.js +7 -11
  29. package/semiplugins/lightweight/line-plugin.js +195 -0
  30. package/semiplugins/lightweight/piece-of-pie-plugin.js +175 -0
  31. package/semiplugins/shape-on-terrain/arc-plugin.js +368 -0
  32. package/{shape-on-terrain/circle/plugin.js → semiplugins/shape-on-terrain/circle-plugin.js} +67 -38
  33. package/semiplugins/shape-on-terrain/derived/padding-plugin.js +96 -0
  34. package/semiplugins/type.js +1 -0
  35. package/types.js +0 -11
  36. package/util/account/create-buffermap-orchastration.js +39 -0
  37. package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +14 -3
  38. package/util/check/typecheck.js +15 -1
  39. package/util/geometry/index.js +3 -2
  40. package/util/gl-util/buffer/attribute-loader.js +2 -5
  41. package/util/gl-util/draw-options/methods.js +4 -5
  42. package/util/webglobjectbuilders.js +4 -9
  43. package/write-text/context-text3.js +17 -0
  44. package/write-text/context-text3old.js +152 -0
  45. package/programs/line-on-globe/circle-accurate.js +0 -176
  46. package/programs/line-on-globe/circle.js +0 -166
  47. package/programs/line-on-globe/to-the-surface.js +0 -111
  48. package/programs/totems/canvas-webglobe-info1.js +0 -106
  49. package/shape-on-terrain/arc/naive/plugin.js +0 -250
  50. package/util/check/get.js +0 -14
  51. package/util/gl-util/buffer/types.js +0 -1
  52. package/util/gl-util/draw-options/types.js +0 -15
  53. package/util/webglobjectbuilders1.js +0 -219
  54. /package/{shape-on-terrain/type.js → range-tools-on-terrain/bearing-line/types.js} +0 -0
@@ -0,0 +1,368 @@
1
+ // import { ArcOnTerrainPluginOptions } from "./type";
2
+ import { LineStripProgramCache } from "../../programs/line-on-globe/linestrip/linestrip";
3
+ import { createBufferAndReadInfo } from "../../util/gl-util/buffer/attribute-loader";
4
+ // import { populateFloat32Array } from "../../util/jshelpers/data-filler";
5
+ import { BufferManager, BufferOrchestrator } from "../../util/account/single-attribute-buffer-management/index";
6
+ import { globe3Dcoordinates, globe2Dcoordinates, RADIANS } from "../../Math/methods";
7
+ import { generateArcPoints, evenlySpacedArcPoints } from "../../Math/arc-cdf-points";
8
+ import { StaticDynamicState, StaticDynamicStrategy } from "../../util/build-strategy/static-dynamic";
9
+ import { opacityCheck } from "../../util/check/typecheck";
10
+ import * as vec3 from "../../Math/vec3";
11
+ import * as arc from "../../Math/arc";
12
+ import { CameraUniformBlockTotemCache } from "../../programs/totems/camerauniformblock";
13
+ import { WORLD_RADIUS_3D } from "../../Math/constants";
14
+ const DYNAMIC_STRATEGY_START_LOD = 12;
15
+ const INITAL_CAPACITY = 10;
16
+ const _attractionPoint = [0, 0, 0];
17
+ const _start = [0, 0, 0];
18
+ const _end = [0, 0, 0];
19
+ const _0arc = arc.create([1, 0, 0], [0, 1, 0]); // zero arc for intersection tests
20
+ export class ArcOnTerrainPlugin {
21
+ id;
22
+ program = null;
23
+ bufferManagerMap = null;
24
+ _bufferOrchestrator = new BufferOrchestrator({ capacity: INITAL_CAPACITY });
25
+ _opacity = 1;
26
+ _arcUBOHandler = null;
27
+ _vao = null;
28
+ globe = null;
29
+ gl = null;
30
+ _arcMap;
31
+ _cameraUniformBlock = null;
32
+ _staticDynamicStrategy = null;
33
+ _options;
34
+ _coordinaateBufferKeysForUpdate = [];
35
+ _freed = false;
36
+ constructor(id, { globeViewOn = true, // If true, arcs are drawn in 3D globe view
37
+ flatViewOn = true, // If true, arcs are drawn in 2D flat view
38
+ variativeColorsOn = false, defaultColor = [0.1, 0.1, 1, 1], // Default color in RGBA format
39
+ defaultHeightFromGroundIn3D = 30.0, // Default height from ground in
40
+ vertexCount = 70, // Number of vertices per arc
41
+ cameraAttractionIsOn = true // If true, camera attraction is enabled else evenly distributed arc points are used
42
+ } = {}) {
43
+ this.id = id;
44
+ this._arcMap = new Map();
45
+ this._options = {
46
+ globeViewOn: globeViewOn ? true : false,
47
+ flatViewOn: flatViewOn ? true : false,
48
+ variativeColorsOn: variativeColorsOn ? true : false,
49
+ defaultColor: defaultColor ? defaultColor : [0.1, 0.1, 1, 1],
50
+ defaultHeightFromGroundIn3D: defaultHeightFromGroundIn3D ? defaultHeightFromGroundIn3D : 30.0,
51
+ vertexCount: vertexCount ? vertexCount : 70,
52
+ cameraAttractionIsOn: cameraAttractionIsOn ? cameraAttractionIsOn : true
53
+ };
54
+ }
55
+ insertBulk(arcs) {
56
+ const keys = [];
57
+ for (let arcInput of arcs) {
58
+ const { key, start, end } = arcInput;
59
+ if (this._arcMap.has(key)) {
60
+ this._arcMap.delete(key);
61
+ }
62
+ vec3.fromLongLatToUnitVector(_start, [start[0] * RADIANS, start[1] * RADIANS]);
63
+ vec3.fromLongLatToUnitVector(_end, [end[0] * RADIANS, end[1] * RADIANS]);
64
+ const _arc = arc.create(_start, _end);
65
+ this._arcMap.set(key, [_arc, arcInput]); // height is null for now
66
+ keys.push(key);
67
+ }
68
+ this.__buildStaticArcs(keys, true);
69
+ this.globe.DrawRender();
70
+ }
71
+ deleteBulk(keys) {
72
+ if (!this._bufferOrchestrator || !this.bufferManagerMap || !this.globe) {
73
+ console.warn("Buffer orchestrator or buffer manager map is not initialized.");
74
+ return;
75
+ }
76
+ for (const key of keys) {
77
+ if (this._arcMap.has(key)) {
78
+ this._arcMap.delete(key);
79
+ }
80
+ else {
81
+ console.warn(`Arc with key ${key} not found in arcMap.`);
82
+ }
83
+ }
84
+ this._bufferOrchestrator.deleteBulk(keys, this.bufferManagerMap);
85
+ this.globe.DrawRender();
86
+ }
87
+ updateColor(key, color) {
88
+ if (this._options.variativeColorsOn === false) {
89
+ console.warn("Variative colors are not enabled in this plugin. Create another instance with variativeColorsOn: true to use this feature.");
90
+ return;
91
+ }
92
+ const { _bufferOrchestrator, bufferManagerMap } = this;
93
+ if (!_bufferOrchestrator || !bufferManagerMap) {
94
+ console.warn("Buffer orchestrator or buffer manager map is not initialized.");
95
+ return;
96
+ }
97
+ const arcInput = this._arcMap.get(key);
98
+ if (!arcInput) {
99
+ console.warn(`Arc with key ${key} not found in arcMap.`);
100
+ return;
101
+ }
102
+ arcInput[1].color = color; // Update the color in the arc map
103
+ _bufferOrchestrator.updateBulk([{ key: key, color: color }], bufferManagerMap, ["color"]);
104
+ this.globe.DrawRender();
105
+ }
106
+ setPluginOpacity(opacity) {
107
+ if (!this.globe || !this.gl) {
108
+ console.warn("Globe or WebGL context is not initialized.");
109
+ return;
110
+ }
111
+ opacityCheck(opacity);
112
+ this._opacity = opacity;
113
+ this.globe.DrawRender();
114
+ }
115
+ setCameraAttraction(isOn) {
116
+ if (!this.globe || !this.gl) {
117
+ console.warn("Globe or WebGL context is not initialized.");
118
+ return;
119
+ }
120
+ this._options.cameraAttractionIsOn = isOn;
121
+ this.globe.DrawRender();
122
+ }
123
+ init(globe, gl) {
124
+ this.globe = globe;
125
+ this.gl = gl;
126
+ this.program = LineStripProgramCache.get(globe);
127
+ this._staticDynamicStrategy = new StaticDynamicStrategy(globe, DYNAMIC_STRATEGY_START_LOD); // Initialize static-dynamic strategy with a transition level of 8
128
+ this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
129
+ this._fillBufferManagerMap();
130
+ this._bufferOrchestrator = new BufferOrchestrator();
131
+ this._arcUBOHandler = this.program.createUBO();
132
+ this._arcUBOHandler.update(new Map([
133
+ ["u_color", new Float32Array(this._options.defaultColor)],
134
+ ]));
135
+ }
136
+ draw3D() {
137
+ // Drawing logic here
138
+ if (!this.globe || !this.gl) {
139
+ console.warn("Globe or WebGL context is not initialized.");
140
+ return;
141
+ }
142
+ this._staticDynamicStrategy?.updateState();
143
+ this._buildArcs(); // can be async
144
+ const { gl, program, _bufferOrchestrator, _vao, _arcUBOHandler, } = this;
145
+ if (!gl || !program || !_bufferOrchestrator || !_vao || !_arcUBOHandler) {
146
+ console.warn("WebGL context, program, or buffer orchestrator is not initialized.");
147
+ return;
148
+ }
149
+ gl.disable(gl.DEPTH_TEST);
150
+ const drawOptions = {
151
+ drawRange: {
152
+ first: 0,
153
+ count: _bufferOrchestrator.length * (this._options.vertexCount + 1)
154
+ },
155
+ indexes: null
156
+ };
157
+ program.draw(_vao, drawOptions, this._opacity, _arcUBOHandler);
158
+ gl.enable(gl.DEPTH_TEST);
159
+ }
160
+ _buildArcs() {
161
+ const state = this._staticDynamicStrategy?.getState();
162
+ if (state === StaticDynamicState.TO_STATIC) {
163
+ this.__buildStaticArcs();
164
+ }
165
+ else if (state === StaticDynamicState.DYNAMIC) {
166
+ this.__buildArcs();
167
+ }
168
+ }
169
+ __buildStaticArcs(keys = [], calledFromInsert = false) {
170
+ const { globe, _arcMap, _cameraUniformBlock, bufferManagerMap, _bufferOrchestrator } = this;
171
+ if (!globe || !_cameraUniformBlock || !bufferManagerMap || !_bufferOrchestrator) {
172
+ console.warn("Globe or camera uniform block is not initialized.");
173
+ return;
174
+ }
175
+ const longLat = [0, 0];
176
+ const _attractionStrength = 0;
177
+ const longLatArr = new Float32Array(2 * this._options.vertexCount);
178
+ const data = [{
179
+ key: "staticArcs",
180
+ longLatArr: longLatArr,
181
+ height: null,
182
+ color: this._options.defaultColor
183
+ }];
184
+ if (keys.length == 0) {
185
+ for (const [key, [arcInstance, arcInput]] of _arcMap) {
186
+ arc.copy(_0arc, arcInstance);
187
+ const generatedPoints = evenlySpacedArcPoints(_0arc.p0, _0arc.normal, _0arc.coverAngle, this._options.vertexCount);
188
+ for (let i = 0; i < generatedPoints.length; i++) {
189
+ const point = generatedPoints[i];
190
+ vec3.fromUnitVectorToLongLat(longLat, point);
191
+ longLatArr.set([longLat[0] / RADIANS, longLat[1] / RADIANS], i * 2);
192
+ }
193
+ data[0].key = key;
194
+ data[0].height = arcInput.height ?? this._options.defaultHeightFromGroundIn3D;
195
+ data[0].color = arcInput.color ?? this._options.defaultColor;
196
+ if (calledFromInsert) {
197
+ this._bufferOrchestrator.insertBulk(data, bufferManagerMap);
198
+ }
199
+ else {
200
+ this._bufferOrchestrator.updateBulk(data, bufferManagerMap, this._coordinaateBufferKeysForUpdate);
201
+ }
202
+ }
203
+ }
204
+ else {
205
+ for (let key of keys) {
206
+ if (!_arcMap.has(key)) {
207
+ console.warn(`Arc with key ${key} not found in arcMap.`);
208
+ continue;
209
+ }
210
+ const [arcInstance, arcInput] = _arcMap.get(key);
211
+ arc.copy(_0arc, arcInstance);
212
+ const generatedPoints = evenlySpacedArcPoints(_0arc.p0, _0arc.normal, _0arc.coverAngle, this._options.vertexCount);
213
+ for (let i = 0; i < generatedPoints.length; i++) {
214
+ const point = generatedPoints[i];
215
+ vec3.fromUnitVectorToLongLat(longLat, point);
216
+ longLatArr.set([longLat[0] / RADIANS, longLat[1] / RADIANS], i * 2);
217
+ }
218
+ data[0].key = key;
219
+ data[0].height = arcInput.height ?? this._options.defaultHeightFromGroundIn3D;
220
+ data[0].color = arcInput.color ?? this._options.defaultColor;
221
+ if (calledFromInsert) {
222
+ this._bufferOrchestrator.insertBulk(data, bufferManagerMap);
223
+ }
224
+ else {
225
+ this._bufferOrchestrator.updateBulk(data, bufferManagerMap, this._coordinaateBufferKeysForUpdate);
226
+ }
227
+ }
228
+ }
229
+ }
230
+ __buildArcs() {
231
+ const { globe, _arcMap, _cameraUniformBlock, bufferManagerMap } = this;
232
+ if (!globe || !_cameraUniformBlock || !bufferManagerMap) {
233
+ console.warn("Globe or camera uniform block is not initialized.");
234
+ return;
235
+ }
236
+ const { cameraAttractionIsOn } = this._options;
237
+ const lookAtPosition = _cameraUniformBlock.getLookAtVector();
238
+ const cameraPosition = _cameraUniformBlock.getCameraVector();
239
+ vec3.divideScalar(cameraPosition, cameraPosition, WORLD_RADIUS_3D);
240
+ vec3.add(cameraPosition, cameraPosition, lookAtPosition);
241
+ // vec3.normalize(cameraPosition, cameraPosition);
242
+ vec3.divideScalar(cameraPosition, cameraPosition, 2);
243
+ // vec3.multiplyScalar(cameraPosition, cameraPosition, 1.3);
244
+ const _attractionStrength = (() => {
245
+ const lod = globe.api_GetCurrentLODWithDecimal();
246
+ if (lod < 11) {
247
+ return 1;
248
+ }
249
+ return lod * (lod - 8.5);
250
+ })();
251
+ const result = [];
252
+ const longLat = [0, 0];
253
+ for (const [key, [arcInstance, arcInput]] of _arcMap) {
254
+ arc.copy(_0arc, arcInstance);
255
+ const isOnArc = arc.closestPoint(_attractionPoint, _0arc, cameraPosition);
256
+ if (!isOnArc) {
257
+ if (vec3.distanceSquared(cameraPosition, _0arc.p0) < vec3.distanceSquared(cameraPosition, _0arc.p1)) {
258
+ vec3.copy(_attractionPoint, _0arc.p0);
259
+ }
260
+ else {
261
+ vec3.copy(_attractionPoint, _0arc.p1);
262
+ }
263
+ }
264
+ const generatedPoints = cameraAttractionIsOn ?
265
+ generateArcPoints(_0arc.p0, _0arc.p1, _0arc.normal, _attractionPoint, this._options.vertexCount, _attractionStrength)
266
+ : evenlySpacedArcPoints(_0arc.p0, _0arc.normal, _0arc.coverAngle, this._options.vertexCount);
267
+ const longLatArr = new Float32Array(2 * this._options.vertexCount);
268
+ for (let i = 0; i < generatedPoints.length; i++) {
269
+ const point = generatedPoints[i];
270
+ vec3.fromUnitVectorToLongLat(longLat, point);
271
+ longLatArr.set([longLat[0] / RADIANS, longLat[1] / RADIANS], i * 2);
272
+ }
273
+ result.push({
274
+ key: key,
275
+ longLatArr: longLatArr,
276
+ height: arcInput.height ?? this._options.defaultHeightFromGroundIn3D,
277
+ // color: arcInput.color // Use the color from the arc map
278
+ });
279
+ }
280
+ // this._bufferOrchestrator.resetWithCapacity(bufferManagerMap, result.length);
281
+ this._bufferOrchestrator.insertBulk(result, bufferManagerMap, ["position3d", "position2d"]);
282
+ }
283
+ _fillBufferManagerMap() {
284
+ const { gl, globe } = this;
285
+ if (!gl || !globe) {
286
+ console.warn("WebGL context or globe is not initialized.");
287
+ return;
288
+ }
289
+ const g2D = globe2Dcoordinates(globe);
290
+ const { flatViewOn, globeViewOn, variativeColorsOn } = this._options;
291
+ this.bufferManagerMap = new Map();
292
+ if (globeViewOn) {
293
+ this.bufferManagerMap.set("position3d", {
294
+ bufferManager: new BufferManager(gl, 3 * (this._options.vertexCount + 1), { bufferType: "STREAM_DRAW", initialCapacity: INITAL_CAPACITY }),
295
+ adaptor: (item) => {
296
+ const { longLatArr, height = this._options.defaultHeightFromGroundIn3D } = item;
297
+ const result = globe3Dcoordinates(globe, height)(longLatArr, { paddingCount: 1 });
298
+ return result;
299
+ }
300
+ });
301
+ }
302
+ if (flatViewOn) {
303
+ this.bufferManagerMap.set("position2d", {
304
+ bufferManager: new BufferManager(gl, 2 * (this._options.vertexCount + 1), { bufferType: "STREAM_DRAW", initialCapacity: INITAL_CAPACITY }),
305
+ adaptor: (item) => {
306
+ const { longLatArr } = item;
307
+ return g2D(longLatArr, { paddingCount: 1 });
308
+ }
309
+ });
310
+ }
311
+ if (this._options.variativeColorsOn) {
312
+ const _colorArray = new Float32Array(4 * (this._options.vertexCount + 1));
313
+ this.bufferManagerMap.set("color", {
314
+ bufferManager: new BufferManager(gl, 4 * (this._options.vertexCount + 1), { bufferType: "STREAM_DRAW", initialCapacity: INITAL_CAPACITY }),
315
+ adaptor: (item) => {
316
+ // Calculate color based on radius
317
+ if (item.color) {
318
+ for (let i = 0; i < this._options.vertexCount; i++) {
319
+ _colorArray.set(item.color, 4 * i); // Fill color for each vertex
320
+ }
321
+ return _colorArray;
322
+ }
323
+ else {
324
+ return _colorArray.fill(-1, 0, 4 * (this._options.vertexCount)); // Fill with -1 if no color is provided
325
+ }
326
+ }
327
+ });
328
+ }
329
+ const bufferObjects = [
330
+ globeViewOn ? "position3d" : null,
331
+ flatViewOn ? "position2d" : null,
332
+ variativeColorsOn ? "color" : null
333
+ ].map((key) => {
334
+ if (!key)
335
+ return null;
336
+ this._coordinaateBufferKeysForUpdate.push(key);
337
+ // @ts-ignore
338
+ const bufferManager = this.bufferManagerMap.get(key).bufferManager;
339
+ // @ts-ignore
340
+ return createBufferAndReadInfo(bufferManager.buffer);
341
+ });
342
+ // @ts-ignore
343
+ this._vao = this.program.createVAO(bufferObjects[0], // position3d
344
+ bufferObjects[1], // position2d
345
+ bufferObjects[2] // color
346
+ );
347
+ }
348
+ free() {
349
+ if (this._freed) {
350
+ console.warn("Plugin already freed");
351
+ return;
352
+ }
353
+ if (!this.gl || !this.program) {
354
+ console.warn("WebGL context or program is not initialized.");
355
+ return;
356
+ }
357
+ this._arcUBOHandler?.free();
358
+ this.bufferManagerMap?.forEach((manager) => {
359
+ manager.bufferManager.free();
360
+ });
361
+ CameraUniformBlockTotemCache.release(this.globe);
362
+ LineStripProgramCache.release(this.globe);
363
+ this.gl = null;
364
+ this.globe = null;
365
+ this._arcMap.clear();
366
+ this._coordinaateBufferKeysForUpdate = [];
367
+ }
368
+ }
@@ -1,13 +1,15 @@
1
1
  import { LineStripProgramCache } from "../../programs/line-on-globe/linestrip/linestrip";
2
2
  import { BufferManager, BufferOrchestrator } from "../../util/account/single-attribute-buffer-management/index";
3
3
  import { CameraUniformBlockTotemCache } from "../../programs/totems/camerauniformblock";
4
- import { createBufferAndReadInfo } from '../../util/gl-util/buffer/attribute-loader';
4
+ import { createBufferAndReadInfo } from "../../util/gl-util/buffer/attribute-loader";
5
5
  import * as CircleMethods from "../../Math/circle";
6
6
  import * as CircleCDF from "../../Math/circle-cdf-points";
7
7
  import * as vec3 from "../../Math/vec3";
8
8
  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
+ import { opacityCheck } from "../../util/check/typecheck";
12
+ const ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL = 8;
11
13
  const CIRCLE_POINTS_COUNT_HALF = 65; // Half of the points plus one for the reflection
12
14
  const CIRCLE_POINTS_COUNT = CIRCLE_POINTS_COUNT_HALF * 2 - 1; // Number of points to approximate the circle
13
15
  const DENSE_PART_SAMPLE_RATIO = 0.80; // Ratio of the dense part of the circle
@@ -50,7 +52,7 @@ const defineStregthLevel = (lod, radiusMeters) => {
50
52
  return Math.min(level, ATTRACTION_LEVELS - 1);
51
53
  };
52
54
  const AnglesStash = CircleCDF.createCummulativeTemplateStash(ATTRACTION_LEVELS, CIRCLE_POINTS_COUNT_HALF, DENSE_PART_SAMPLE_RATIO, STRENGTH_FACTOR);
53
- const _colorArray = new Float32Array(4); // Used to store the color for each circle
55
+ const _colorArray = new Float32Array(4 * CIRCLE_POINTS_COUNT); // Used to store the color for each circle
54
56
  export class CircleOnTerrainPlugin {
55
57
  id;
56
58
  globe = null;
@@ -68,21 +70,19 @@ export class CircleOnTerrainPlugin {
68
70
  _staticDynamicStrategy = null;
69
71
  _styleOptions = {
70
72
  variativeColorsOn: false,
71
- defaultColor: [0.1, 0.1, 1, 1], // Default color in RGBA format
73
+ defaultColor: [0.1, 0.1, 0.1, 1], // Default color in RGBA format
72
74
  defaultHeightFromGroundIn3D: 30.0
73
75
  };
74
- constructor(id, styleOptions = {
75
- variativeColorsOn: false, defaultColor: [0.1, 0.1, 1, 1]
76
- }) {
76
+ constructor(id, styleOptions = {}) {
77
77
  this.id = id;
78
- this._styleOptions = styleOptions;
78
+ this._styleOptions = { ...this._styleOptions, ...styleOptions };
79
79
  this._styleOptions.defaultColor = new Float32Array(this._styleOptions.defaultColor);
80
80
  }
81
81
  init(globe, gl) {
82
82
  this.globe = globe;
83
83
  this.gl = gl;
84
84
  // Initialize the program cache for line strip rendering.
85
- this._staticDynamicStrategy = new StaticDynamicStrategy(globe, 8);
85
+ this._staticDynamicStrategy = new StaticDynamicStrategy(globe, ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL);
86
86
  this.lineProgram = LineStripProgramCache.get(globe);
87
87
  // const g3D = globe3Dcoordinates(globe, 30);
88
88
  const g2D = globe2Dcoordinates(globe);
@@ -106,17 +106,19 @@ export class CircleOnTerrainPlugin {
106
106
  });
107
107
  if (this._styleOptions.variativeColorsOn) {
108
108
  this.bufferManagerMap.set("color", {
109
- bufferManager: new BufferManager(gl, 4, { initialCapacity }),
109
+ bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 4, { initialCapacity }),
110
110
  adaptor: (item) => {
111
- const { radius } = item;
112
- // Calculate color based on radius
113
111
  if (item.color) {
114
- _colorArray.set(item.color);
115
- return _colorArray;
112
+ for (let i = 0; i < CIRCLE_POINTS_COUNT; i++) {
113
+ _colorArray.set(item.color, i * 4);
114
+ }
116
115
  }
117
116
  else {
118
- return this._styleOptions.defaultColor;
117
+ for (let i = 0; i < CIRCLE_POINTS_COUNT; i++) {
118
+ _colorArray.set(this._styleOptions.defaultColor, i * 4);
119
+ }
119
120
  }
121
+ return _colorArray;
120
122
  }
121
123
  });
122
124
  }
@@ -125,36 +127,61 @@ export class CircleOnTerrainPlugin {
125
127
  this._circleUBOHandler = this.lineProgram.createUBO();
126
128
  this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
127
129
  }
128
- insertCircle(key, longitude, latitude, radius, height = null) {
129
- const circle = {
130
- center: [longitude, latitude],
131
- radius: radius
132
- };
133
- const circleForAzimuthCalc = CircleMethods.createCircleClosestAzimuthAngleProperties(circle);
134
- this.circleMap.set(key, [circle, circleForAzimuthCalc, height]);
135
- // @ts-ignore
136
- if (this._staticDynamicStrategy.getState() !== StaticDynamicState.DYNAMIC) {
137
- this.__buildStaticCircles([key]);
130
+ insertBulk(circles) {
131
+ if (this._isFree)
132
+ return;
133
+ if (!this.globe || !this.gl || !this.lineProgram || !this.bufferOrchestrator ||
134
+ !this.bufferManagerMap || !this._vao || !this._circleUBOHandler) {
135
+ throw new Error("Plugin not initialized properly");
136
+ }
137
+ //
138
+ const fillStaticKeys = [];
139
+ for (const circleInput of circles) {
140
+ if (!circleInput.key || !circleInput.center || !circleInput.radius) {
141
+ console.warn(`CircleOnTerrainPlugin: Circle input is missing required properties: ${circleInput.radius} or ${circleInput.center} or ${circleInput.key}`);
142
+ continue;
143
+ }
144
+ fillStaticKeys.push(circleInput.key);
145
+ const circleForAzimuthCalc = CircleMethods.createCircleClosestAzimuthAngleProperties(circleInput);
146
+ this.circleMap.set(circleInput.key, [circleInput, circleForAzimuthCalc]);
147
+ if (this._staticDynamicStrategy?.getState() !== StaticDynamicState.DYNAMIC) {
148
+ fillStaticKeys.push(circleInput.key);
149
+ }
138
150
  }
139
- this.globe?.DrawRender();
151
+ this.__buildStaticCircles(fillStaticKeys);
152
+ this.globe.DrawRender();
140
153
  }
141
- deleteCircle(keys) {
154
+ deleteBulk(keys) {
155
+ if (this._isFree)
156
+ return;
157
+ if (!this.globe || !this.gl || !this.lineProgram || !this.bufferOrchestrator ||
158
+ !this.bufferManagerMap || !this._vao || !this._circleUBOHandler) {
159
+ throw new Error("Plugin not initialized properly");
160
+ }
161
+ this.bufferOrchestrator.deleteBulk(keys, this.bufferManagerMap);
142
162
  for (const key of keys) {
143
163
  if (this.circleMap.has(key)) {
144
164
  this.circleMap.delete(key);
145
- this.globe?.DrawRender();
165
+ }
166
+ else {
167
+ console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap. Cannot delete.`);
146
168
  }
147
169
  }
148
- this._dobuild = true;
149
- this.globe?.DrawRender();
170
+ }
171
+ setPluginOpacity(opacity) {
172
+ if (!this.globe || !this.gl) {
173
+ console.warn("Globe or WebGL context is not initialized.");
174
+ return;
175
+ }
176
+ opacityCheck(opacity);
177
+ this._opacity = opacity;
178
+ this.globe.DrawRender();
150
179
  }
151
180
  // IMPLICIT METHODS
152
181
  _buildCircles() {
153
182
  // @ts-ignore
154
183
  this._staticDynamicStrategy?.updateState();
155
184
  const state = this._staticDynamicStrategy?.getState();
156
- if (state === StaticDynamicState.TO_STATIC)
157
- console.log("state", state);
158
185
  if (state === StaticDynamicState.TO_STATIC) {
159
186
  this.__buildStaticCircles();
160
187
  }
@@ -168,7 +195,7 @@ export class CircleOnTerrainPlugin {
168
195
  !bufferOrchestrator || !bufferManagerMap || !circleMap)
169
196
  throw new Error("Plugin not initialized properly");
170
197
  // unoptimized.. resets all circles.
171
- bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
198
+ // bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
172
199
  // Prepare the data for the buffers
173
200
  const data = [{
174
201
  key: "",
@@ -183,10 +210,9 @@ export class CircleOnTerrainPlugin {
183
210
  const currentLOD = globe.api_GetCurrentLODWithDecimal();
184
211
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
185
212
  for (const [key, circle] of this.circleMap.entries()) {
186
- const [{ radius, center }, circleForAzimuthCalc, height] = circle;
213
+ const [{ radius, center, height = null }, circleForAzimuthCalc] = circle;
187
214
  const closestAzimuthAngle = CircleMethods.closestAzimuthAngle(circleForAzimuthCalc, cameraPosition);
188
215
  const stregthLevel = defineStregthLevel(currentLOD, radius);
189
- // console.log('DrawStregthLevel', stregthLevel, currentLOD, radius);
190
216
  if (stregthLevel < 0) {
191
217
  console.warn(`CircleOnTerrainPlugin: Circle ${key} has too small radius for current LOD ${currentLOD}. Skipping., radius: ${radius}, stregthLevel: ${stregthLevel}`);
192
218
  continue;
@@ -197,7 +223,7 @@ export class CircleOnTerrainPlugin {
197
223
  data[0].longLatArr = circlePointsLongLat;
198
224
  data[0].height = height;
199
225
  // Add to buffer orchestrator
200
- this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
226
+ this.bufferOrchestrator.insertBulk(data, bufferManagerMap, ["position3d", "position2d"]);
201
227
  }
202
228
  }
203
229
  // this will be used to build static circles, which are not affected by camera position or LOD.
@@ -210,7 +236,8 @@ export class CircleOnTerrainPlugin {
210
236
  const data = [{
211
237
  key: "",
212
238
  longLatArr: [],
213
- height: null
239
+ height: null,
240
+ color: [1, 1, 1, 1]
214
241
  }];
215
242
  // ensure buffer orchestrotrator have enough capacity
216
243
  // all circles are build with even sampling, AttractionLevel = 0
@@ -220,11 +247,12 @@ export class CircleOnTerrainPlugin {
220
247
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
221
248
  bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
222
249
  for (const [key, circle] of this.circleMap.entries()) {
223
- const [{ radius, center }, _, height] = circle;
250
+ const [{ radius, center, height = null, color = null }, _] = circle;
224
251
  CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
225
252
  data[0].key = key;
226
253
  data[0].longLatArr = circlePointsLongLat;
227
254
  data[0].height = height;
255
+ data[0].color = color || this._styleOptions.defaultColor;
228
256
  this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
229
257
  }
230
258
  }
@@ -238,12 +266,13 @@ export class CircleOnTerrainPlugin {
238
266
  console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap.`);
239
267
  continue;
240
268
  }
241
- const [{ radius, center }, _, height] = this.circleMap.get(key);
269
+ const [{ radius, center, height = null, color = null }, _] = this.circleMap.get(key);
242
270
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
243
271
  CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
244
272
  data[0].key = key;
245
273
  data[0].longLatArr = circlePointsLongLat;
246
274
  data[0].height = height;
275
+ data[0].color = color || this._styleOptions.defaultColor;
247
276
  this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
248
277
  }
249
278
  }